feat: 드라이브(파일 저장소) 프론트엔드 UI 구현

폴더 탐색·드래그앤드롭 업로드(presigned 3단계)·다운로드·이름변경/삭제, 라우트(/drive)·사이드바 네비 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-30 18:20:51 +09:00
parent 9ce3158450
commit 638d1265f6
8 changed files with 1264 additions and 1 deletions
+83
View File
@@ -0,0 +1,83 @@
// 드라이브 클라이언트 측 상수/순수 유틸 — 업로드 사전 검증·MIME 추론
// (백엔드 drive.config.ts 의 화이트리스트/최대크기와 동기화 유지)
// 파일 1건 최대 크기(기본 200MB) — 백엔드 DRIVE_MAX_FILE_MB 기본값과 일치
export const DRIVE_MAX_FILE_SIZE = 200 * 1024 * 1024
// 허용 MIME 화이트리스트(백엔드 DRIVE_ALLOWED_MIME_TYPES 미러)
export const DRIVE_ALLOWED_MIME: ReadonlySet<string> = new Set<string>([
// 이미지
'image/png',
'image/jpeg',
'image/gif',
'image/webp',
// 문서
'application/pdf',
'text/plain',
'text/csv',
'text/markdown',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/json',
// 압축
'application/zip',
'application/x-zip-compressed',
'application/x-7z-compressed',
'application/x-rar-compressed',
// 미디어
'video/mp4',
'video/webm',
'video/quicktime',
'audio/mpeg',
'audio/wav',
'audio/ogg',
])
// <input type="file" accept="..."> 용 확장자 목록
export const DRIVE_ACCEPT =
'.png,.jpg,.jpeg,.gif,.webp,.pdf,.txt,.csv,.md,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.json,.zip,.7z,.rar,.mp4,.webm,.mov,.mp3,.wav,.ogg'
// 확장자 → MIME 추론(브라우저가 file.type 을 비워줄 때 보완)
const EXT_TO_MIME: Record<string, string> = {
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
gif: 'image/gif',
webp: 'image/webp',
pdf: 'application/pdf',
txt: 'text/plain',
csv: 'text/csv',
md: 'text/markdown',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
json: 'application/json',
zip: 'application/zip',
'7z': 'application/x-7z-compressed',
rar: 'application/x-rar-compressed',
mp4: 'video/mp4',
webm: 'video/webm',
mov: 'video/quicktime',
mp3: 'audio/mpeg',
wav: 'audio/wav',
ogg: 'audio/ogg',
}
// 파일의 MIME 결정 — file.type 우선, 없으면 확장자로 추론
export function resolveMimeType(file: File): string {
if (file.type) return file.type
const ext = file.name.split('.').pop()?.toLowerCase() ?? ''
return EXT_TO_MIME[ext] ?? ''
}
// 업로드 허용 여부
export function isAllowedDriveMime(mime: string): boolean {
return DRIVE_ALLOWED_MIME.has(mime)
}