v0.3 Phase 5d: Files page migrated to quietware skeleton
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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}/`);
|
||||
|
||||
@@ -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
|
||||
// <html data-design> 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 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col h-full overflow-y-auto animate-fade-in">
|
||||
<div class="flex flex-col h-full {isQuietware ? '' : 'overflow-y-auto'} animate-fade-in">
|
||||
{#if isQuietware}
|
||||
<!-- =================================================================
|
||||
v0.3 Phase 5d — quietware Files layout. Uses LumotiaPageSkeleton
|
||||
with the same five-zone language as Dictation:
|
||||
|
||||
Capture header title + description
|
||||
Slim notice nested inside the primary surface for errors
|
||||
Primary surface drop zone / progress / transcript states
|
||||
Action dock Browse Files / Copy / Export
|
||||
Mono footer formats · model · Local only
|
||||
|
||||
All existing state and handlers preserved.
|
||||
================================================================= -->
|
||||
<LumotiaPageSkeleton>
|
||||
{#snippet header()}
|
||||
<div>
|
||||
<h1 class="text-[18px] font-medium text-text leading-tight">File transcription</h1>
|
||||
<p class="text-[12px] text-text-secondary mt-0.5">Transcribe audio files locally.</p>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet primary()}
|
||||
<div class="h-full flex flex-col">
|
||||
{#if error}
|
||||
<div class="px-6 pt-4">
|
||||
<LumotiaNotice tone="danger" slim dismissible onDismiss={() => error = ""}>
|
||||
{error}
|
||||
</LumotiaNotice>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex-1 flex flex-col px-8 py-6 min-h-0 overflow-hidden">
|
||||
{#if transcribing}
|
||||
<!-- Progress state -->
|
||||
<div class="flex-1 flex flex-col items-center justify-center gap-4 px-12 text-text-tertiary">
|
||||
<Upload size={48} class="opacity-50" aria-hidden="true" />
|
||||
<p class="text-[18px] font-medium text-text">Transcribing</p>
|
||||
{#if fileName}
|
||||
<p class="text-[13px] text-text-secondary text-center font-mono break-all">{fileName}</p>
|
||||
{/if}
|
||||
<div class="w-full max-w-md">
|
||||
<LumotiaProgress value={progress} max={100} tone="transcribing" ariaLabel="Transcription progress" showValue />
|
||||
{#if progressText}
|
||||
<p class="text-[12px] text-text-tertiary mt-2 text-center">{progressText}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else if !fileTranscript}
|
||||
<!-- Empty state: drop zone -->
|
||||
<div
|
||||
class="flex-1 flex flex-col items-center justify-center text-center gap-3 rounded-xl border-2 border-dashed transition-colors duration-150
|
||||
{isDragOver
|
||||
? 'border-[var(--button-primary-bg)] bg-[var(--color-info-bg)]'
|
||||
: 'border-border-subtle text-text-tertiary'}"
|
||||
role="region"
|
||||
aria-label="Audio file drop zone"
|
||||
>
|
||||
<Upload size={56} class="opacity-50" aria-hidden="true" />
|
||||
<p class="font-display italic text-[28px] text-text">Drop an audio file.</p>
|
||||
<p class="text-[14px] text-text-secondary">Or use Browse files in the action bar.</p>
|
||||
<p class="text-[12px] text-text-tertiary mt-2 font-mono">MP3 · WAV · M4A · MP4 · FLAC · OGG</p>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Transcript display -->
|
||||
<textarea
|
||||
class="font-transcript flex-1 w-full bg-transparent text-text resize-none placeholder:text-text-tertiary leading-relaxed"
|
||||
placeholder="Transcribed text will appear here..."
|
||||
bind:value={fileTranscript}
|
||||
data-no-transition
|
||||
aria-label="File transcript"
|
||||
aria-live="polite"
|
||||
></textarea>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Action dock attached to the surface. -->
|
||||
<div class="flex items-center gap-2 justify-end px-6 py-3 border-t border-border-subtle bg-bg-elevated/40">
|
||||
<LumotiaButton
|
||||
variant={fileTranscript ? "secondary" : "primary"}
|
||||
size="sm"
|
||||
disabled={transcribing}
|
||||
onclick={handleBrowse}
|
||||
>Browse files</LumotiaButton>
|
||||
<LumotiaButton variant="tertiary" size="sm" onclick={copyAll} disabled={!fileTranscript}>Copy</LumotiaButton>
|
||||
<LumotiaMenu
|
||||
align="start"
|
||||
items={[
|
||||
{ value: "txt", label: "Plain text", onSelect: () => 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()}
|
||||
<LumotiaButton variant={fileTranscript ? "primary" : "secondary"} size="sm" disabled={!fileTranscript}>Export</LumotiaButton>
|
||||
{/snippet}
|
||||
</LumotiaMenu>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet metadata()}
|
||||
<div class="flex items-center justify-end">
|
||||
MP3 · WAV · M4A · MP4 · FLAC · OGG · {settings.modelSize} · Local only
|
||||
</div>
|
||||
{/snippet}
|
||||
</LumotiaPageSkeleton>
|
||||
{:else}
|
||||
<!-- Title -->
|
||||
<h2 class="font-display text-[26px] italic text-text px-7 pt-6 pb-4">File Transcription</h2>
|
||||
|
||||
@@ -274,4 +406,5 @@
|
||||
{/snippet}
|
||||
</LumotiaMenu>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user