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:
@@ -0,0 +1,50 @@
|
||||
import { app } from 'electron'
|
||||
import { readFile, writeFile, mkdir } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import type { Settings } from '@shared/types'
|
||||
import { SETTINGS_FILE } from '@shared/constants'
|
||||
import { DEFAULT_LANG } from '@shared/i18n'
|
||||
|
||||
const DEFAULTS: Settings = {
|
||||
language: DEFAULT_LANG, // 기본 한국어
|
||||
theme: 'dark', // 기본 다크모드
|
||||
onboarded: false
|
||||
}
|
||||
|
||||
/** 앱 설정(언어/테마/온보딩) 영속화. userData/settings.json */
|
||||
class SettingsStore {
|
||||
private settings: Settings = { ...DEFAULTS }
|
||||
private loaded = false
|
||||
|
||||
private filePath(): string {
|
||||
return join(app.getPath('userData'), SETTINGS_FILE)
|
||||
}
|
||||
|
||||
async load(): Promise<Settings> {
|
||||
if (this.loaded) return this.settings
|
||||
try {
|
||||
const raw = await readFile(this.filePath(), 'utf-8')
|
||||
const parsed = JSON.parse(raw) as Partial<Settings>
|
||||
this.settings = { ...DEFAULTS, ...parsed }
|
||||
} catch {
|
||||
this.settings = { ...DEFAULTS }
|
||||
}
|
||||
this.loaded = true
|
||||
return this.settings
|
||||
}
|
||||
|
||||
/** 동기 접근(load 이후). 메뉴 빌드 등에서 사용 */
|
||||
current(): Settings {
|
||||
return this.settings
|
||||
}
|
||||
|
||||
async set(patch: Partial<Settings>): Promise<Settings> {
|
||||
await this.load()
|
||||
this.settings = { ...this.settings, ...patch }
|
||||
await mkdir(app.getPath('userData'), { recursive: true })
|
||||
await writeFile(this.filePath(), JSON.stringify(this.settings, null, 2), 'utf-8')
|
||||
return this.settings
|
||||
}
|
||||
}
|
||||
|
||||
export const settingsStore = new SettingsStore()
|
||||
Reference in New Issue
Block a user