미디어 폴더 패널 렌더링 분리

This commit is contained in:
2026-07-24 13:43:47 +09:00
parent e6c78f8686
commit b2537d4d14
7 changed files with 197 additions and 116 deletions

View File

@@ -36,13 +36,6 @@ const memberRoleBadgeLabels = {
member: '멤버'
}
/**
* 논리 폴더 경로가 썸네일 전용 루트인지 확인한다.
* @param {string} folder - 폴더 경로
* @returns {boolean} 썸네일 전용이면 true
*/
const isThumbnailFolderPath = (folder) => folder === MEDIA_THUMBNAIL_ROOT || String(folder).startsWith(`${MEDIA_THUMBNAIL_ROOT}/`)
const activeTab = ref('library')
const searchText = ref('')
const {
@@ -83,13 +76,6 @@ const { toast, showToast } = useAdminToast()
const { openMenuId, closeMenu } = useAdminRowMenu()
/**
* 폴더 행 메뉴 id
* @param {string} folder - 폴더 경로
* @returns {string}
*/
const getFolderMenuId = (folder) => `folder:${folder}`
const mediaQuery = computed(() => ({
paged: '1',
tab: activeTab.value,
@@ -712,20 +698,6 @@ const formatFileSize = (size) => {
return `${(size / 1024 / 1024).toFixed(1)} MB`
}
/**
* 폴더 경로의 표시 이름 조회
* @param {string} folder - 폴더 경로
* @returns {string} 표시 이름
*/
const getFolderName = (folder) => folder.split('/').filter(Boolean).pop() || '미분류'
/**
* 폴더 깊이 조회
* @param {string} folder - 폴더 경로
* @returns {number} 폴더 깊이
*/
const getFolderDepth = (folder) => Math.max(folder.split('/').filter(Boolean).length - 1, 0)
/**
* 미디어 선택 여부 확인
* @param {Object} item - 미디어 항목
@@ -1433,90 +1405,22 @@ watch(() => mediaPagination.value.page, (page) => {
</div>
<div class="admin-media__layout mt-8 grid gap-5 lg:grid-cols-[16rem_minmax(0,1fr)]">
<aside
v-if="activeTab === 'library'"
class="admin-media__folders rounded border border-line bg-white p-3"
>
<button
class="admin-media__folder-button flex w-full items-center justify-between rounded px-3 py-2 text-left text-sm font-semibold hover:bg-surface"
:class="!activeFolder ? 'bg-[#15171a] text-white hover:bg-[#15171a]' : 'text-ink'"
type="button"
@click="selectFolder('')"
@dragover.prevent
@drop.prevent="dropMediaOnFolder('미분류')"
>
<span>전체 미디어</span>
<span>{{ mediaCounts.tabs?.library || 0 }}</span>
</button>
<div class="admin-media__folder-list mt-3 grid gap-1">
<div
v-for="folder in normalizedFolders"
:key="folder"
class="admin-media__folder-row flex items-stretch rounded"
:class="activeFolder === folder ? 'bg-[#15171a] text-white' : 'text-ink hover:bg-surface'"
>
<button
class="admin-media__folder-button flex min-w-0 flex-1 items-center justify-between rounded py-2 pr-3 text-left text-sm"
:style="{ paddingLeft: `${12 + getFolderDepth(folder) * 14}px` }"
type="button"
@click="selectFolder(folder)"
@dragover.prevent
@drop.prevent="dropMediaOnFolder(folder)"
>
<span class="admin-media__folder-name min-w-0 truncate">{{ getFolderName(folder) }}</span>
<span class="admin-media__folder-count shrink-0 text-xs opacity-70">{{ folderMediaCounts[folder] || 0 }}</span>
</button>
<AdminRowMoreMenu
v-if="folder !== '미분류' && !isThumbnailFolderPath(folder)"
v-model:open-menu-id="openMenuId"
:item-id="getFolderMenuId(folder)"
menu-label="폴더 메뉴"
size="sm"
class="mr-0.5 shrink-0"
:inverse="activeFolder === folder"
:busy="deletingFolder === folder"
>
<button
class="admin-row-more-menu__item admin-row-more-menu__item--danger"
type="button"
role="menuitem"
:disabled="deletingFolder === folder"
@click="removeMediaFolder(folder)"
>
폴더 삭제
</button>
</AdminRowMoreMenu>
</div>
</div>
<div v-if="activeTab === 'library'" class="admin-media__folder-actions mt-4 border-t border-line pt-4">
<button
class="admin-media__folder-add w-full rounded bg-[#15171a] px-3 py-2 text-xs font-semibold text-white"
type="button"
@click="openCreateFolderModal"
>
폴더 추가
</button>
</div>
</aside>
<aside
v-else
class="admin-media__folders admin-media__folders--thumbnails rounded border border-line bg-white p-3"
>
<button
class="admin-media__folder-button flex w-full items-center justify-between rounded px-3 py-2 text-left text-sm font-semibold bg-[#15171a] text-white hover:bg-[#15171a]"
type="button"
@click="selectFolder('')"
>
<span>{{ activeSystemMediaTitle }}</span>
<span>{{ activeSystemMediaCount }}</span>
</button>
<p class="admin-media__thumb-hint mt-4 text-xs leading-relaxed text-muted">
{{ activeSystemMediaHint }}
</p>
</aside>
<AdminMediaFolderPanel
v-model:open-menu-id="openMenuId"
:active-folder="activeFolder"
:active-system-media-count="activeSystemMediaCount"
:active-system-media-hint="activeSystemMediaHint"
:active-system-media-title="activeSystemMediaTitle"
:deleting-folder="deletingFolder"
:folder-media-counts="folderMediaCounts"
:folders="normalizedFolders"
:library-count="mediaCounts.tabs?.library || 0"
:mode="activeTab === 'library' ? 'library' : 'system'"
@create-folder="openCreateFolderModal"
@drop-folder="dropMediaOnFolder"
@remove-folder="removeMediaFolder"
@select-folder="selectFolder"
/>
<div class="admin-media__content min-w-0">
<div class="admin-media__toolbar flex flex-wrap items-center justify-between gap-3">