From f311fdc47f355fff35a88541160b3777f6e16fea Mon Sep 17 00:00:00 2001 From: Jake Date: Fri, 15 May 2026 18:03:45 +0100 Subject: [PATCH] v0.3 Phase 5d: Files page migrated to quietware skeleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same gated-layout pattern as Phase 5c. v0.2 surface untouched; quietware path renders FilesPage via LumotiaPageSkeleton with the four zones the page actually needs: Capture header "File transcription" + "Transcribe audio files locally." Primary surface drop zone / progress / transcript states Action dock Browse files / Copy / Export Mono footer formats · model · Local only State + handlers preserved. fileTranscript, segments, isDragOver, progress, progressText, fileName, error, transcribing, showExportMenu — all unchanged. handleBrowse, transcribeFiles, copyAll, handleExport — all unchanged. Tauri drag-drop listeners stay live on onMount; new MutationObserver for data-design joins them. Primary surface state machine. transcribing Upload icon, "Transcribing" label, mono file name, LumotiaProgress (tone="transcribing", so the blue Phase 4k progress fill applies). Progress text below. empty Dashed drop zone using --button-primary-bg accent when isDragOver, neutral subtle border otherwise. Empty-state typography mirrors Dictation: Young Serif italic "Drop an audio file.", Work Sans support, format list in JetBrains Mono. has transcript Full-bleed editable textarea. Action dock. Browse files (primary when no transcript; secondary when transcript exists — at that point Export becomes the primary action). Copy (tertiary, disabled until transcript exists). Export (LumotiaMenu trigger — primary when transcript exists, secondary otherwise). Disabled controls render neutral per the Phase 4k token contract. Mono footer. Single line: "MP3 · WAV · M4A · MP4 · FLAC · OGG · {model} · Local only" Capture script updated. scripts/capture-quietware-screenshots.mjs now navigates to the Files page via the sidebar nav button after capturing the root route, and screenshots both quietware modes. Verified. - npm run check: 0 errors, 0 warnings across 5707 files. - Headless captures confirm the new layout in both modes: drop zone + action dock + mono footer with the right Phase 4j colour grammar applied. Browse Files blue primary, disabled actions neutral, dashed border picks up --button-primary-bg when isDragOver. Phase 5e (Tasks) and 5f (History) follow same pattern. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/capture-quietware-screenshots.mjs | 20 ++++ src/lib/pages/FilesPage.svelte | 135 +++++++++++++++++++++- 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/scripts/capture-quietware-screenshots.mjs b/scripts/capture-quietware-screenshots.mjs index a2c378c..535ef72 100644 --- a/scripts/capture-quietware-screenshots.mjs +++ b/scripts/capture-quietware-screenshots.mjs @@ -83,5 +83,25 @@ try { console.error(`root route skipped: ${e.message}`); } +// Files page — SPA navigation via the sidebar item. +try { + console.log("\n=== files page (best effort) ==="); + await page.evaluate(() => { + const items = Array.from(document.querySelectorAll('button, a, [role="button"], li')); + const target = items.find(el => (el.textContent || "").trim().toLowerCase() === "files"); + if (target) target.click(); + }); + await page.waitForTimeout(1500); + for (const mode of MODES.slice(1, 3)) { + await setMode(mode); + await page.waitForTimeout(400); + const file = `${OUT}/files__${mode.id}.png`; + await page.screenshot({ path: file, fullPage: false }); + console.log(` files ${mode.id}`); + } +} catch (e) { + console.error(`files page skipped: ${e.message}`); +} + await browser.close(); console.log(`\nWrote screenshots to ${OUT}/`); diff --git a/src/lib/pages/FilesPage.svelte b/src/lib/pages/FilesPage.svelte index abcc61a..75aef89 100644 --- a/src/lib/pages/FilesPage.svelte +++ b/src/lib/pages/FilesPage.svelte @@ -11,6 +11,8 @@ import LumotiaNotice from "$lib/ui/LumotiaNotice.svelte"; import LumotiaProgress from "$lib/ui/LumotiaProgress.svelte"; import LumotiaMenu from "$lib/ui/LumotiaMenu.svelte"; + // v0.3 Phase 5d — quietware layout for Files page. + import LumotiaPageSkeleton from "$lib/ui/LumotiaPageSkeleton.svelte"; import { exportTranscript } from "$lib/utils/export.js"; import { hasTauriRuntime } from "$lib/utils/runtime"; import { toasts } from "$lib/stores/toasts.svelte.js"; @@ -30,7 +32,25 @@ let unlistenEnter = null; let unlistenLeave = null; + // v0.3 Phase 5d — quietware layout switch. MutationObserver on + // mirrors the SettingsPage / DictationPage + // pattern. Without quietware the existing v0.2 layout renders. + let isQuietware = $state(false); + let quietwareObserver: MutationObserver | null = null; + onMount(async () => { + if (typeof document !== "undefined") { + const sync = () => { + isQuietware = document.documentElement.dataset.design === "quietware"; + }; + sync(); + quietwareObserver = new MutationObserver(sync); + quietwareObserver.observe(document.documentElement, { + attributes: true, + attributeFilter: ["data-design"], + }); + } + unlistenDrop = await listen("tauri://drag-drop", async (event) => { isDragOver = false; if (event.payload?.paths?.length > 0) { @@ -45,6 +65,8 @@ if (unlistenDrop) unlistenDrop(); if (unlistenEnter) unlistenEnter(); if (unlistenLeave) unlistenLeave(); + quietwareObserver?.disconnect(); + quietwareObserver = null; }); async function handleBrowse() { @@ -175,7 +197,117 @@ } -
+
+ {#if isQuietware} + + + {#snippet header()} +
+

File transcription

+

Transcribe audio files locally.

+
+ {/snippet} + + {#snippet primary()} +
+ {#if error} +
+ error = ""}> + {error} + +
+ {/if} + +
+ {#if transcribing} + +
+
+ {:else if !fileTranscript} + +
+
+ {:else} + + + {/if} +
+ + +
+ Browse files + Copy + handleExport("txt") }, + { value: "md", label: "Markdown", onSelect: () => handleExport("md") }, + { value: "csv", label: "CSV", onSelect: () => handleExport("csv") }, + { value: "html",label: "HTML", onSelect: () => handleExport("html") }, + { value: "srt", label: "SRT subtitles", onSelect: () => handleExport("srt") }, + { value: "vtt", label: "WebVTT", onSelect: () => handleExport("vtt") }, + ]} + > + {#snippet trigger()} + Export + {/snippet} + +
+
+ {/snippet} + + {#snippet metadata()} +
+ MP3 · WAV · M4A · MP4 · FLAC · OGG · {settings.modelSize} · Local only +
+ {/snippet} +
+ {:else}

File Transcription

@@ -274,4 +406,5 @@ {/snippet}
+ {/if}