대표 이미지 선택 흐름 정리

This commit is contained in:
2026-05-07 16:02:50 +09:00
parent f757c3db78
commit 97d2d8ffb3
7 changed files with 58 additions and 22 deletions

View File

@@ -47,6 +47,7 @@ const isRestoringAutosave = ref(false)
const isSettingsOpen = ref(true)
const tagInput = ref('')
const activeMediaPickerTab = ref('upload')
const selectedMediaPickerUrl = ref('')
/**
* ISO 날짜를 datetime-local 입력값으로 변환
@@ -337,6 +338,7 @@ const fetchMediaItems = async () => {
const openMediaPicker = async (target = 'featuredImage') => {
mediaPickerTarget.value = target
activeMediaPickerTab.value = 'upload'
selectedMediaPickerUrl.value = form[target] || ''
isMediaPickerOpen.value = true
await fetchMediaItems()
}
@@ -350,12 +352,24 @@ const closeMediaPicker = () => {
}
/**
* 대표 이미지 선택
* 대표 이미지 선택 상태 변경
* @param {Object} item - 미디어 항목
* @returns {void}
*/
const selectPickedImage = (item) => {
form[mediaPickerTarget.value] = item.url
selectedMediaPickerUrl.value = item.url
}
/**
* 선택한 대표 이미지 적용
* @returns {void}
*/
const applyPickedImage = () => {
if (!selectedMediaPickerUrl.value) {
return
}
form[mediaPickerTarget.value] = selectedMediaPickerUrl.value
closeMediaPicker()
}
@@ -425,9 +439,9 @@ const uploadFeaturedImageFile = async (file) => {
method: 'POST',
body: formData
})
form.featuredImage = result.files?.[0]?.url || ''
selectedMediaPickerUrl.value = result.files?.[0]?.url || ''
await fetchMediaItems()
closeMediaPicker()
activeMediaPickerTab.value = 'library'
} finally {
isUploadingFeaturedImage.value = false
}
@@ -586,17 +600,13 @@ defineExpose({
<main class="admin-post-form__editor-scroll min-h-0 flex-1 overflow-y-auto">
<section class="admin-post-form__content mx-auto w-full max-w-[804px] px-8 pb-16 pt-32">
<div class="admin-post-form__feature-block mb-9">
<figure v-if="form.featuredImage" class="admin-post-form__featured-editor overflow-hidden rounded border border-line bg-white">
<figure v-if="form.featuredImage" class="admin-post-form__featured-editor group relative overflow-hidden bg-white">
<img class="admin-post-form__featured-editor-image aspect-[16/9] w-full bg-surface object-cover" :src="form.featuredImage" alt="">
<figcaption class="admin-post-form__featured-editor-actions flex flex-wrap items-center gap-2 border-t border-line p-3">
<button class="admin-post-form__featured-change rounded border border-line px-3 py-1.5 text-xs font-semibold transition-colors hover:border-[#c8ced3] hover:bg-[#eff1f2]" type="button" @click="openMediaPicker('featuredImage')">
<figcaption class="admin-post-form__featured-editor-actions pointer-events-none absolute inset-0 flex items-end justify-end gap-2 bg-gradient-to-t from-black/40 via-black/5 to-transparent p-4 opacity-0 transition-opacity duration-150 group-hover:pointer-events-auto group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:opacity-100">
<button class="admin-post-form__featured-change rounded bg-white/95 px-3 py-1.5 text-xs font-semibold text-[#15171a] shadow-sm transition-colors hover:bg-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white" type="button" @click="openMediaPicker('featuredImage')">
변경
</button>
<label class="admin-post-form__featured-reupload cursor-pointer rounded border border-line px-3 py-1.5 text-xs font-semibold transition-colors hover:border-[#c8ced3] hover:bg-[#eff1f2]">
업로드
<input class="sr-only" type="file" accept="image/*" @change="uploadFeaturedImage">
</label>
<button class="admin-post-form__featured-remove rounded border border-red-200 px-3 py-1.5 text-xs font-semibold text-red-700 transition-colors hover:bg-red-50" type="button" @click="removeFeaturedImage">
<button class="admin-post-form__featured-remove rounded bg-[#fff1f2]/95 px-3 py-1.5 text-xs font-semibold text-red-700 shadow-sm transition-colors hover:bg-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white" type="button" @click="removeFeaturedImage">
삭제
</button>
</figcaption>
@@ -874,12 +884,19 @@ defineExpose({
<button
v-for="item in mediaItems"
:key="item.url"
class="admin-post-form__media-picker-item overflow-hidden border border-line bg-white text-left transition hover:border-[#8e9cac] hover:shadow-sm"
class="admin-post-form__media-picker-item relative overflow-hidden border bg-white text-left transition hover:border-[#8e9cac] hover:shadow-sm"
:class="selectedMediaPickerUrl === item.url ? 'border-[#15171a] ring-2 ring-[#15171a]' : 'border-line'"
type="button"
:aria-pressed="selectedMediaPickerUrl === item.url"
@click="selectPickedImage(item)"
>
<img class="admin-post-form__media-picker-image aspect-square w-full bg-surface object-cover" :src="item.url" :alt="item.title">
<span class="admin-post-form__media-picker-name block truncate px-2 py-1.5 text-xs font-semibold text-ink">{{ item.name }}</span>
<span v-if="selectedMediaPickerUrl === item.url" class="admin-post-form__media-picker-selected absolute right-2 top-2 grid size-6 place-items-center rounded-full bg-[#15171a] text-white" aria-hidden="true">
<svg width="13" height="10" viewBox="0 0 13 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 5L4.5 8.5L12 1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</button>
</div>
<p v-else class="admin-post-form__media-picker-empty border border-dashed border-line p-8 text-center text-sm text-muted">
@@ -889,11 +906,12 @@ defineExpose({
</div>
<div class="admin-post-form__media-picker-footer flex h-14 shrink-0 items-center justify-end border-t border-line px-5">
<button
class="admin-post-form__media-picker-confirm h-9 rounded border border-line px-4 text-sm font-semibold text-muted disabled:cursor-not-allowed disabled:opacity-50"
class="admin-post-form__media-picker-confirm h-9 rounded bg-[#15171a] px-4 text-sm font-semibold text-white transition-colors hover:bg-black disabled:cursor-not-allowed disabled:bg-[#d7dce0] disabled:text-[#8e9cac]"
type="button"
disabled
:disabled="!selectedMediaPickerUrl"
@click="applyPickedImage"
>
대표 이미지 설정
대표 이미지 적용
</button>
</div>
</section>