v0.2 Phase 7.2: FilesPage — wrapper sweep

Migrated FilesPage chrome to the new grammar; the drop-zone affordance
and transcript textarea (the page's identity surfaces) stay verbatim.

  - Card import → LumotiaCard
  - EmptyState import → LumotiaEmptyState
  - "Browse Files" filled button → LumotiaButton variant=primary size=lg
  - Bottom "Copy" / "Export" toolbar → LumotiaButton variant=tertiary
  - Custom export dropdown → LumotiaMenu (Bits UI DropdownMenu)
  - Inline danger error → LumotiaNotice tone=danger
  - Custom progress bar → LumotiaProgress

Banks the LumotiaField + LumotiaNotice patterns the plan called out;
Field stays on the textarea (transcript surface is intentionally
naked inside the card per brand spec).

Per-page gate: npm run check (0/0/5704 files). Vitest / browser-mode /
e2e baselines unchanged (no behaviour change to the smoke surface).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 08:54:24 +01:00
parent 3614c94885
commit d812410039

View File

@@ -5,8 +5,12 @@
import { listen } from "@tauri-apps/api/event";
import { settings, addToHistory } from "$lib/stores/page.svelte.js";
import { profilesStore } from "$lib/stores/profiles.svelte.ts";
import Card from "$lib/components/Card.svelte";
import EmptyState from "$lib/components/EmptyState.svelte";
import LumotiaCard from "$lib/ui/LumotiaCard.svelte";
import LumotiaEmptyState from "$lib/ui/LumotiaEmptyState.svelte";
import LumotiaButton from "$lib/ui/LumotiaButton.svelte";
import LumotiaNotice from "$lib/ui/LumotiaNotice.svelte";
import LumotiaProgress from "$lib/ui/LumotiaProgress.svelte";
import LumotiaMenu from "$lib/ui/LumotiaMenu.svelte";
import { exportTranscript } from "$lib/utils/export.js";
import { hasTauriRuntime } from "$lib/utils/runtime";
import { toasts } from "$lib/stores/toasts.svelte.js";
@@ -190,7 +194,7 @@
aria-label="Audio file drop zone"
>
{#if !fileTranscript && !transcribing}
<EmptyState
<LumotiaEmptyState
icon={Upload}
message="Drop an audio file or click to browse"
/>
@@ -210,14 +214,9 @@
<!-- Browse buttons + progress -->
<div class="flex items-center gap-2 px-7 pb-3">
<button
class="btn-lg rounded-lg font-medium btn-filled-text bg-accent hover:bg-accent-hover
shadow-[var(--shadow-accent-raised)]"
onclick={handleBrowse}
disabled={transcribing}
>
<LumotiaButton variant="primary" size="lg" disabled={transcribing} onclick={handleBrowse}>
Browse Files
</button>
</LumotiaButton>
<div class="flex-1"></div>
{#if progressText}
<span class="text-[12px] text-text-secondary animate-fade-in">{progressText}</span>
@@ -227,21 +226,14 @@
<!-- Error -->
{#if error}
<div class="px-7 pb-2 animate-fade-in">
<div class="px-4 py-2 rounded-lg bg-danger/10 border border-danger/20 text-[12px] text-danger">
{error}
</div>
<LumotiaNotice tone="danger">{error}</LumotiaNotice>
</div>
{/if}
<!-- Progress bar -->
{#if progress > 0}
<div class="px-7 pb-3 animate-fade-in">
<div class="h-[3px] bg-bg-elevated rounded-full overflow-hidden">
<div
class="h-full bg-accent rounded-full shadow-[var(--shadow-accent-glow)]"
style="width: {progress}%; transition-duration: var(--duration-ui)"
></div>
</div>
<LumotiaProgress value={progress} max={100} ariaLabel="Transcription progress" />
{#if fileName}
<p class="text-[12px] text-text-secondary mt-1.5">{fileName}</p>
{/if}
@@ -250,7 +242,7 @@
<!-- File transcript -->
<div class="flex-1 px-7 pb-3 min-h-0">
<Card classes="h-full flex flex-col">
<LumotiaCard classes="h-full flex flex-col">
<textarea
class="font-transcript flex-1 w-full bg-transparent text-text p-6
resize-none placeholder:text-text-tertiary"
@@ -260,27 +252,26 @@
aria-label="File transcript"
aria-live="polite"
></textarea>
</Card>
</LumotiaCard>
</div>
<!-- Bottom actions -->
<div class="flex gap-0.5 px-7 pb-4">
<button class="btn-md rounded-lg text-text-secondary hover:bg-hover hover:text-text" onclick={copyAll}>Copy</button>
<div class="relative">
<button
class="btn-md rounded-lg text-text-secondary hover:bg-hover hover:text-text"
onclick={() => showExportMenu = !showExportMenu}
>Export</button>
{#if showExportMenu}
<div class="absolute left-0 bottom-full mb-1 bg-bg-card border border-border rounded-lg shadow-lg py-1 z-10 animate-fade-in min-w-[120px]">
{#each [["txt", "Plain Text"], ["md", "Markdown"], ["csv", "CSV"], ["html", "HTML"], ["srt", "SRT Subtitles"], ["vtt", "WebVTT"]] as [fmt, label]}
<button
class="w-full text-left btn-md text-text-secondary hover:bg-hover hover:text-text"
onclick={() => handleExport(fmt)}
>{label}</button>
{/each}
</div>
{/if}
</div>
<div class="flex gap-1 px-7 pb-4">
<LumotiaButton variant="tertiary" onclick={copyAll}>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="tertiary">Export</LumotiaButton>
{/snippet}
</LumotiaMenu>
</div>
</div>