미디어 그리드 렌더링 분리

This commit is contained in:
2026-07-24 13:47:34 +09:00
parent b2537d4d14
commit 5b6e4d33dd
7 changed files with 161 additions and 86 deletions

View File

@@ -1471,88 +1471,21 @@ watch(() => mediaPagination.value.page, (page) => {
</div>
</div>
<div v-if="filteredMediaItems.length" class="admin-media__grid mt-5 grid grid-cols-3 gap-2 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10">
<div
v-for="(item, index) in paginatedMediaItems"
:key="item.url"
class="admin-media__item group relative overflow-hidden border border-line bg-white text-left outline-none transition hover:border-[#15171a]"
:draggable="activeTab === 'library'"
@dragstart="startMediaDrag($event, item)"
>
<button
type="button"
class="admin-media__select-toggle absolute left-1.5 top-1.5 z-10 grid size-7 place-items-center rounded-md border-2 shadow-md outline-none transition focus-visible:ring-2 focus-visible:ring-[#15171a] focus-visible:ring-offset-1"
:class="isMediaSelected(item)
? 'border-white bg-[#15171a] text-white'
: 'border-[#394047] bg-white/95 text-[#15171a] hover:border-[#15171a] hover:bg-white'"
:aria-label="`${item.name} 선택`"
:aria-pressed="isMediaSelected(item)"
@click.stop="toggleMediaSelection(item, index, $event)"
>
<svg
v-if="isMediaSelected(item)"
class="size-4 shrink-0"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5" />
</svg>
</button>
<button
class="admin-media__thumb flex w-full flex-col text-left outline-none"
type="button"
@click="openMediaDetail(item)"
>
<span class="admin-media__thumb-frame relative block w-full overflow-hidden">
<img
v-if="getMediaItemKind(item) === 'image'"
class="admin-media__image aspect-square w-full bg-surface object-cover"
:src="getMediaGridPreviewUrl(item)"
:alt="item.title"
loading="lazy"
decoding="async"
@error="onMediaGridImageError($event, item)"
>
<AdminMediaVideoThumbnail
v-else-if="getMediaItemKind(item) === 'video'"
:src="item.url"
:alt="item.title"
/>
<span
v-else
class="admin-media__image flex aspect-square w-full items-center justify-center bg-surface text-xs font-bold uppercase tracking-[0.18em] text-muted"
>
{{ getMediaItemKind(item) }}
</span>
<span
v-if="getMediaUsageBadgeCount(item)"
class="admin-media__usage-count-badge pointer-events-none absolute right-1.5 top-1.5 z-[1] rounded bg-[#15171a] px-1.5 py-0.5 text-[10px] font-semibold text-white"
>
{{ getMediaUsageBadgeCount(item) }}
</span>
<span
v-if="getMediaBadgeLabel(item)"
class="admin-media__usage-badge pointer-events-none absolute right-1.5 z-[1] rounded px-1.5 py-0.5 text-[10px] font-semibold"
:class="[
getMediaBadgeClass(item),
getMediaUsageBadgeCount(item) ? 'top-8' : 'top-1.5'
]"
>
{{ getMediaBadgeLabel(item) }}
</span>
</span>
<span class="admin-media__name block truncate px-2 py-1.5 text-xs font-semibold text-ink">
{{ item.name }}
</span>
</button>
</div>
</div>
<AdminMediaGrid
v-if="filteredMediaItems.length"
:active-tab="activeTab"
:get-media-badge-class="getMediaBadgeClass"
:get-media-badge-label="getMediaBadgeLabel"
:get-media-grid-preview-url="getMediaGridPreviewUrl"
:get-media-item-kind="getMediaItemKind"
:get-media-usage-badge-count="getMediaUsageBadgeCount"
:items="paginatedMediaItems"
:selected-urls="selectedMediaUrls"
@drag-start="startMediaDrag"
@image-error="onMediaGridImageError"
@open-detail="openMediaDetail"
@toggle-selection="toggleMediaSelection"
/>
<p v-else class="admin-media__empty mt-5 border border-dashed border-line bg-white p-8 text-center text-sm text-muted">
표시할 미디어가 없습니다.