()
| 233 | } |
| 234 | |
| 235 | export function QuickCaptureApp(): JSX.Element { |
| 236 | const prefs = useMemo(() => loadPrefs(), []) |
| 237 | // `docTitle` is the live title derived from the editor's first line — |
| 238 | // pure display, the body is the single place to type. '' means the |
| 239 | // buffer is empty / has no usable first line yet. |
| 240 | const [docTitle, setDocTitle] = useState('') |
| 241 | const [mode, setMode] = useState<EditingMode>(NEW_MODE) |
| 242 | const [charCount, setCharCount] = useState(0) |
| 243 | const [submitting, setSubmitting] = useState(false) |
| 244 | const [error, setError] = useState<string | null>(null) |
| 245 | const [notes, setNotes] = useState<NoteMeta[]>([]) |
| 246 | const [overlay, setOverlay] = useState<'none' | 'search' | 'command'>('none') |
| 247 | const editorRef = useRef<EditorView | null>(null) |
| 248 | |
| 249 | // Set a different title for the quick capture window. |
| 250 | useEffect(() => { |
| 251 | document.title = 'ZenNotes Quick Capture' |
| 252 | }, []) |
| 253 | |
| 254 | // Apply theme + font CSS vars before paint. |
| 255 | useEffect(() => { |
| 256 | applyTheme(prefs) |
| 257 | const mql = window.matchMedia('(prefers-color-scheme: dark)') |
| 258 | if (prefs.themeMode === 'auto') { |
| 259 | const onChange = (): void => applyTheme(prefs) |
| 260 | mql.addEventListener('change', onChange) |
| 261 | return () => mql.removeEventListener('change', onChange) |
| 262 | } |
| 263 | return undefined |
| 264 | }, [prefs]) |
| 265 | |
| 266 | // Initial notes fetch + live refresh from the vault watcher so the |
| 267 | // picker stays current as files are created or renamed elsewhere. |
| 268 | useEffect(() => { |
| 269 | let alive = true |
| 270 | const refresh = (): void => { |
| 271 | void window.zen.listNotes().then((all) => { |
| 272 | if (!alive) return |
| 273 | setNotes(all.filter((n) => n.folder !== 'trash')) |
| 274 | }) |
| 275 | } |
| 276 | refresh() |
| 277 | const off = window.zen.onVaultChange(() => refresh()) |
| 278 | return () => { |
| 279 | alive = false |
| 280 | off() |
| 281 | } |
| 282 | }, []) |
| 283 | |
| 284 | // When the OS window regains focus, drop the cursor back into the |
| 285 | // editor. The renderer process stays alive between hide/show, so any |
| 286 | // draft or open existing note is still here. |
| 287 | useEffect(() => { |
| 288 | const onFocus = (): void => { |
| 289 | if (overlay !== 'none') return |
| 290 | requestAnimationFrame(() => editorRef.current?.focus()) |
| 291 | } |
| 292 | window.addEventListener('focus', onFocus) |
nothing calls this directly
no test coverage detected