From 95d234a625fedd844711ca5cd3f8549377968e3f Mon Sep 17 00:00:00 2001 From: zenn Date: Tue, 9 Jun 2026 17:10:16 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B8=80=EC=93=B0=EA=B8=B0=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EC=A0=9C=ED=95=9C=EA=B3=BC=20=ED=91=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- components/admin/AdminMarkdownEditor.vue | 32 ++-- components/admin/AdminPostForm.vue | 39 +++- components/admin/AdminSlashCommandIcon.vue | 6 + components/admin/AdminTagForm.vue | 71 +++++++- .../content/ContentMarkdownRenderer.vue | 168 ++++++++++++++++++ .../056_site_settings_post_tag_limit.sql | 10 ++ docs/changelog.md | 13 ++ docs/deploy.md | 17 +- docs/history.md | 4 + docs/map.md | 15 +- docs/spec.md | 19 +- docs/update.md | 17 ++ lib/markdown-slash-commands.js | 8 + lib/post-tag-limit.js | 18 ++ package.json | 2 +- pages/admin/settings/index.vue | 69 +++++-- pages/admin/tags/[id].vue | 26 ++- pages/admin/tags/index.vue | 16 ++ pages/admin/tags/new.vue | 25 ++- server/repositories/content-repository.js | 5 + server/routes/admin/api/posts.post.js | 12 +- server/routes/admin/api/posts/[id].put.js | 12 +- server/utils/admin-site-settings-input.js | 8 + server/utils/site-settings.js | 2 + 24 files changed, 560 insertions(+), 54 deletions(-) create mode 100644 db/migrations/056_site_settings_post_tag_limit.sql create mode 100644 lib/post-tag-limit.js diff --git a/components/admin/AdminMarkdownEditor.vue b/components/admin/AdminMarkdownEditor.vue index 7c439f9..b698145 100644 --- a/components/admin/AdminMarkdownEditor.vue +++ b/components/admin/AdminMarkdownEditor.vue @@ -2747,6 +2747,10 @@ defineExpose({ * @returns {void} */ const closeMediaPicker = () => { + if (isUploading.value) { + return + } + isMediaPickerOpen.value = false selectedMediaUrls.value = [] activeMediaPickerTab.value = 'library' @@ -2999,7 +3003,7 @@ const handleFileInput = async (event, target) => { } /** - * 미디어 모달 업로드 탭에서 파일을 삽입한다. + * 미디어 모달 업로드 탭에서 파일을 업로드하고 라이브러리 목록을 갱신한다. * @param {FileList|Array} files - 업로드 파일 목록 * @returns {Promise} */ @@ -3008,10 +3012,6 @@ const uploadFromMediaModal = async (files) => { return } - const target = mediaPickerTarget.value === 'gallery' || mediaPickerTarget.value === 'active-gallery' - ? 'gallery' - : mediaPickerTarget.value - isUploading.value = true try { @@ -3020,8 +3020,10 @@ const uploadFromMediaModal = async (files) => { ...uploadedFiles, ...mediaItems.value ]) - insertSelectedMediaItems(target === 'gallery' ? uploadedFiles : uploadedFiles.slice(0, 1)) - closeMediaPicker() + selectedMediaUrls.value = [] + activeMediaPickerTab.value = 'library' + mediaSearchQuery.value = '' + showToast('success', '업로드가 완료되었습니다. 목록에서 파일을 선택해 삽입해 주세요.') } catch (error) { showToast('error', resolveUploadFetchErrorMessage(error)) } finally { @@ -3360,7 +3362,12 @@ const handleKeydown = (event) => { {{ selectedMediaUrls.length }}개 선택됨

- @@ -3483,13 +3490,18 @@ const handleKeydown = (event) => {