feat(1.0.14): тематики searchable, фикс лага confirm-диалога

- Confirm dialog: предзагрузка WebContentsView при старте приложения.
  Раньше каждое нажатие "Закрыть" создавало новый view с холодной
  загрузкой HTML+React → ~2с лаг и дубликаты от повторных кликов.
  Теперь view кэшируется, текст обновляется через IPC, повторные
  клики игнорируются пока диалог открыт.
- Темы: 14 → 71 (Война, Холодная война, Вьетнам, Призраки, Драконы,
  Шахматы, Самолёты, Поезда, Сёрфинг, Япония, ...). Все ID
  провалидированы probe-скриптом (≥50 фильмов на тематику).
- Chip-row заменён на SearchableSelect с поиском по подстроке —
  длинный список не помещается в чипы, а dropdown с фильтром
  гораздо удобнее. Заодно ушёл фиолетовый цвет чипа, плохо
  сочетавшийся с темой сайта.
This commit is contained in:
2026-05-17 11:29:39 +03:00
parent 8684eb7b67
commit 747b0f4c18
5 changed files with 265 additions and 45 deletions

View File

@@ -4,22 +4,42 @@ import '../styles/dialogs.css'
declare global {
interface Window {
electron?: { handleAction: (action: string) => void }
electron?: {
handleAction: (action: string) => void
on: (channel: string, fn: (...args: any[]) => void) => () => void
}
__dialogData?: { text?: string }
}
}
const ConfirmDialog = () => {
// Cached view re-uses этот компонент: текст и видимость приходят по IPC.
// initialText из URL — backwards compat (если кто-то откроет dialog-confirm.html напрямую).
const initialText = new URLSearchParams(window.location.search).get('text') || ''
const [text, setText] = useState(initialText)
const [visible, setVisible] = useState(false)
const params = new URLSearchParams(window.location.search)
const text = params.get('text') || window.__dialogData?.text || ''
useEffect(() => {
requestAnimationFrame(() => requestAnimationFrame(() => setVisible(true)))
if (initialText) {
requestAnimationFrame(() => requestAnimationFrame(() => setVisible(true)))
}
return window.electron?.on('dialog-confirm-set', (data: { text?: string; visible?: boolean }) => {
if (typeof data.text === 'string') setText(data.text)
if (typeof data.visible === 'boolean') {
if (data.visible) requestAnimationFrame(() => requestAnimationFrame(() => setVisible(true)))
else setVisible(false)
}
})
}, [])
useEffect(() => {
if (visible) document.body.classList.add('visible')
if (visible) {
document.body.classList.remove('hiding')
document.body.classList.add('visible')
} else {
document.body.classList.remove('visible')
document.body.classList.add('hiding')
}
}, [visible])
return (