src/routes/+layout.svelte was 537 LOC of mixed runtime, chrome and overlay concerns. Split into three single-purpose shells under src/lib/shell/, with +layout.svelte reduced to ~28 LOC of pure composition. AppRuntime (no DOM beyond <svelte:window>): - Global hotkey dual backend (evdev / tauri-plugin-global-shortcut) - 120ms hotkey debounce (sacred behaviour §5 #2) - PREFERENCES_CHANGED_EVENT listener (sacred §5 #4) - KI-05 one-shot legacy-theme migration - Sidebar hotkeys: [ toggle, Ctrl+K, Ctrl+, (sacred §5 #10) - Wind-down tray listener - Meeting auto-capture poller - Global frontend error capture - Nudge bus + implementation intentions lifecycle - Font-size CSS var $effect - Window resize → sidebar auto-collapse - Onboarding/first-run check + update check + LLM status warm-up AppChrome (the visual shell): - Titlebar (OS-aware via customChrome helper) - Sidebar (recording-state-aware — sacred §5 #1 stays in Sidebar.svelte verbatim) - Main slot - TaskSidebar conditional rail AppOverlays (mounted-once globals): - ToastViewport - FocusTimer - MorningTriageModal - ResizeHandles (OS-gated) src/lib/utils/customChrome.svelte.ts holds the single source of truth for useCustomChrome, a module-level $state both AppChrome and AppOverlays subscribe to. Each only ever sees one loadOsInfo() call between them. Secondary windows still escape via their own +layout@.svelte; the defensive isSecondaryWindow check in +layout.svelte stays so a direct /float, /viewer, /preview navigation through the root layout also drops the chrome. Phase 6 per-page gate green: npm run check (0/0/5704 files), npm test, npm run test:browser (3/3), npm run test:e2e (16/16). No regressions in the Phase 1 smoke baseline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
37 lines
1.2 KiB
Svelte
37 lines
1.2 KiB
Svelte
<script lang="ts">
|
|
// @ts-nocheck
|
|
// v0.2 Phase 6 — thin composition. The three split-out shells own
|
|
// their respective responsibilities; this file just decides whether
|
|
// to render the chrome (main window) or pass children straight
|
|
// through (secondary windows like /float, /viewer, /preview, which
|
|
// also have their own +layout@.svelte to break out of this layout).
|
|
import "../app.css";
|
|
import { page as sveltePage } from "$app/stores";
|
|
import AppRuntime from "$lib/shell/AppRuntime.svelte";
|
|
import AppChrome from "$lib/shell/AppChrome.svelte";
|
|
import AppOverlays from "$lib/shell/AppOverlays.svelte";
|
|
|
|
let { children } = $props();
|
|
|
|
// Defensive: secondary windows use +layout@.svelte to escape this
|
|
// root layout, but if any /float, /viewer, /preview load ever
|
|
// reaches here we still drop the chrome.
|
|
let isSecondaryWindow = $derived(
|
|
$sveltePage.url.pathname.startsWith("/float") ||
|
|
$sveltePage.url.pathname.startsWith("/viewer") ||
|
|
$sveltePage.url.pathname.startsWith("/preview")
|
|
);
|
|
</script>
|
|
|
|
<AppRuntime />
|
|
|
|
{#if isSecondaryWindow}
|
|
{@render children()}
|
|
{:else}
|
|
<AppChrome>
|
|
{@render children()}
|
|
</AppChrome>
|
|
{/if}
|
|
|
|
<AppOverlays />
|