Five-slice navigable map of the entire codebase under
docs/architecture-map/. Each slice is a self-contained
breadcrumbed sub-tree:
01-frontend (16) Svelte/SvelteKit UI
02-tauri-runtime (26) src-tauri commands + lifecycle
03-audio-transcription (16) audio + transcription crates
04-llm-formatting-mcp (19) llm, ai-formatting, mcp, cloud
05-core-storage-hotkey-build core, storage, hotkey, workspace,
(26) CI, dev glue
Plus master README.md and data-flow-end-to-end.md tracing
audio bytes from microphone to FTS5 search to MCP read.
Generated by 5 parallel subagents on 2026/05/09 against
HEAD 3c47000. Each page has YAML frontmatter, file:line code
refs, sibling cross-links, plain-English summaries.
Aggregated debt surfaced (full lists in master README):
RB-08 macOS power assertion, schema head drift v14 vs v15,
VAD blocked on ort version conflict, streaming primitives
not wired into live.rs, no prompt versioning, MCP has no
auth, cloud-providers in-memory keystore, SettingsPage
2 484 LOC, commands/live.rs 1 737 LOC, dual theme system,
brand rename to Lumenote pending across the codebase.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
120 lines
9.6 KiB
Markdown
120 lines
9.6 KiB
Markdown
---
|
|
name: Windows and SvelteKit routes
|
|
type: architecture-map-page
|
|
slice: 01-frontend
|
|
last_verified: 2026/05/09
|
|
---
|
|
|
|
# Windows and routes
|
|
|
|
> **Where you are:** [Architecture map](../README.md) → [Frontend](README.md) → Windows and routes
|
|
|
|
**Plain English summary.** Magnotia is a single SvelteKit build that runs as multiple desktop windows. The Rust side opens four webviews (main, tasks float, transcript viewer, transcription preview) and points each one at a different SvelteKit route. The frontend uses SvelteKit's `+layout@.svelte` "break" trick so secondary windows skip the main shell (sidebar, titlebar, toast viewport) and render a focused, single purpose UI.
|
|
|
|
## At a glance
|
|
|
|
- **Path:** `src/routes/`
|
|
- **LOC:** 2 740 across the route tree.
|
|
- **Key files:**
|
|
- `src/routes/+layout.js:5`. Disables SSR. Adapter is `adapter-static` with `index.html` fallback (`svelte.config.js:6`). The whole tree is SPA only.
|
|
- `src/routes/+layout.svelte`. The shell. Sidebar, custom titlebar (non Linux only), toast viewport, focus timer overlay, morning triage modal, resize handles, global hotkey wiring, OS detection, profile load, first run gate, error capture.
|
|
- `src/routes/+page.svelte`. The main window's page switch (`page.current` → 7 page modules).
|
|
- `src/routes/float/+layout@.svelte`. "Break" layout for the tasks float window.
|
|
- `src/routes/float/+page.svelte`. Tasks float window UI.
|
|
- `src/routes/viewer/+layout@.svelte`. Break layout for the transcript editor window.
|
|
- `src/routes/viewer/+page.svelte`. Transcript editor with audio playback.
|
|
- `src/routes/preview/+layout@.svelte`. Break layout for the live transcription preview overlay.
|
|
- `src/routes/preview/+page.svelte`. Preview state machine: listening → live → cleanup → final.
|
|
- **Imports:**
|
|
- Internal: every store, plus shell components (`Sidebar`, `TaskSidebar`, `Titlebar`, `ToastViewport`, `ResizeHandles`, `FocusTimer`, `MorningTriageModal`).
|
|
- External: `@tauri-apps/api/core` (invoke, Channel, convertFileSrc), `@tauri-apps/api/event` (listen, emit), `@tauri-apps/api/window` (getCurrentWindow), `@tauri-apps/plugin-global-shortcut`, `@tauri-apps/plugin-dialog`, `lucide-svelte`.
|
|
- **Used by:** Tauri (slice 02). Window labels are `main`, `tasks-float`, `transcript-viewer`, `transcription-preview`. Each is created with the matching route URL.
|
|
|
|
## What's in here
|
|
|
|
### `src/routes/+layout.js` (5 LOC)
|
|
|
|
Single line: `export const ssr = false;`. Tauri has no Node server, so SvelteKit must run as a SPA.
|
|
|
|
### `src/routes/+layout.svelte` (493 LOC)
|
|
|
|
The shell. Mounts on every window (the secondary windows then render only `{@render children()}` and suppress the chrome).
|
|
|
|
Responsibilities:
|
|
- Initialise svelte-i18n (`initI18n()` is idempotent across windows, `+layout.svelte:38`).
|
|
- Detect Tauri runtime (`hasTauriRuntime`) and OS (`loadOsInfo`). Linux uses native KWin/Mutter decorations; macOS and Windows render the custom `Titlebar` plus invisible `ResizeHandles`. Default `useCustomChrome = false` to avoid a flash on Linux (`+layout.svelte:49`).
|
|
- Hotkey backend selection. On Wayland, attempt the evdev backend (`check_hotkey_access`). Otherwise fall back to `tauri-plugin-global-shortcut`. Falls back to "unavailable" if neither path works (`+layout.svelte:76-102`).
|
|
- Hotkey registration. Only the `main` window owns the global shortcut. The function debounces evdev autorepeat at 120 ms (Handy issue #1143 referenced in comments, `+layout.svelte:171-186`).
|
|
- Cross window listeners: `magnotia:hotkey-pressed` (evdev path), `magnotia:open-wind-down` (tray menu), `magnotia:preferences-changed` (sync prefs across windows). Apply external preferences if the source label differs from our own.
|
|
- Theme migration `$effect`. Reads `settings.theme` (legacy "Light" / "Dark" / "System") and writes `preferences.theme` ("light" / "dark" / "system"). See README debt note 2.
|
|
- Font size CSS variable `--font-size-transcript` set on `<body>` from `settings.fontSize`.
|
|
- Global error capture. `window.onerror` and `unhandledrejection` forward to `log_frontend_error` Rust command. Best effort, swallow throws.
|
|
- First run check on mount. If `list_models` and `list_parakeet_models` both return empty arrays, switch `page.current` to `"first-run"`.
|
|
- Background update check via `check_for_update`. Toast on result.
|
|
- Pre warm default model on mount if `settings.prewarmModelOnStartup` (calls `prewarm_default_model_cmd`).
|
|
- Meeting auto capture poller (`$effect`). When `settings.meetingAutoCapture` is true, polls `detect_meeting_processes` every 15 s with the configured patterns (default `["zoom", "teams"]`). Edge triggered (toast only on first match per session). Tear down on effect re run.
|
|
- Sidebar collapse heuristic. `[` toggles, narrow viewport collapses automatically.
|
|
- Render branches: `isSecondaryWindow` (URL starts with `/float` or `/viewer`) renders only children. Otherwise: optional Titlebar, sidebar (hidden on first run), main slot, optional task sidebar (when `page.taskSidebarOpen`).
|
|
- Always rendered alongside: `<ToastViewport />`, `<FocusTimer />`, `<MorningTriageModal />`, `<ResizeHandles />` (custom chrome only).
|
|
|
|
### `src/routes/+page.svelte` (33 LOC)
|
|
|
|
Pure dispatcher. Switches the seven page modules from `page.current`:
|
|
- `first-run` → `FirstRunPage`
|
|
- `dictation` → `DictationPage`
|
|
- `files` → `FilesPage`
|
|
- `tasks` → `TasksPage`
|
|
- `history` → `HistoryPage`
|
|
- `settings` → `SettingsPage`
|
|
- `shutdown` → `ShutdownRitualPage`
|
|
|
|
Also redirects the legacy `page.current === "profiles"` to `"settings"` via `$effect` (debt note 5).
|
|
|
|
### `src/routes/float/+layout@.svelte` (99 LOC)
|
|
|
|
The `@.svelte` suffix tells SvelteKit to skip parent layouts. Reimports `app.css`, mounts `Titlebar` (non Linux) and `FocusTimer`, applies the same theme migration `$effect`, listens on the browser `storage` event (not Tauri events) to sync `settings` from main window writes, and handles the `task-window-focus` Tauri event to glow and auto focus the quick add input.
|
|
|
|
### `src/routes/float/+page.svelte` (481 LOC)
|
|
|
|
Tasks float window. Self contained quick add, list filter, sort menu, completed toggle, list management (rename, delete, reorder, move to profile), drag and drop reordering. Reads tasks straight from the `page.svelte.ts` store helpers. No `invoke()` calls of its own; mutations go via `addTask`, `completeTask`, etc, which then call Rust.
|
|
|
|
### `src/routes/viewer/+layout@.svelte` (77 LOC)
|
|
|
|
Same break layout pattern. Mounts `Titlebar`, `ToastViewport`, applies preferences sync via `magnotia:preferences-changed`, applies theme.
|
|
|
|
### `src/routes/viewer/+page.svelte` (606 LOC)
|
|
|
|
Transcript editor. Hydrates from a transcript ID handed off via `localStorage` (`magnotia:viewer-handoff` style key, see file). Fetches the full row from SQLite via `get_transcript`. Renders an `<audio>` element using `convertFileSrc()` to map the saved audio path to a webview URL. Provides per segment editing, debounced autosave through `saveTranscriptMeta`, virtual scrolling via `VirtualSegmentList`, playback speed control (`PLAYBACK_SPEEDS`), starring and tagging.
|
|
|
|
### `src/routes/preview/+layout@.svelte` (68 LOC)
|
|
|
|
Mounts only what the overlay needs: theme, preferences sync. No sidebar, no titlebar, no toast viewport.
|
|
|
|
### `src/routes/preview/+page.svelte` (274 LOC)
|
|
|
|
Live transcription overlay. Listens for `preview-listening`, `preview-cleanup`, `preview-hide` (and reads partial text via the same `Channel` pattern as Dictation, in some flows). State machine: `listening → live → cleanup → final → auto hide`. Provides a copy button (uses `navigator.clipboard.writeText` first, falls back to `copy_to_clipboard` invoke) and a revert to raw button. Auto hide timer constants live at the top of the file.
|
|
|
|
## Data flow
|
|
|
|
- Window creation: Rust opens four webviews and routes them to `/`, `/float`, `/viewer`, `/preview`. The same JS bundle loads in each.
|
|
- Cross window state:
|
|
- `localStorage` carries `magnotia_settings` and the viewer handoff payload. Float window listens on the browser `storage` event to mirror settings.
|
|
- Tauri events carry preferences (`magnotia:preferences-changed`), tray driven navigation (`magnotia:open-wind-down`), and float window focus (`task-window-focus`).
|
|
- Hotkey: only the main window registers, but every window's layout includes the migration `$effect`. The label guard at `+layout.svelte:115-121` prevents secondary windows from re registering.
|
|
- First run gating: only the main window evaluates and sets `page.current = "first-run"`. The float/viewer/preview windows skip the shell altogether.
|
|
|
|
## Watch outs
|
|
|
|
- The `useCustomChrome` flash is mitigated by defaulting to `false` on Linux. If you ever flip the default, expect a one frame flash of custom chrome before `loadOsInfo()` resolves.
|
|
- The break layouts duplicate the theme migration `$effect`. Touch one, touch all. Same for `applyExternalPreferences` listeners.
|
|
- `transcription-preview` is a borderless overlay with `WindowTypeHint = Utility`. Layout assumptions about chrome height do not apply.
|
|
- `+layout.svelte` calls `applyExternalPreferences` only after a payload `source` check. If you ever add a fifth window, its label must be propagated correctly or the window will echo its own preference writes.
|
|
- Drag drop on `FilesPage.svelte` listens on `tauri://drag-drop` events, which require the window to declare drag drop in `tauri.conf.json`. Slice 02 owns that surface.
|
|
|
|
## See also
|
|
|
|
- [Pages overview](pages-overview.md). What `page.current` ends up rendering.
|
|
- [Frontend ↔ Tauri bridge](frontend-tauri-bridge.md). Every command and event referenced above.
|
|
- [App shell and styling](app-shell-and-styling.md). The CSS plumbing that the shell relies on.
|
|
- [../02-tauri-runtime/README.md](../02-tauri-runtime/README.md). Window creation, tray, and the matching event surface.
|