import React, { useEffect, useState, useCallback } from 'react'; import type { WatchedDir, UndoEntry, AppSettings } from '../../core/types'; const api = (window as any).api; type Tab = 'dirs' | 'undo' | 'general'; export function Settings() { const [tab, setTab] = useState('dirs'); return (

NFD → NFC 설정

{(['dirs', 'undo', 'general'] as Tab[]).map((t) => ( ))}
{tab === 'dirs' && } {tab === 'undo' && } {tab === 'general' && }
); } // ── 디렉토리 탭 ── function DirsTab() { const [dirs, setDirs] = useState([]); const [scanning, setScanning] = useState(null); const [scanResults, setScanResults] = useState>({}); const refresh = useCallback(async () => setDirs(await api.dirs.list()), []); useEffect(() => { refresh(); }, [refresh]); const addDir = async () => { const p = await api.dirs.selectDirectory(); if (!p) return; await api.dirs.add(p); refresh(); }; const removeDir = async (id: string) => { await api.dirs.remove(id); refresh(); }; const toggleEnabled = async (dir: WatchedDir) => { await api.dirs.update(dir.id, { enabled: !dir.enabled }); refresh(); }; const toggleMode = async (dir: WatchedDir) => { await api.dirs.update(dir.id, { mode: dir.mode === 'auto' ? 'manual' : 'auto' }); refresh(); }; const toggleRecursive = async (dir: WatchedDir) => { await api.dirs.update(dir.id, { recursive: !dir.recursive }); refresh(); }; const dryRun = async (id: string) => { setScanning(id); const results = await api.dirs.scan(id); setScanResults((prev) => ({ ...prev, [id]: results })); setScanning(null); }; return (
감시할 디렉토리를 추가하세요
{dirs.length === 0 &&
추가된 디렉토리가 없습니다.
} {dirs.map((dir) => (
{dir.path.split('/').pop()}
{dir.path}
toggleEnabled(dir)} />
모드: {dir.mode === 'auto' ? '자동 변환' : '수동 승인'}
{dir.mode === 'auto' ? 'NFD 감지 즉시 자동 rename' : '감지 후 사용자 확인 필요'}
toggleRecursive(dir)} />
추가 필터 범위
hex 범위 (예: 0300-036F). 한글은 기본 포함.
{scanResults[dir.id] && ( setScanResults((p) => { const n = {...p}; delete n[dir.id]; return n; })} /> )}
))}
); } function RangeEditor({ dir, onRefresh }: { dir: WatchedDir; onRefresh: () => void }) { const [input, setInput] = useState(''); const addRange = async () => { const parts = input.trim().split('-'); if (parts.length !== 2) return; const lo = parseInt(parts[0], 16); const hi = parseInt(parts[1], 16); if (isNaN(lo) || isNaN(hi)) return; await api.dirs.update(dir.id, { customRanges: [...dir.customRanges, [lo, hi]] }); setInput(''); onRefresh(); }; const removeRange = async (idx: number) => { const newRanges = dir.customRanges.filter((_, i) => i !== idx); await api.dirs.update(dir.id, { customRanges: newRanges }); onRefresh(); }; return (
setInput(e.target.value)} style={{ width: 120 }} onKeyDown={(e) => e.key === 'Enter' && addRange()} />
{dir.customRanges.map(([lo, hi], i) => ( removeRange(i)}> {lo.toString(16).toUpperCase()}-{hi.toString(16).toUpperCase()} ))}
); } function ScanPreview({ results, onClose }: { results: unknown[]; onClose: () => void }) { return (
미리보기 ({results.length}개)
{results.length === 0 &&
변환 대상 없음
} {results.map((r: any, i) => (
{r.type === 'directory' ? '📁' : '📄'} {r.path.split('/').pop()}
))}
); } // ── Undo 탭 ── function UndoTab() { const [log, setLog] = useState([]); const refresh = useCallback(async () => { const entries = await api.undo.list(); setLog([...entries].reverse().slice(0, 200)); }, []); useEffect(() => { refresh(); }, [refresh]); const revertEntry = async (entry: UndoEntry) => { await api.undo.revertEntry(entry); refresh(); }; const revertBatch = async () => { await api.undo.revertLastBatch(); refresh(); }; return (
최대 1000개 보관
{log.length === 0 &&
Undo 기록이 없습니다.
} {log.map((entry) => (
↩ {entry.oldPath.split('/').pop()}
→ {entry.newPath.split('/').pop()}
{new Date(entry.ts).toLocaleTimeString('ko-KR')}
{!entry.reverted && ( )}
))}
); } // ── 일반 탭 ── function GeneralTab() { const [settings, setSettings] = useState(null); useEffect(() => { api.settings.get().then(setSettings); }, []); const update = async (patch: Partial) => { await api.settings.update(patch); setSettings((prev) => prev ? { ...prev, ...patch } : prev); }; if (!settings) return
로딩 중…
; return (
동작
새 디렉토리 추가 시 기본으로 적용
update({ notificationsEnabled: e.target.checked })} />
지정 시간마다 변환 건수를 한 번에 알림
{ const v = Math.max(5, Math.min(3600, Number(e.target.value))); update({ notificationIntervalSecs: v }); }} style={{ width: 70 }} />
); }