v1.4.1: 관리자 미디어 업로드 한도·라이브 에디터 UX 개선
종류별 업로드 크기 한도와 413 안내를 추가하고, 임베드·미디어 라이브 프리뷰·제목 Enter 포커스·스크롤 동작을 보정한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,18 @@
|
||||
# 업데이트 요약
|
||||
|
||||
## v1.4.1
|
||||
|
||||
- 관리자에서 비디오 등 대용량 미디어 업로드 시 적용되던 10MB 공통 한도를 종류별로 분리했다(비디오 기본 200MB).
|
||||
- 새 임베드 저장 형식을 단독 URL 한 줄로 통일해 `:::embed`와 URL-only가 섞이는 문제를 줄였다.
|
||||
- 글쓰기 라이브 모드에서 임베드·업로드 미디어 카드를 바로 프리뷰로 표시하고 방향키 이동, 버튼/키보드 삭제를 할 수 있게 했다.
|
||||
- 글쓰기 라이브 모드에서 제목 입력 후 Enter가 원문 편집처럼 보이던 흐름을 수정했다.
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- 본문에서 비디오, 오디오, 파일 다운로드 카드를 렌더링할 수 있도록 확장했다.
|
||||
- X/Twitter 임베드 카드 폭을 조정하고 Mastodon 공개 게시물 임베드의 높이 자동 조절을 추가했다.
|
||||
- 관리자 글쓰기에서 비디오·오디오·파일 업로드를 바로 연결하고, 단독 URL 한 줄을 자동 임베드로 표시한다.
|
||||
|
||||
## v1.2.0
|
||||
|
||||
- 관리자 글 목록 정렬·개수·추천 필터·별 표시, 슬러그·예약 시각 UX를 정리했다.
|
||||
|
||||
@@ -344,7 +344,7 @@ docker compose --env-file .env.production restart sori-studio-db
|
||||
- `public/uploads/`는 Git에 포함하지 않는다.
|
||||
- NAS 운영에서는 `docker-compose.yml`의 `./public/uploads:/app/public/uploads` 볼륨으로 업로드 파일을 유지한다.
|
||||
- 운영 빌드에서는 `/uploads/**` 서버 라우트가 `.output/public`이 아니라 `/app/public/uploads` 볼륨의 실제 파일을 직접 제공한다.
|
||||
- `MAX_FILE_SIZE` 환경 변수로 관리자 이미지 업로드 최대 크기를 제한한다.
|
||||
- `MAX_FILE_SIZE`, `MAX_VIDEO_FILE_SIZE`, `MAX_AUDIO_FILE_SIZE`, `MAX_DOCUMENT_FILE_SIZE` 환경 변수로 관리자 미디어 업로드 최대 크기를 제한한다. 리버스 프록시(Nginx 등)를 쓰면 `client_max_body_size`가 앱 한도보다 작지 않은지 함께 확인한다.
|
||||
- 관리자 미디어 화면은 현재 업로드 파일 시스템을 기준으로 목록, 파일명 변경, 삭제를 처리한다.
|
||||
|
||||
## 사용자 액션 필요 항목
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# 의사결정 이력
|
||||
|
||||
## 2026-05-21 v1.4.1 — 라이브 모드 임베드 즉시 프리뷰 전환
|
||||
|
||||
단독 URL 붙여넣기가 임베드 작성의 기본 흐름이 되면서 라이브 모드의 별도 URL 입력 카드는 같은 값을 다시 입력하게 만드는 중복 UI가 됐다. 임베드 블록은 즉시 실제 프리뷰로 보여주고, iframe 때문에 일반 텍스트처럼 커서를 둘 수 없는 문제는 프리뷰 래퍼 자체를 포커스 가능한 블록으로 만들어 삭제·아래 줄 추가 키보드 조작을 받도록 했다. 같은 문제가 업로드 비디오·오디오·파일 카드에도 적용되므로 공통 프리뷰 카드 동작으로 확장한다. iframe·audio 컨트롤 등이 내부 포커스를 가져갈 수 있으므로 hover/focus 삭제 버튼을 둔다. 선택된 프리뷰 카드에서 방향키가 페이지 스크롤로 빠지지 않도록 `ArrowUp`·`ArrowDown`은 이전/다음 편집 줄 포커스 이동으로 처리한다. 임베드 전용 왼쪽 핸들은 전체 블록 공통 정책이 아니므로 제거한다.
|
||||
|
||||
## 2026-05-21 v1.4.1 — 라이브 모드 제목 Enter 처리 보정
|
||||
|
||||
제목 블록에서 Enter를 누를 때 일반 블록 아래 삽입 로직만 타면 현재 제목 편집 값이 먼저 저장되지 않거나 다음 포커스가 원문 줄처럼 보이는 상태로 이어질 수 있었다. 제목 Enter는 제목 마크다운 줄과 아래 빈 줄을 한 번에 반영해, 제목은 유지하고 다음 빈 문단으로 자연스럽게 이동하도록 분리했다.
|
||||
|
||||
## 2026-05-21 v1.4.1 — 임베드 저장 형식 단독 URL 통일
|
||||
|
||||
단독 URL 한 줄을 자동 임베드로 해석하게 되면서 같은 외부 링크가 `https://...`와 `:::embed` fenced block 두 형식으로 새로 저장될 수 있었다. 작성자가 원본 마크다운을 읽을 때 혼선이 생기지 않도록 새 임베드 삽입, 라이브 편집, 레거시 블록 변환의 저장 형식은 단독 URL 한 줄로 통일하고, 기존 `:::embed` 콘텐츠는 렌더링 호환만 유지한다.
|
||||
|
||||
## 2026-05-21 v1.4.1 — 미디어 업로드 크기 한도 분리
|
||||
|
||||
관리자 게시물 미디어 업로드 API가 `MAX_FILE_SIZE`(기본 10MB) 하나만 쓰고 있어 동영상 업로드가 413으로 실패했다. 아바타·로고 등 이미지 전용 한도는 유지하고, `POST /admin/api/uploads`만 비디오·오디오·문서별 환경 변수(`MAX_VIDEO_FILE_SIZE` 등)로 검사하도록 분리했다. 에디터 미디어 모달에는 최대 용량 안내와 413 토스트를 추가했다.
|
||||
|
||||
## 2026-05-20 v1.4.0
|
||||
|
||||
### 미디어 선택과 단독 URL을 작성 흐름에 연결
|
||||
|
||||
비디오·오디오·파일 블록을 템플릿만 삽입하면 작성자가 업로드 URL을 직접 복사해야 하므로 이미지/갤러리와 UX가 맞지 않는다. 기존 미디어 모달을 확장해 파일 종류별 선택·업로드 후 fenced block URL과 표시 메타를 자동으로 채우도록 했다. 외부 임베드는 작성자가 `:::embed`를 기억하지 않아도 되도록 단독 `http(s)` URL 한 줄을 같은 임베드 블록으로 해석한다.
|
||||
|
||||
### 외부 임베드를 플랫폼별 표시 정책으로 분리
|
||||
|
||||
YouTube는 본문 폭 16:9 영상이 자연스럽지만 X/Twitter 공식 iframe은 내부 카드 최대 폭이 고정되어 있어 전체 폭 iframe으로 두면 오른쪽 공백이 커지고 내용이 잘릴 수 있다. X/Twitter와 Mastodon은 소셜 카드로 보고 좁은 폭 중앙 정렬을 적용한다. Mastodon은 인스턴스별 공개 게시물 URL 뒤에 `/embed`를 붙이는 표준 경로를 우선 사용하고, 공식 embed 스크립트와 같은 `postMessage` 높이 요청으로 긴 글이 잘리지 않게 한다. 다만 인스턴스 정책에 따라 iframe 표시가 실패할 수 있으므로 링크 fallback 정책은 유지한다.
|
||||
|
||||
### 미디어 Prose 블록을 fenced block 렌더링으로 연결
|
||||
|
||||
비디오·오디오·파일은 기존 이미지/갤러리처럼 업로드 URL을 본문 마크다운에 저장하는 방식이 관리와 이식성이 가장 단순하다. 따라서 `:::video`, `:::audio`, `:::file` fenced block을 추가하고, 표시용 메타는 `url=`, `title=` 같은 키값으로 둔다. 공개 화면은 카드형 컴포넌트가 렌더링하고, 관리자 에디터는 슬래시 명령으로 기본 템플릿을 삽입해 이후 업로드/선택 UI 확장과 분리한다.
|
||||
|
||||
## 2026-05-20 v1.3.7
|
||||
|
||||
### NAS 마이그레이션 명령을 npm 없는 호스트 기준으로 보정
|
||||
|
||||
17
docs/map.md
17
docs/map.md
@@ -23,9 +23,12 @@
|
||||
|
||||
| 파일 | 용도 |
|
||||
|------|------|
|
||||
| lib/upload-size-limit.js | 관리자 미디어 업로드 종류별 최대 바이트 판별·용량 문구(서버·클라이언트 공용) |
|
||||
| lib/external-favicon-url.js | 외부 URL 호스트 기준 Google `s2/favicons` 썸네일 URL 생성(내부 경로는 빈 문자열) |
|
||||
| lib/navigation-editor-tree.js | 관리자 메뉴 UI·서버 `renumberSortOrderByTree`가 쓰는 `buildNavigationEditorTree`, 관리자 상단 네비 평면 표용 `flattenNavigationEditorWrappers` |
|
||||
| lib/markdown-content-normalizer.js | 관리자 Markdown-first 전환 후 레거시 블록 배열·객체 본문 값을 저장용 마크다운 문자열로 변환 |
|
||||
| lib/markdown-block-context.js | 관리자 Markdown textarea 커서 위치 기준 이미지·갤러리·임베드 블록 설정 패널 대상 판별 |
|
||||
| lib/markdown-slash-commands.js | 관리자 Markdown-first 에디터 슬래시 명령 목록과 삽입 줄 정의 |
|
||||
| lib/analytics-shared.js | 통계 추적 경로 필터·체류/스크롤 상수(클라이언트·서버 공용) |
|
||||
| lib/analytics.js | 서버 전용 visitor/session hash(`node:crypto`) |
|
||||
|
||||
@@ -74,7 +77,7 @@
|
||||
| components/admin/AdminSettingsNavIcon.vue | 사이트 설정 좌측 내비 항목 아이콘(`iconId`별 SVG·미구현 placeholder) |
|
||||
| components/admin/AdminPostForm.vue | 관리자 글 작성/수정 폼, Ghost형 툴바(영문 상태·Publish/Update/Unpublish/Unschedule, 서버 반영 상태 기준 분기), 초안만 서버 디바운스 자동 저장·신규 임시 슬러그·발행·예약 글은 Update로만 반영, 발행 모달(중앙 배치), 좌우 설정 패널, 미리보기 emit·미저장 이탈 가드, 추천 글 토글 등 |
|
||||
| components/admin/AdminPageForm.vue | 관리자 페이지 작성/수정 폼, 대표 이미지 선택 |
|
||||
| components/admin/AdminMarkdownEditor.vue | 관리자 글 Markdown-first 에디터, 라이브·소스 모드 `/` 슬래시 명령·미디어 모달, 커서 블록 컨텍스트·`block-panel` emit |
|
||||
| components/admin/AdminMarkdownEditor.vue | 관리자 글 Markdown-first 에디터, 라이브·소스 모드 `/` 슬래시 명령·미디어 모달(이미지·갤러리·비디오·오디오·파일), 커서 블록 컨텍스트·`block-panel` emit |
|
||||
| components/admin/AdminEditorBlockPanel.vue | 게시물 설정 사이드바 오버레이 블록 설정(이미지·갤러리·임베드) |
|
||||
| components/admin/AdminBlockEditor.vue | 관리자 글 블록형 에디터, 이미지/갤러리/콜아웃/토글/임베드 블록, 콜아웃 Emoji on/off·이모지 프리셋·배경 프리셋 선택(우측 고정 설정 패널), 갤러리 복수 미디어 선택·이미지 수별 열 배치·삽입 위치 표시 드래그 순서 변경, 한글 조합 입력 처리, Shift+Enter 줄바꿈, 코드 블록 단축 변환, AFFiNE 참고 세로 막대형 블록 핸들 선택/삭제/드래그 이동과 삽입선 표시, 하단 빈 입력 블록 유지, 본문 placeholder 표시 |
|
||||
| components/admin/AdminTagForm.vue | 관리자 태그 생성/수정 폼(이름/슬러그/설명/색상만 편집) |
|
||||
@@ -103,14 +106,14 @@
|
||||
| components/content/ProseCallout.vue | Callout 카드(Emoji 표시/숨김, 배경 프리셋, 상단 여백 중심) |
|
||||
| components/content/ProseToggle.vue | Toggle 카드(펼침 애니메이션, chevron 트리거) |
|
||||
| components/content/ContentMarkdownToggleEditor.vue | 라이브 모드 토글 제목·본문 인라인 편집 |
|
||||
| components/content/ProseVideo.vue | 비디오 |
|
||||
| components/content/ProseAudio.vue | 오디오 |
|
||||
| components/content/ProseFile.vue | 파일 |
|
||||
| components/content/ProseVideo.vue | `:::video` 공개 비디오 카드 |
|
||||
| components/content/ProseAudio.vue | `:::audio` 공개 오디오 플레이어 카드 |
|
||||
| components/content/ProseFile.vue | `:::file` 공개 다운로드 파일 카드 |
|
||||
| components/content/ProseProduct.vue | 상품 카드 |
|
||||
| components/content/ProseBookmark.vue | 본문 북마크 카드(썸네일·도메인·`http(s)` 외부 링크) |
|
||||
| components/content/ProseSignup.vue | 본문 회원가입·뉴스레터 CTA 카드 |
|
||||
| components/content/ProseHeaderCard.vue | 헤더 카드 |
|
||||
| components/content/ProseEmbed.vue | YouTube·Twitter/X iframe 임베드, 기타 `http(s)` 외부 링크 |
|
||||
| components/content/ProseEmbed.vue | YouTube 영상 iframe, X/Twitter 소셜 iframe, Mastodon `/embed` iframe, 기타 `http(s)` 외부 링크 |
|
||||
|
||||
## 관리자 페이지
|
||||
|
||||
@@ -125,7 +128,7 @@
|
||||
| pages/admin/pages/index.vue | 페이지 목록, 행 more vert 메뉴(수정·삭제) |
|
||||
| pages/admin/pages/new.vue | 페이지 작성, 저장 토스트 |
|
||||
| pages/admin/pages/[id].vue | 페이지 수정, 저장/삭제 토스트 |
|
||||
| pages/admin/media/index.vue | 미디어 관리, **미디어 라이브러리/썸네일** 탭, 폴더 트리 more vert(폴더 삭제), 검색·드래그·상세 모달 등 |
|
||||
| pages/admin/media/index.vue | 미디어 관리, **미디어 라이브러리/썸네일** 탭, 이미지·비디오·오디오·파일 목록, 폴더 트리 more vert(폴더 삭제), 검색·드래그·상세 모달 등 |
|
||||
| pages/admin/navigation/index.vue | 메뉴 관리: 상단/하단/추천 탭, 행 more vert(메뉴 항목 삭제), 드래그 정렬, `useAdminToast` |
|
||||
| components/admin/AdminRowMoreMenu.vue | 관리자 행 more vert 메뉴(트리거·팝오버) |
|
||||
| composables/useAdminRowMenu.js | 관리자 행 메뉴 열림 상태·바깥 클릭 닫기 |
|
||||
@@ -205,7 +208,7 @@
|
||||
| server/routes/admin/api/media.delete.js | 관리자 미디어 삭제 API |
|
||||
| server/routes/admin/api/media-folders.get.js | 관리자 미디어 폴더 목록 API |
|
||||
| server/routes/admin/api/media-folders.post.js | 관리자 미디어 폴더 생성 API |
|
||||
| server/routes/admin/api/uploads.post.js | 관리자 게시물·페이지용 이미지 업로드 API(원본명 기반 파일명·충돌 시 넘버링, `/uploads/posts` 저장, 성공 시 `media_metadata`를 `미분류`로 기록) |
|
||||
| server/routes/admin/api/uploads.post.js | 관리자 게시물·페이지용 미디어 업로드 API(이미지·비디오·오디오·문서, 원본명 기반 파일명·충돌 시 넘버링, `/uploads/posts` 저장, 성공 시 `media_metadata`를 `미분류`로 기록) |
|
||||
| server/routes/admin/api/member-avatar.post.js | 관리자 새 회원 생성 전 썸네일 사전 업로드 API(`/uploads/members/avatars` 저장, WebP 변환·1:1 크롭) |
|
||||
| server/routes/admin/api/tags.get.js | 관리자 태그 목록 API(`tagType`, `q`, `limit` 검색 옵션) |
|
||||
| server/routes/admin/api/tags.post.js | 관리자 태그 생성 API |
|
||||
|
||||
32
docs/spec.md
32
docs/spec.md
@@ -184,6 +184,12 @@ components/content/
|
||||
- 이미지 갤러리
|
||||
- `:::gallery` ~ `:::` fenced block 내부에 이미지 마크다운 행을 여러 개 작성
|
||||
- 렌더링: `ContentMarkdownRenderer.vue` (그리드 + 라이트박스, Esc 닫기·←/→ 이전·다음)
|
||||
- 비디오·오디오·파일 카드
|
||||
- 비디오: `:::video` ~ `:::` (`url`, `title`, `poster`, `caption` 키값 또는 URL 단독 줄)
|
||||
- 오디오: `:::audio` ~ `:::` (`url`, `title`, `description`)
|
||||
- 파일: `:::file` ~ `:::` (`url`, `title`, `description`, `name`, `size`) — 다운로드 링크 카드
|
||||
- 렌더링: `ProseVideo.vue`, `ProseAudio.vue`, `ProseFile.vue`
|
||||
- 관리자 슬래시: `/video`, `/audio`, `/file`로 빈 템플릿 삽입 후 URL·메타 수정
|
||||
- 문단과 줄바꿈
|
||||
- 관리자 Markdown-first 에디터에서 Enter는 새 문단(마크다운 한 줄)만 사용한다. Shift+Enter·문단 내 hard break는 지원하지 않는다.
|
||||
- 공개 본문 렌더러는 마크다운 한 줄을 한 문단으로 렌더링한다(레거시 줄끝 `\\`/공백 2개 표식은 표시 시 제거).
|
||||
@@ -195,7 +201,7 @@ components/content/
|
||||
- Toggle: `:::toggle 제목` ~ `:::`
|
||||
- Bookmark: `:::bookmark` ~ `:::` (본문은 `url=`, `title=`, `description=`, `thumbnail=` 키값 또는 첫 줄 URL·이어지는 제목/설명 줄)
|
||||
- Signup: `:::signup` ~ `:::` (선택: `title=`, `description=`, `button=`, `placeholder=`)
|
||||
- Embed: `:::embed` ~ `:::` (YouTube·YouTube Shorts URL은 iframe, `twitter.com`·`x.com` 게시물 URL은 X 공식 embed iframe, 그 외는 외부 링크 카드)
|
||||
- Embed: 단독 `http(s)` URL 한 줄(기존 `:::embed` ~ `:::`도 렌더링 호환). YouTube·YouTube Shorts URL은 iframe, `twitter.com`·`x.com` 게시물 URL은 X 공식 embed iframe, 그 외는 외부 링크 카드
|
||||
- 렌더링: `ProseCallout.vue`, `ProseToggle.vue`, `ProseBookmark.vue`, `ProseSignup.vue`, `ProseEmbed.vue`
|
||||
|
||||
---
|
||||
@@ -519,7 +525,7 @@ components/content/
|
||||
- 툴바 `이미지`·`갤러리`는 미디어 모달을 연다. 모달 기본 탭은 **미디어 라이브러리**이며 **업로드** 탭에서 드래그·파일 선택 후 즉시 삽입한다.
|
||||
- 미디어 라이브러리에서 단일 이미지를 선택하면 `` 형식으로 삽입한다.
|
||||
- 미디어 라이브러리에서 여러 이미지를 선택하면 `:::gallery` fenced block으로 삽입한다.
|
||||
- 작성 모드에서 커서가 이미지 마크다운 줄, `:::gallery`, `:::embed` 블록 안에 있고 textarea(또는 블록 패널)에 포커스가 있으면 게시물 설정 사이드바(420px) 위에 **블록 설정 패널**(`AdminEditorBlockPanel`)이 오른쪽에서 슬라이드 인한다. 본문 포커스가 완전히 이탈하면 슬라이드 아웃한다.
|
||||
- 작성 모드에서 커서가 이미지 마크다운 줄, `:::gallery`, 단독 URL 임베드 줄 또는 기존 `:::embed` 블록 안에 있고 textarea(또는 블록 패널)에 포커스가 있으면 게시물 설정 사이드바(420px) 위에 **블록 설정 패널**(`AdminEditorBlockPanel`)이 오른쪽에서 슬라이드 인한다. 본문 포커스가 완전히 이탈하면 슬라이드 아웃한다.
|
||||
- 블록 설정 패널: 이미지·갤러리(캡션, **파일명을 캡션으로 사용** 토글·기본 끔, URL, 갤러리 순서·삭제·추가), 임베드(URL). `AdminMarkdownEditor`는 `block-panel` 이벤트로 상태를 `AdminPostForm`에 전달한다.
|
||||
- 미디어 라이브러리 갤러리 다중 선택 시 선택 항목은 **주황(`#ff7a00`) 굵은 테두리**로 표시한다.
|
||||
- 옵시디언식 토큰 숨김/백스페이스 복원 Live Preview는 후속 단계로 둔다.
|
||||
@@ -574,15 +580,24 @@ components/content/
|
||||
- 관리자 갤러리 블록의 이미지 순서는 드래그 앤 드롭으로 변경하며, 드래그 중 삽입 위치를 이미지 사이 라인으로 표시한다.
|
||||
- 공개 갤러리는 한 줄에 2~3개 이미지 그리드로 표시하고 클릭 시 라이트박스로 크게 확인한다.
|
||||
- 이미지와 갤러리 블록은 기존 업로드 미디어 선택 또는 새 이미지 업로드를 제공한다.
|
||||
- 관리자 미디어 업로드 API는 이미지(`jpg`, `png`, `webp`, `gif`), 비디오(`mp4`, `webm`, `mov`), 오디오(`mp3`, `wav`, `ogg`, `m4a`), 파일(`pdf`, `zip`, `txt`, `csv`, `docx`, `xlsx`, `pptx`)을 지원한다.
|
||||
- 콜아웃 블록은 `:::callout` fenced block 안에 본문을 저장한다.
|
||||
- 콜아웃 블록은 선언부 옵션으로 `emoji`, `bg`를 저장할 수 있다. 예: `:::callout emoji=💡 bg=blue`
|
||||
- `emoji=none`이면 공개 렌더러에서 이모지를 숨긴다.
|
||||
- 콜아웃 배경 프리셋은 `gray`, `blue`, `green`, `yellow`, `red`, `purple`, `pink`를 지원한다.
|
||||
- 토글 블록은 `:::toggle 제목` fenced block 안에 펼침 본문을 저장한다. 라이브 모드에서는 제목·본문을 인라인 편집하며, chevron으로 펼침·접힘 시 본문이 애니메이션된다.
|
||||
- 임베드 블록은 `:::embed` fenced block 안에 URL을 저장한다.
|
||||
- YouTube 임베드 URL은 공개 화면에서 iframe으로 렌더링한다.
|
||||
- Twitter/X 게시물 URL(`twitter.com`·`x.com`·`mobile.twitter.com`, 경로에 `status` 포함)은 `platform.twitter.com/embed/Tweet.html` iframe으로 렌더링하며, 테마는 `useThemeMode()`와 동기화한다.
|
||||
- 임베드 블록은 단독 `http(s)` URL 한 줄을 기본 저장 형식으로 사용한다.
|
||||
- 기존 `:::embed` fenced block은 이전 콘텐츠 호환을 위해 계속 파싱·렌더링한다.
|
||||
- 관리자 Markdown-first 에디터의 라이브/스타일 모드에서 임베드 블록은 URL 입력 카드 없이 즉시 실제 임베드 프리뷰로 표시된다. 임베드·비디오·오디오·파일 프리뷰 카드는 hover/focus 시 우측 상단 삭제 버튼을 표시한다. 블록 래퍼에 포커스한 상태에서 `Backspace`·`Delete`·`Ctrl/Cmd+Shift+K`로 삭제하고, `Enter`로 아래 빈 줄을 추가하며, `ArrowUp`·`ArrowDown`은 브라우저 스크롤 대신 이전/다음 편집 줄로 이동한다.
|
||||
- 라이브/스타일 모드에서 제목 블록 Enter는 현재 제목 내용을 저장한 뒤 바로 아래 빈 문단을 추가하고, 원문 마크다운 편집 상태로 전환하지 않는다.
|
||||
- 게시물 작성 화면 상단 제목 입력 후 Enter는 현재 에디터 모드를 유지한 채 본문 첫 줄(마크다운 첫 줄이 제목이면 그 다음 줄)로 포커스를 옮긴다. 라이브 모드 전환 시 미리보기 스크롤은 맨 위에서 시작한다.
|
||||
- YouTube 임베드 URL은 공개 화면에서 본문 폭 기준 16:9 iframe으로 렌더링한다.
|
||||
- Twitter/X 게시물 URL(`twitter.com`·`x.com`·`mobile.twitter.com`, 경로에 `status` 포함)은 `platform.twitter.com/embed/Tweet.html` iframe으로 렌더링하며, 테마는 `useThemeMode()`와 동기화한다. X 공식 iframe의 내부 최대 폭 때문에 공개 화면에서는 카드 폭을 좁혀 중앙 정렬한다.
|
||||
- Mastodon 공개 게시물 URL(`/@user/id`, `/users/user/statuses/id`)은 `{원본 URL}/embed` iframe으로 렌더링한다. iframe 로드 후 Mastodon 공식 embed 방식과 같은 `postMessage` 높이 요청을 보내 응답 높이를 반영한다. 인스턴스가 embed를 차단하거나 지원하지 않으면 브라우저 iframe 정책에 따라 표시되지 않을 수 있다.
|
||||
- 그 외 URL은 외부 링크 텍스트 카드로 표시한다.
|
||||
- 비디오 블록은 `:::video` fenced block 안에 `url`, `title`, `poster`, `caption` 값을 저장하며 공개 화면에서 가로형 비디오 카드로 렌더링한다. 관리자 `/video` 슬래시 명령은 비디오 미디어 선택·업로드 모달을 열고 선택 파일 URL을 자동으로 채운다.
|
||||
- 오디오 블록은 `:::audio` fenced block 안에 `url`, `title`, `description` 값을 저장하며 공개 화면에서 아이콘+플레이어 카드로 렌더링한다. 관리자 `/audio` 슬래시 명령은 오디오 미디어 선택·업로드 모달을 열고 선택 파일 URL을 자동으로 채운다.
|
||||
- 파일 블록은 `:::file` fenced block 안에 `url`, `title`, `description`, `name`, `size` 값을 저장하며 공개 화면에서 다운로드 카드로 렌더링한다. 관리자 `/file` 슬래시 명령은 문서 파일 선택·업로드 모달을 열고 URL·파일명·크기를 자동으로 채운다.
|
||||
- 북마크 블록은 `:::bookmark` fenced block으로 저장할 수 있으며 공개 화면에서 Thred형 가로 카드로 렌더링한다.
|
||||
- 회원가입(뉴스레터) CTA는 `:::signup` fenced block으로 저장할 수 있으며 실제 폼 연동은 후속 작업으로 분리한다.
|
||||
|
||||
@@ -674,8 +689,8 @@ components/content/
|
||||
- 사이트 로고와 파비콘은 `public/uploads/system/`에 저장되며, 업로드 시 `media_metadata.category`는 논리 폴더 **`시스템`**으로 저장한다. 현재 사이트 설정의 `logo_url` 또는 `favicon_url`이 가리키는 파일은 사용 중인 미디어로 표시하고 파일명 변경·삭제를 차단한다.
|
||||
- 레거시 메타 값 `posts`, `회원/썸네일`은 마이그레이션 `016_media_category_normalize.sql` 및 서버 정규화로 각각 `미분류`, `썸네일`에 맞춘다.
|
||||
|
||||
- 관리자 이미지 업로드 API는 `image/jpeg`, `image/png`, `image/webp`, `image/gif`만 허용한다.
|
||||
- 업로드 파일 크기 제한은 `MAX_FILE_SIZE` 환경 변수를 따른다.
|
||||
- 관리자 미디어 업로드 API는 이미지·비디오·오디오·문서 확장자를 허용한다(에디터 슬래시·미디어 모달과 동일 목록).
|
||||
- 업로드 파일 크기 제한은 종류별 환경 변수를 따른다. 이미지·아바타·로고 등은 `MAX_FILE_SIZE`(기본 10MB), 비디오는 `MAX_VIDEO_FILE_SIZE`(기본 200MB), 오디오는 `MAX_AUDIO_FILE_SIZE`(기본 50MB), 문서·ZIP 등은 `MAX_DOCUMENT_FILE_SIZE`(기본 50MB).
|
||||
- 로컬 개발 업로드 파일은 `public/uploads/posts/YYYY/MM/` 아래 저장하고 `/uploads/posts/YYYY/MM/filename` URL로 제공한다.
|
||||
- 관리자 미디어 화면 상단에 **미디어 라이브러리** 탭과 **썸네일** 탭을 두어, 라이브러리 탭에서는 게시물·기타 이미지만, 썸네일 탭에서는 `/members/avatars/` 파일만 검색·탐색한다.
|
||||
- 미디어 라이브러리 탭은 왼쪽 폴더 트리와 오른쪽 고밀도 썸네일 갤러리, 검색, 파일명 변경, 개별 삭제를 제공한다.
|
||||
@@ -716,6 +731,9 @@ ANALYTICS_HASH_SECRET=replace-with-random-password
|
||||
# Upload
|
||||
UPLOAD_DIR=/uploads
|
||||
MAX_FILE_SIZE=10485760
|
||||
MAX_VIDEO_FILE_SIZE=209715200
|
||||
MAX_AUDIO_FILE_SIZE=52428800
|
||||
MAX_DOCUMENT_FILE_SIZE=52428800
|
||||
AVATAR_MIN_WIDTH=96
|
||||
AVATAR_MIN_HEIGHT=96
|
||||
AVATAR_MAX_WIDTH=512
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
- [ ] ProseButton Left/Center 정렬 검증
|
||||
- [ ] ProseCallout 실제 스타일 세부 조정
|
||||
- [ ] ProseToggle 실제 스타일 세부 조정
|
||||
- [ ] ProseVideo 실제 임베드 렌더링 연결
|
||||
- [ ] ProseAudio 실제 오디오 렌더링 연결
|
||||
- [ ] ProseFile 실제 파일 데이터 연결
|
||||
- [ ] ProseProduct 실제 상품 카드 데이터 연결
|
||||
- [ ] ProseHeaderCard Simple/Wide/Full-width/Split 변형 구현
|
||||
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# 업데이트 이력
|
||||
|
||||
## v1.4.1
|
||||
|
||||
- 관리자 미디어 업로드: 이미지·비디오·오디오·문서별 최대 크기 한도 분리(`MAX_VIDEO_FILE_SIZE` 등). 기본 비디오 200MB.
|
||||
- 관리자 글쓰기: 업로드 크기 초과·API 413 시 토스트 오류 표시, 미디어 모달에 최대 용량 안내 추가.
|
||||
- `lib/upload-size-limit.js`: 클라이언트 번들에서 `node:path` 제거(500·hydration 경고 수정).
|
||||
- 임베드 저장 형식: 새 임베드 삽입·라이브 편집·레거시 블록 변환 시 `:::embed` 대신 단독 URL 한 줄로 저장하도록 통일, 단독 URL 줄도 블록 설정 패널 대상으로 인식.
|
||||
- 관리자 글쓰기: 라이브 모드 임베드를 URL 입력 카드 없이 즉시 프리뷰로 표시, 임베드·비디오·오디오·파일 카드 삭제 버튼과 방향키 이동·삭제·아래 줄 추가 키보드 조작 지원.
|
||||
- 관리자 글쓰기: 라이브 모드 제목 Enter 시 현재 제목 저장 후 아래 빈 문단 추가, 원문 편집 상태로 전환되던 흐름 수정.
|
||||
- 관리자 글쓰기: 게시물 상단 제목 Enter 시 소스 모드 강제 전환 제거, 라이브 모드 상단 스크롤·본문 첫 줄 포커스 보정.
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- 콘텐츠 렌더러: `:::video`, `:::audio`, `:::file` fenced block 파싱과 `ProseVideo`·`ProseAudio`·`ProseFile` 카드 렌더링 연결.
|
||||
- 관리자 글쓰기: 슬래시 명령에 비디오·오디오·파일 블록 템플릿 추가.
|
||||
- 임베드: X/Twitter iframe 폭·높이·외곽 여백 보정, Mastodon 공개 게시물 `/embed` 렌더링과 postMessage 기반 자동 높이 조절 추가.
|
||||
- 관리자 글쓰기: 라이브/스타일 모드의 `:::embed` 블록에 URL 입력 카드와 적용 미리보기 전환 버튼 표시.
|
||||
- 관리자 글쓰기: `/video`, `/audio`, `/file` 슬래시 명령을 미디어 선택·업로드 모달과 연결해 업로드 후 URL 자동 채우기 지원.
|
||||
- 콘텐츠 렌더러: 단독 `http(s)` URL 한 줄을 `:::embed` 블록과 동일하게 자동 임베드 렌더링.
|
||||
- 미디어 라이브러리: 이미지 외 비디오·오디오·문서 파일 업로드와 목록 표시 지원.
|
||||
|
||||
## v1.3.9
|
||||
|
||||
- NAS 마이그레이션: `psql`이 while 루프 stdin을 소비해 001만 처리되던 `migrate-production-db.sh` 버그 수정.
|
||||
|
||||
Reference in New Issue
Block a user