// src/renderer/pages/DictionaryPage.tsx // 인스트루먼트 미학: MetalCard + PhosphorText + 타이포 토큰 import { useState, useEffect, useCallback } from 'react' import { Box, TextField, Button, IconButton, Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material' import AddIcon from '@mui/icons-material/Add' import DeleteIcon from '@mui/icons-material/Delete' import EditIcon from '@mui/icons-material/Edit' import { MetalCard, PhosphorText } from '../components/ds' import { PageHeader, SearchInput, EmptyStateCard } from '../components/shared' import { d3roPalette, d3roFontMono, d3roTypo } from '../theme' import { useI18n } from '../i18n' import type { DictionaryEntry, DictionaryPage as DictPageData } from '@shared/types' const PAGE_SIZE = 50 export function DictionaryPage(): React.ReactElement { const { t } = useI18n() const [data, setData] = useState(null) const [search, setSearch] = useState('') const [loading, setLoading] = useState(true) const [dialogOpen, setDialogOpen] = useState(false) const [editId, setEditId] = useState(null) const [formWord, setFormWord] = useState('') const [formPronunciation, setFormPronunciation] = useState('') const loadData = useCallback(async () => { setLoading(true) const result = search.trim() ? await window.electronAPI.dictionary.search({ query: search, page: 0, pageSize: PAGE_SIZE }) : await window.electronAPI.dictionary.getAll({ page: 0, pageSize: PAGE_SIZE }) if (result.success) setData(result.data) setLoading(false) }, [search]) useEffect(() => { loadData() }, [loadData]) const openAdd = () => { setEditId(null) setFormWord('') setFormPronunciation('') setDialogOpen(true) } const openEdit = (entry: DictionaryEntry) => { setEditId(entry.id) setFormWord(entry.word) setFormPronunciation(entry.pronunciation ?? '') setDialogOpen(true) } const handleSave = async () => { if (!formWord.trim()) return if (editId) { await window.electronAPI.dictionary.update({ id: editId, word: formWord.trim(), pronunciation: formPronunciation.trim() || undefined, }) } else { await window.electronAPI.dictionary.add({ word: formWord.trim(), pronunciation: formPronunciation.trim() || undefined, }) } setDialogOpen(false) loadData() } return ( } onClick={openAdd} size="small"> {t('dictionary.add').toUpperCase()} } /> {loading ? ( {t('common.loading').toUpperCase()} ) : !data || data.entries.length === 0 ? ( ) : ( {data.entries.map((entry: DictionaryEntry) => ( {entry.word} {entry.pronunciation && ( [{entry.pronunciation}] )} {entry.category.toUpperCase()} · {t('dictionary.used', { count: entry.usageCount })} openEdit(entry)} sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}> { window.electronAPI.dictionary.delete({ id: entry.id }); loadData() }} sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.red } }}> ))} )} setDialogOpen(false)} maxWidth="xs" fullWidth> {editId ? t('dictionary.editTitle') : t('dictionary.addTitle')} setFormWord(e.target.value)} fullWidth autoFocus sx={{ mt: 1 }} /> setFormPronunciation(e.target.value)} fullWidth sx={{ mt: 2 }} /> ) }