From a93780731c6585b73762e1cdf17efe8122b904ea Mon Sep 17 00:00:00 2001 From: zenn Date: Wed, 24 Jun 2026 10:16:40 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8C=80=ED=91=9C=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=9B=90=EB=B3=B8=20=EC=84=A0=ED=83=9D=20=EB=B3=B4?= =?UTF-8?q?=EA=B0=95=20v1.7.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/admin/AdminMarkdownEditor.vue | 10 ++-------- components/admin/AdminPostForm.vue | 17 +++++++++++++---- docs/changelog.md | 5 +++++ docs/deploy.md | 9 ++++++++- docs/map.md | 5 +++-- docs/spec.md | 3 ++- docs/update.md | 6 ++++++ lib/post-card-thumbnail-url.js | 10 ++++++++++ package-lock.json | 4 ++-- package.json | 2 +- server/utils/admin-post-input.js | 7 ++++++- server/utils/post-thumbnail-image.js | 11 +++-------- 12 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 lib/post-card-thumbnail-url.js diff --git a/components/admin/AdminMarkdownEditor.vue b/components/admin/AdminMarkdownEditor.vue index 053c29e..189f5e5 100644 --- a/components/admin/AdminMarkdownEditor.vue +++ b/components/admin/AdminMarkdownEditor.vue @@ -25,6 +25,7 @@ import { import { buildCalloutOpenerLine, CALLOUT_BACKGROUND_OPTIONS, QUOTE_BACKGROUND_OPTIONS } from '../../lib/markdown-callout.js' import { buildCodeFenceOpener } from '../../lib/markdown-code-block.js' import { buildToggleOpenerLine } from '../../lib/markdown-toggle.js' +import { isPostCardThumbnailUrl } from '../../lib/post-card-thumbnail-url.js' import { getTextareaCaretCoordinates } from '../../lib/textarea-caret-coordinates.js' import { buildDefaultUploadSizeLimits, @@ -138,13 +139,6 @@ const mediaPickerAccept = computed(() => { return '.pdf,.zip,.txt,.csv,.docx,.xlsx,.pptx' }) -/** - * 게시물 카드용 파생 썸네일 URL인지 확인한다. - * @param {string|null|undefined} url - 미디어 URL - * @returns {boolean} 카드 썸네일 여부 - */ -const isPostCardThumbnailMediaUrl = (url) => /^\/uploads\/posts\/\d{4}\/\d{2}\/thumbs\/[^/?#]+-card\.webp$/i.test(String(url || '')) - /** 작성 textarea 최소 높이(px) */ const MIN_TEXTAREA_HEIGHT_PX = 620 @@ -1819,7 +1813,7 @@ const getMediaItemKind = (item) => { * @returns {boolean} 선택 가능 여부 */ const isMediaItemSelectableForTarget = (item) => { - if (isPostCardThumbnailMediaUrl(item?.url)) { + if (isPostCardThumbnailUrl(item?.url)) { return false } diff --git a/components/admin/AdminPostForm.vue b/components/admin/AdminPostForm.vue index 0649987..374c8f0 100644 --- a/components/admin/AdminPostForm.vue +++ b/components/admin/AdminPostForm.vue @@ -5,6 +5,7 @@ import { toAdminPostStoredTitle } from '../../lib/admin-post-title.js' import { normalizeMarkdownContent } from '../../lib/markdown-content-normalizer.js' +import { isPostCardThumbnailUrl } from '../../lib/post-card-thumbnail-url.js' import { DEFAULT_POST_TAG_LIMIT, normalizePostTagLimit } from '../../lib/post-tag-limit.js' const props = defineProps({ @@ -92,6 +93,14 @@ const defaultTagColor = '#15171a' /** @type {number} 한국어 본문 예상 읽기 속도(분당 공백 제외 문자 수) */ const READING_CHARS_PER_MINUTE = 600 +/** + * 대표 이미지로 선택 가능한 원본 이미지 목록 + * @returns {Array} 카드 썸네일을 제외한 이미지 목록 + */ +const featuredImageMediaItems = computed(() => mediaItems.value.filter((item) => ( + item?.kind === 'image' && !isPostCardThumbnailUrl(item.url) +))) + /** * ISO 날짜를 datetime-local 입력값으로 변환 * @param {string} value - ISO 날짜 문자열 @@ -750,7 +759,7 @@ const fetchMediaItems = async () => { const openMediaPicker = async (target = 'featuredImage') => { mediaPickerTarget.value = target activeMediaPickerTab.value = 'upload' - selectedMediaPickerUrl.value = form[target] || '' + selectedMediaPickerUrl.value = isPostCardThumbnailUrl(form[target]) ? '' : form[target] || '' isMediaPickerOpen.value = true await fetchMediaItems() } @@ -777,7 +786,7 @@ const selectPickedImage = (item) => { * @returns {void} */ const applyPickedImage = () => { - if (!selectedMediaPickerUrl.value) { + if (!selectedMediaPickerUrl.value || isPostCardThumbnailUrl(selectedMediaPickerUrl.value)) { return } @@ -2138,9 +2147,9 @@ defineExpose({

미디어를 불러오는 중입니다.

-
+