Add video sorting, reference thumbnails, theme/i18n, menu, DnD/paste, presets
Feature work on top of the initial organizer: - Videos: .mp4/.mov/.avi/.mkv/.webm/.m4v sorted into output/Movie/YYYY/MM - Profiles: reference-image thumbnail cards via a secure photoai-media:// protocol (serves only registered reference images); per-thumbnail delete; add via click, drag & drop, or paste (Ctrl+V) using webUtils.getPathForFile + a byte-based addReferenceData path for clipboard images - Presets: local person library (max 5) saved to userData; one-click apply into active profiles; reusing stored descriptors (no recompute) - Theme: dark/light with dark default (Tailwind class strategy) - i18n: ko/en table-based localization; first-run onboarding to pick language + theme; English-neutral "Unsorted" folder (was [미정]) - App menu: File/Edit/View/Window/Help, localized; Help opens a detailed, theme-aware user guide window - UI: History block scrolls internally (no whole-window scroll); threshold/concurrency tooltips; generic example name - Settings persisted to userData/settings.json; menu + renderer kept in sync - Docs: NextGen Photo AI feasibility review + Phase 0/1 roadmap All typecheck/tests (12) /build green; boot smoke verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+25
-14
@@ -1,5 +1,7 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useStore, wireEvents } from './store'
|
||||
import { useT } from './i18n'
|
||||
import { Onboarding } from './components/Onboarding'
|
||||
import { ProfileManager } from './components/ProfileManager'
|
||||
import { FolderPicker } from './components/FolderPicker'
|
||||
import { RunControl } from './components/RunControl'
|
||||
@@ -8,35 +10,44 @@ import { FileList } from './components/FileList'
|
||||
import { ReportView } from './components/ReportView'
|
||||
|
||||
export default function App(): JSX.Element {
|
||||
const t = useT()
|
||||
const phase = useStore((s) => s.phase)
|
||||
const onboarded = useStore((s) => s.onboarded)
|
||||
const refreshProfiles = useStore((s) => s.refreshProfiles)
|
||||
const initSettings = useStore((s) => s.initSettings)
|
||||
const [ready, setReady] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const unwire = wireEvents()
|
||||
// 설정 로드(테마 적용 포함) 후 화면 표시
|
||||
void initSettings().then(() => setReady(true))
|
||||
void refreshProfiles()
|
||||
return unwire
|
||||
}, [refreshProfiles])
|
||||
}, [refreshProfiles, initSettings])
|
||||
|
||||
if (!ready) return <div className="h-full" />
|
||||
if (!onboarded) return <Onboarding />
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col">
|
||||
<header className="px-6 py-4 bg-white border-b border-slate-200 shadow-sm">
|
||||
<h1 className="text-xl font-bold text-brand-dark">AI Photo Organizer</h1>
|
||||
<p className="text-sm text-slate-500">
|
||||
얼굴 인식 + 촬영일 기준 자동 사진 정리 · 로컬 전용
|
||||
</p>
|
||||
<div className="h-full flex flex-col">
|
||||
<header className="px-6 py-4 bg-white dark:bg-slate-800 border-b border-slate-200 dark:border-slate-700 shadow-sm shrink-0">
|
||||
<h1 className="text-xl font-bold text-brand-dark dark:text-brand">{t('app.title')}</h1>
|
||||
<p className="text-sm text-slate-500 dark:text-slate-400">{t('app.subtitle')}</p>
|
||||
</header>
|
||||
|
||||
<main className="flex-1 grid grid-cols-12 gap-4 p-6 overflow-hidden">
|
||||
{/* 좌측: 설정 패널 */}
|
||||
<section className="col-span-5 flex flex-col gap-4 overflow-y-auto pr-2">
|
||||
<main className="flex-1 min-h-0 grid grid-cols-12 gap-4 p-6">
|
||||
{/* 좌측: 설정 패널 (자체 스크롤) */}
|
||||
<section className="col-span-5 min-h-0 flex flex-col gap-4 overflow-y-auto pr-2">
|
||||
<ProfileManager />
|
||||
<FolderPicker />
|
||||
<RunControl />
|
||||
</section>
|
||||
|
||||
{/* 우측: 진행/결과 */}
|
||||
<section className="col-span-7 flex flex-col gap-4 overflow-hidden">
|
||||
{phase === 'done' ? <ReportView /> : <ProgressView />}
|
||||
{/* 우측: 진행/결과 — FileList만 내부 스크롤 */}
|
||||
<section className="col-span-7 min-h-0 flex flex-col gap-4">
|
||||
<div className="shrink-0">
|
||||
{phase === 'done' ? <ReportView /> : <ProgressView />}
|
||||
</div>
|
||||
<FileList />
|
||||
</section>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user