diff --git a/frontend/src/pages/relay/DrivePage.vue b/frontend/src/pages/relay/DrivePage.vue
index 08ae8af..43ffad9 100644
--- a/frontend/src/pages/relay/DrivePage.vue
+++ b/frontend/src/pages/relay/DrivePage.vue
@@ -9,7 +9,7 @@ import EmptyState from '@/components/common/EmptyState.vue'
import DriveNameModal from '@/components/drive/DriveNameModal.vue'
import { useDriveStore } from '@/stores/drive.store'
import { useDialog } from '@/composables/useDialog'
-import { fileBadge, formatBytes, relativeTimeKo } from '@/shared/utils/format'
+import { fileBadgeOf, formatBytes, relativeTimeKo } from '@/shared/utils/format'
import {
DRIVE_ACCEPT,
DRIVE_MAX_FILE_SIZE,
@@ -409,8 +409,8 @@ watch(
>
{{ fileBadge(f.kind).label }}
+ :class="fileBadgeOf(f.name).cls"
+ >{{ fileBadgeOf(f.name).label }}
{{ f.name }}
{{ formatBytes(f.size) }} · {{ relativeTimeKo(f.updatedAt) }}
@@ -681,6 +681,18 @@ watch(
.dr-badge.fi-doc {
background: #3d8bf2;
}
+.dr-badge.fi-xls {
+ background: #1f9d57;
+}
+.dr-badge.fi-ppt {
+ background: #e0823d;
+}
+.dr-badge.fi-txt {
+ background: #5b6470;
+}
+.dr-badge.fi-media {
+ background: #c0469d;
+}
.dr-main {
min-width: 0;
display: flex;
diff --git a/frontend/src/shared/utils/format.ts b/frontend/src/shared/utils/format.ts
index 323c0d8..6f8ab46 100644
--- a/frontend/src/shared/utils/format.ts
+++ b/frontend/src/shared/utils/format.ts
@@ -82,6 +82,31 @@ export function fileBadge(kind: FileKind): { label: string; cls: string } {
return map[kind]
}
+/**
+ * 확장자 기준 세분화 배지(라벨/색상) — 4종 kind 보다 정확히 표기.
+ * 예: 엑셀 → XLS, 파워포인트 → PPT, 워드 → DOC. (드라이브 파일 행 등)
+ */
+export function fileBadgeOf(name: string): { label: string; cls: string } {
+ const ext = name.split('.').pop()?.toLowerCase() ?? ''
+ if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp'].includes(ext))
+ return { label: 'IMG', cls: 'fi-img' }
+ if (ext === 'pdf') return { label: 'PDF', cls: 'fi-pdf' }
+ if (['xls', 'xlsx'].includes(ext)) return { label: 'XLS', cls: 'fi-xls' }
+ if (['doc', 'docx'].includes(ext)) return { label: 'DOC', cls: 'fi-doc' }
+ if (['ppt', 'pptx'].includes(ext)) return { label: 'PPT', cls: 'fi-ppt' }
+ if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext))
+ return { label: 'ZIP', cls: 'fi-zip' }
+ if (ext === 'csv') return { label: 'CSV', cls: 'fi-txt' }
+ if (ext === 'json') return { label: 'JSON', cls: 'fi-txt' }
+ if (['txt', 'md'].includes(ext))
+ return { label: ext.toUpperCase(), cls: 'fi-txt' }
+ if (['mp4', 'webm', 'mov', 'avi', 'mkv'].includes(ext))
+ return { label: 'VID', cls: 'fi-media' }
+ if (['mp3', 'wav', 'ogg', 'flac', 'm4a'].includes(ext))
+ return { label: 'AUD', cls: 'fi-media' }
+ return { label: 'FILE', cls: 'fi-doc' }
+}
+
/** 바이트 수를 사람이 읽기 쉬운 단위로 (예: 19293798 → "18.4 MB") */
export function formatBytes(bytes: number): string {
if (!Number.isFinite(bytes) || bytes <= 0) return '0 B'