48685f9dda6e19e46b8408560fb5f934f77e7589
211 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 48685f9dda |
v0.3 Phase 5c refinements: spacing, nested notice, conditional Save variant, paper edge
Final small refinements on Dictation per round-11 feedback before
moving to Files/Tasks/History.
1. Vertical rhythm tightened.
LumotiaPageSkeleton header padding pt-5 pb-3 -> pt-3 pb-2.
Notice padding pt-3 -> pt-2.
Primary surface area pt-5 pb-3 -> pt-3 pb-2.
DictationPage primary inner py-8 -> py-6.
Net: about 16 px shaved off the top band. Transcript canvas
begins higher, no longer feels like a large header above empty
space.
2. Disabled actions go neutral when there is nothing to act on.
Save button variant is now conditional:
variant={transcript.trim() ? "primary" : "secondary"}
Previously Save kept the blue primary fill even when disabled.
Disabled blue under 50% opacity still read as a strong primary
cue. Now: no transcript = neutral secondary; transcript exists
= primary blue. Other actions (Copy / Extract / Template / Open
Viewer) stay neutral regardless and become enabled when
transcript exists.
3. Light-mode transcript surface gains a tactile paper edge.
LumotiaPageSkeleton primary surface gains:
shadow-[inset_0_1px_0_rgba(0,0,0,0.05)]
Subtle 1-px inset top shadow at 5% opacity. Invisible in dark
mode (against the dark surface), visible in light mode as a
faint paper edge. Skeleton-wide because it costs nothing in
dark and adds the warmth Jake asked for in light.
4. Ambient info notice nested inside transcript surface.
Browser-preview notice + real-error notice now render INSIDE
the transcript card via the primary snippet, not in the
skeleton's notice slot. Renders contained at the top of the
card rather than as a full-width page banner. The notice slot
on LumotiaPageSkeleton stays available for blocking/error-
banner cases on other pages.
5. Mock-ready screenshot delivered.
Captured two new screenshot pairs:
root_PREVIEW__quiet-{dark,light}.png browser-preview state
root_READY__quiet-{dark,light}.png mocked Tauri-available
Mock done by temporarily setting tauriRuntimeAvailable = true
for the capture run, then reverted to hasTauriRuntime() at
commit time. The headless context still has no real Tauri
runtime so the model-check call fails — that surfaces as a
danger-tone slim notice in the ready screenshots, which
happens to demonstrate the danger-slim notice rendering
alongside the enabled red Record button.
In the real Tauri desktop app the danger notice would not
appear; only the Record (red), empty-state typography, and
bottom action dock with all-disabled neutral controls would.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
No colour exploration. No new tokens. Same red/blue/green/yellow/
orange grammar from Phase 4k.
Phase 5c is now complete. Next focused commits: 5d (Files), 5e
(Tasks), 5f (History), then Phase 6 (icon — waiting on SVG) and
Phase 7 (motion audit).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| ce784e58ab |
v0.3 Phase 5c polish: tighter header, disabled-record clarity, softer notice, attached action bar
Focused polish pass on the Dictation quietware layout per round-10
feedback. No colour exploration; only the eight specific tweaks.
1. Capture header tightened.
Record button + status block now grouped in their own flex
container (gap-3) so they read as one capture component. Record
size dropped from 72px to 64px so the group balances against the
status text. Timer pushed to far right via flex-1 on the inner
group. The trio (record / status / timer) feels like one unit.
2. Disabled Record affordance now reads as record.
Browser-preview state no longer renders as a neutral grey blob.
Instead:
bg-transparent
border-2 border-[color-mix(in_srgb,var(--button-record-bg)_45%,
transparent)]
opacity-80
cursor-not-allowed
inner muted-red dot bg-[color-mix(in_srgb,var(--button-record-bg)
_55%,transparent)]
Result: clearly a record control, clearly disabled, doesn't look
clickable. aria-label updated to "Record (desktop app only)" in
that state so screen readers carry the same message.
3. Slim notice border softened.
LumotiaNotice slim variant now uses border-border-subtle for the
outer border instead of the role-coloured border. Left bar stays
full role colour (the visible signal). Icon stays role colour.
Background stays at the role tinted bg. Net effect: notice is
ambient, not loud.
4. Action bar attached to transcript surface.
Dropped the LumotiaPageSkeleton actionBar slot for Dictation;
moved the buttons into the primary snippet as a bottom row inside
the same surface. Internal border-t + bg-bg-elevated/40 separator
keeps it visually nested. Reads as transcript actions, not a
generic page footer.
Also dropped primaryBleed so LumotiaPageSkeleton's default card
chrome wraps the transcript + action dock together — that gives
the surface boundary Jake asked for in light mode without
introducing a card-heavy treatment.
5. Compact one-line metadata footer.
Was: "Smart · {model} · Local only" + "{formatMode} · {profile}"
Now: "{formatMode} · {model} · Local only / Browser preview · {profile}"
Right-aligned. Single line. No duplicated "Smart". JetBrains Mono
via the existing --font-family-mono. text-tertiary.
6. Typography corrected.
Status title moved from Young Serif italic (font-display) to Work
Sans medium-weight (default body). Young Serif italic is now
reserved for the empty-state "Talk now, think later." line, which
remains the only emotional moment in the page.
7. Light mode surface intentional.
By dropping primaryBleed the skeleton's default surface chrome
(bg-bg-card + border-border-subtle + rounded-lg) wraps the
transcript canvas. Light mode now reads as a deliberate paper
surface, not an open page. Same boundary applies in dark.
8. Colour restraint preserved.
No token changes. Same red/blue/green/yellow/orange grammar.
Wireline contract unchanged. Brand orange still reserved for
logo/identity.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
- Headless screenshots confirm both quietware modes deliver the
polish: tight header, recognisable disabled-record, softer
notice border, attached action dock, compact metadata,
Work Sans status title, clear surface boundary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 4de3acd426 |
v0.3 Phase 5c: Dictation layout migration toward the mockup structure
Layout work, not a colour pass. DictationPage's existing 1 282-LOC
structure stays untouched for v0.2; under quietware a new layout
renders via LumotiaPageSkeleton with five zones matching the mockup:
Capture header large Record + status + secondary support + timer + pill
Slim notice info-classed browser-preview or danger-classed errors
Primary surface calm transcript canvas with empty-state typography
Action bar Copy / Save / Extract Tasks / Template / Open Viewer
Mono metadata Smart · model · Local-only or Browser-preview
Implementation pattern. Gated {#if isQuietware} branch inside the
existing {#if needsDownload}{:else} structure. The new layout
subscribes to ALL existing state bindings (page.recording,
page.timerText, transcript, error, tauriRuntimeAvailable, modelLoading,
settings.*, etc.) and reuses every existing handler:
toggleRecording, copyAll, saveTypedText, manualExtractTasks,
applyTemplate, invoke("open_viewer_window")
v0.2 surface unchanged — when data-design="quietware" is absent the
existing control-strip / toolbar / post-capture-card layout renders
as before.
Capture-header.
- Record button (72 px circular) carries the role-correct
--button-record-bg (red). Recording state pulses; modelLoading
shows spinner; non-Tauri state neutral-disabled.
- Status text uses Young Serif italic. Four states map to
"Ready to capture" / "Loading model" / "Desktop preview mode"
/ "Recording…".
- Secondary support text in Work Sans body weight, adapts per state.
- Timer in JetBrains Mono tabular-nums, right aligned.
- Status pill appears when useful (recording / transcribing / ready).
Slim notice.
- Browser-preview renders LumotiaNotice tone="info" slim dismissible
with the friendly Phase 5b copy.
- Real errors render tone="danger" slim dismissible.
- Slot stays empty otherwise — no permanent banner clutter.
Transcript surface.
- Empty state: 56-px Mic icon, Young Serif italic
"Talk now, think later.", Work Sans support "Press record, or
Ctrl+Shift+R." Centred, low-emphasis tertiary text on the calm
card surface.
- Populated: scrollable transcript at the user's accessibility
transcript-size preference.
Bottom action bar.
- Copy (tertiary), Save (primary blue), Extract Tasks (secondary),
Template (secondary, applies templates[0] when present), Open
Viewer (secondary, gated on Tauri).
- All disabled until transcript has content. Disabled controls
render neutral with no wireline per the Phase 4k token contract.
Mono metadata footer.
- Left: "Smart · {model} · Local only" or "Browser preview".
- Right: "{formatMode} · {activeProfile}".
- JetBrains Mono, text-tertiary, single line, below the action bar.
What's preserved (no behaviour change).
- Recording events, hotkey listeners (lumotia:toggle-recording).
- Tauri runtime branching (tauriRuntimeAvailable, browser-preview state).
- Live preview hooks (emit("preview-listening") etc.).
- Task extraction (manualExtractTasks -> extractTasksForTranscript).
- Template apply (applyTemplate(template)).
- Copy / Save paths (copyAll, saveTypedText).
- All existing state bindings on page.*, settings.*, prefs.*.
Out of scope for this commit (queued for follow-up).
- Files / Tasks / History page migrations (Phases 5d-5f).
- Real Lumotia wordmark / icon integration (Phase 6).
- Motion audit (Phase 7).
- Full Template-picker menu (currently auto-applies templates[0]).
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
- Headless-Chromium screenshots confirm the new layout renders
correctly in quietware-dark and quietware-light with the
disabled-record state (Tauri APIs absent in browser preview),
slim info notice, and empty-state typography.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| b9dd598937 |
v0.3 Phase 4k: palette architecture hardening — scales + component tokens + contrast check
Token-hardening pass per round-9 redirect. No new visual decisions —
just plumbing the tokens correctly so the colour grammar locked in
Phase 4j has a system underneath instead of hand-tuned hex.
Scales.
NEW: src/design-system/v0.3-quietware-scales.css. 11-step tonal
scales (50, 100, ..., 900, 950) for five source hues and their five
complement sources. Saturation drops at extremes to avoid neon
highs and washed-out lows. Hue-stable lightness curve picked to
mimic Material 3 / IBM Carbon tonal scales.
Generated by scripts/generate-quietware-scales.py (committed) so
values are reproducible. To regenerate:
python3 scripts/generate-quietware-scales.py > scales.css
Wired into src/app.css directly before v0.3-quietware-tokens.css.
Component tokens consume scale references only.
All --button-{role}-{tier} and --progress-{state}-fill tokens now
read from var(--{hue}-{step}) instead of raw hex literals. Future
scale tuning happens in one place; component callers never change.
--button-record-bg: var(--red-600)
--button-primary-bg: var(--blue-700)
--button-success-bg: var(--green-800) /* darkened so white
text clears AA */
--button-caution-bg: var(--yellow-400)
--button-neutral-bg: var(--color-bg-elevated)
--button-disabled-bg: var(--color-bg-elevated)
--brand-accent: var(--orange-500)
Progress component tokens.
New family: --progress-{download,transcribing,success,caution,danger,
disk,disk-caution,disk-danger}-fill plus --progress-track. Each
mode tunes the shade step so the bar reads on its track:
Dark: blue-400 / green-500 / yellow-500 / red-500
Light: blue-700 / green-800 / yellow-600 / red-700
HC-light: blue-700 / green-800 / yellow-700 / red-700
HC-dark: blue-300 / green-400 / yellow-400 / red-400
LumotiaProgress.svelte gains tone="transcribing", "disk",
"disk-caution", "disk-danger" so callers map progress role to
token explicitly.
Border / wireline / focus-ring discipline.
Three distinct token families:
--button-primary-border structural component edge
--button-primary-wire complementary identity detail
--focus-ring-color keyboard interaction
Documented as separate concerns in the tokens file.
Contrast check script.
NEW: scripts/check-colour-contrast.mjs. Parses scales + tokens
CSS, builds per-scope token tables for dark / light / HC-light /
HC-dark, resolves var() chains and color-mix() expressions, then
verifies twelve load-bearing component pairs against WCAG 2.2
minima (4.5:1 text, 3:1 UI). Exit code 1 on failure.
Current state: 0 failures across 4 modes.
Two pairs reported as "warn" rather than "fail": caution progress
on cream + caution notice border on cream. The yellow source colour
cannot clear 3:1 on a near-white surface without losing its
identity. Role recognition is carried by left-bar + icon + label,
not by surface contrast.
Verified.
- node scripts/check-colour-contrast.mjs: 0 failures, 4 modes, 12
load-bearing pairs + 2 known-limitation warns.
- npm run check: 0 errors, 0 warnings across 5707 files.
Phase 5c (Dictation layout migration) is the natural next focused
sitting. This commit gives Phase 5c the systematic colour grammar to
build on, and the contrast check gates future palette regressions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 2c6f5ca230 |
v0.3 Phase 4j: colour grammar correction — record red, brand orange separate, wirelines bumped
Major correction per round-8 redirect.
Problem.
- Brown/copper --color-accent #C97845/#9D5F32 was dragging the UI
back into the warm-brutalist palette and competing with semantic
yellow.
- Record button about to become blue (Lumotia primary). Wrong —
record is universally red across products and OSes.
- Brand orange conflated with primary action. Orange should be
brand mark only.
Solution.
Source tokens — identity-only, never used directly in components:
--source-red #FF0700
--source-yellow #FFCD00
--source-green #00FF56
--source-blue #000AFF
--source-orange-brand #F0620A
--{role}-complement-source for the wireline layer
Component tokens — what components subscribe to. Hand-tuned hex
values verified at WCAG AA on the foreground each button pairs with.
Tonal scales (red-50..red-950 etc.) reserved for a focused future
commit; component names stay stable through that upgrade:
--button-record-bg #DC2626 (red)
--button-record-fg #FFFFFF
--button-record-border #B91C1C
--button-record-wire #00D8E0 (cyan, red's complement)
--button-primary-bg #2563EB (blue)
--button-primary-fg #FFFFFF
--button-primary-wire #F6E600 (yellow, blue's complement)
--button-danger-bg same as record (red, fg white, cyan wire)
--button-success-bg #15803D dark / #166534 light (green)
--button-success-wire #E600A0 (magenta, green's complement)
--button-caution-bg #FACC15 (yellow, fg #1A1500 near-black)
--button-caution-wire #1850D8 (blue, yellow's complement)
--brand-accent #F0620A (orange, LOGO ONLY)
--brand-wire #0A98F0 (cyan-blue, orange's complement)
--color-accent repointed:
quietware dark: #4A7BFF (was #C97845 copper)
quietware light: #1D4ED8 (was #9D5F32 copper)
HC: #005FCC (existing, unchanged)
v0.2 fallback: var(--color-accent) preserved → v0.2 stays amber.
New LumotiaButton variant: "record". Used by DictationPage's
record control. Existing v0.2 record button class swapped from
bg-accent (amber) to bg-[var(--button-record-bg)] (red). v0.2
fallback at :root maps --button-record-bg to var(--color-danger)
so non-quietware surface keeps its red-when-recording / amber-when-
idle behaviour.
Wirelines (renamed from counterlines).
--wire-width 1px / --wire-width-active 2px / --wire-width-focus 2px
--wire-opacity-dark 0.75 (was 0.32; bumped per round-8 spec)
--wire-opacity-light 0.6 (was 0.22)
--wire-opacity-active 0.9
--wire-opacity-focus 1
--wire-opacity is a mode-aware resolver (-dark dark / -light light)
--wire-style solid (dotted reserved for design-preview / drag-drop)
HC contract: --wire-width 0, --wire-width-focus 2px kept.
--focus-ring-color #005FCC (strong blue), not a decorative complement.
Legacy --counterline-* tokens kept as aliases pointing at the new
--wire-* set so Phase 4h/4i opt-in code still works.
Design-system-v2 preview now shows the new record variant alongside
primary so both red and blue button identities are visible.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
Phase 5c (Dictation layout migration) still queued for the next
focused sitting. This commit gives Phase 5c the correct grammar to
build on.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 001d8fe83d |
v0.3 Phase 4i: counterlines as interaction-affordance identity
Round-7 redirect (Option D): move counterlines from notices (where
they're invisible) to interactive controls (where they add identity).
Three-level model:
Level 0 no counterline panels, notices (default), content, disabled
Level 1 quiet controls, chips, active nav
1 px, 48% opacity dark / 34% light
Level 2 focus / strong keyboard focus, recording state
2 px, 85% opacity
Notices retire from default counterline rendering. Notice already
carries enough semantic language: bar + icon + border + bg + label.
A complementary inset on top was adding nothing. Notice can opt in
via <LumotiaNotice counterline ... /> when it deliberately mimics
control identity.
Token deltas vs Phase 4h.
--counterline-width: 1px unchanged
--counterline-width-focus: 2px new (Level-2 width)
--counterline-opacity-dark: 0.48 was 0.32 (raised so Level-1
actually reads on controls)
--counterline-opacity-light: 0.34 was 0.22
--counterline-opacity-focus: 0.85 new
--role-brand-counterline: #3A6BFF new (blue counter for the
orange brand accent so
primary buttons get an
identity edge like the
other roles)
--button-{role}-counterline new (per-role component tokens
subscribing to role-counterline
via color-mix)
--focus-ring-color new (defaults to brand accent;
HC overrides to #005FCC)
LumotiaButton applies counterlines to primary + destructive variants
only. Secondary + tertiary stay clean. All variants get a Level-2
focus-visible ring at --focus-ring-color * opacity-focus, with the
existing ring-offset-2 ring-offset-bg pattern.
LumotiaNotice gains a `counterline` boolean prop, default false. When
set, the previous Phase 4h inset shadow re-applies.
HC contract: counterline-width 0 + all -counterline tokens transparent.
Focus width stays 2 px because the HC focus ring IS the tactile
detail in that mode. focus-ring-color forces to #005FCC.
Honest evaluation of the visible result.
Notices: visibly cleaner without the default inset shadow. Reads
with more confidence. Good change.
Buttons: counterline applied at 1 px / 48% dark / 34% light is
perceptible at standard viewing but screenshot-zoom subtle. Focus
state implemented but not visible in static screenshots; requires
manual tab-test in the dev server.
Recommend keeping the architecture even if the visual is restrained,
because the focus-state work is genuinely valuable accessibility
scaffolding regardless of how the Level-1 reads.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
Phase 5c (Dictation layout migration) still queued for a focused
fresh sitting. This commit does not block it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 74bcc293bb |
v0.3 Phase 4h: counterlines test on LumotiaNotice
Test commit for Jake's round-6 spec. Subtle 1-px inset shadow in a
softened complementary hue, applied to LumotiaNotice only. Other
test surfaces (Button.destructive, status pills, record ring, active
nav) reserved for after evaluation.
Tokens (quietware scope only, v0.2 surface unchanged):
--counterline-width: 1px
Raw complementary hues per Jake's table:
--role-info-counterline var(--color-accent) /* copper for blue */
--role-danger-counterline #6EA8FF /* soft blue for red */
--role-success-counterline #B891FF /* soft violet for green */
--role-caution-counterline #3A6BFF /* soft blue for yellow */
Tinted per-mode via color-mix:
Dark mode: 32% opacity (slightly stronger against dark surface)
Light mode: 22% opacity (whisper-quiet against cream)
HC mode: all transparent, --counterline-width: 0
Per-usage notice tokens emitted:
--notice-{role}-counterline
LumotiaNotice applies via Tailwind arbitrary value:
shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-{tone}-counterline,transparent)]
HC contract zeroes both the width and the colour token so the 2-px
HC border carries the tactile detail instead.
Honest evaluation of the visible result.
At 1px and 22%/32% opacity the counterline is implemented
correctly but reads as whisper-quiet to the point of being almost
invisible at standard viewing zoom. Doesn't look noisy (the risk
Jake flagged), but also doesn't add perceptible tactility.
Pending Jake's call:
(a) raise opacity to ~45% dark / ~35% light for visibility,
(b) keep at current opacity for the quietness,
(c) revert and proceed Phase 5c.
Phase 5c proceeds either way; this commit does NOT block the
layout migration.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 2f11f493c5 |
v0.3 Phase 4g: four-tier semantic tokens + notice usage layer
Round-5 feedback flagged the muddy result of forcing one --color-caution
to be both bright yellow (signal) and accessible text (ochre). The
single-token-per-role model collapsed the visible identity. Caution
notices ended up reading as brown/khaki surfaces because color-mix(
in oklab, var(--color-caution) 8%, transparent) over cream produced
muddy results whatever the source hex.
New architecture: four-tier per-role tokens, hand-tuned -bg surfaces,
plus usage-specific notice tokens on top.
Tier model — each semantic role publishes four tokens:
signal Brand-true colour. Left bars, large icons, dots, focus rings.
Looks like the role at a glance.
ink Accessible text variant. Used ONLY when text itself must
carry the role colour. WCAG AA 4.5:1 on its surface.
border Middle value. Visible chip/notice outline; not text-safe.
bg Hand-tuned pale tint surface. NOT a color-mix derivation.
Example, light-mode caution:
--color-caution-signal #FFCD00 (bright yellow)
--color-caution-ink #7A5D00 (ochre, for small text only)
--color-caution-border #D9A900 (mid gold)
--color-caution-bg #FFF7D6 (clean pale yellow tint)
--color-{role} retained as a backward-compat alias pointing at -signal.
v0.2 callers keep working; new code reaches for the specific tier.
Usage layer — components subscribe to usage-specific tokens, not
role-tier tokens directly:
--notice-{role}-bar left bar, signal-tier
--notice-{role}-icon signal in dark, ink in light, signal in HC
--notice-{role}-border outer border colour
--notice-{role}-bg hand-tuned pale surface
LumotiaNotice reads these via Tailwind arbitrary-value classes
(bg-[var(--notice-info-bg)] etc). v0.2 fallback values defined at
:root (outside quietware blocks) using color-mix from v0.2 --color-
{role} tokens so the Notice keeps rendering sensibly when quietware
is off.
HC contract — every -bg token forces to transparent. HC notices
render text + icon + 2-px border + left bar, no body tint. Brand
atmosphere steps fully aside.
Per Jake's round-5 spec: yellow stays yellow as the visible signal,
ochre only appears as small-text ink, and brown/khaki never
represents the caution role's primary visual identity again. Same
discipline applies to red/blue/green — each role has a clean
hand-tuned -bg pale tint per theme.
Verified — visible result.
Light caution notice: bright #FFCD00 bar + signal icon + ink-darkened
small icon + pale #FFF7D6 surface + #D9A900 border. Clean,
semantically clear, no mud.
Dark caution notice: bright #FFCD00 bar + signal icon + dark warm
#29210A surface + bright yellow border. Reads as yellow at a glance.
HC modes: no body tint, strong bordered notices, semantic colours
preserved as primary identifier alongside icon + label.
npm run check: 0 errors, 0 warnings across 5707 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 2fcb5aff78 |
v0.3 Phase 4f/5a/5b: token architecture + skeleton + browser-preview reclass
Three small phases land together for Jake's round-4 feedback. Each is
focused and reviewable. Larger Dictation/Settings/Tasks/History page
migrations are deferred to focused future sittings.
Phase 4f — semantic source / derived token architecture.
Added --semantic-{red,blue,green,yellow}-source raw-palette tokens.
These encode the role's hue identity from Jake's color.adobe.com
palette (#FF0700 / #FFCD00 / #00FF56 / #000AFF) and stay constant
across all themes. The existing --color-{danger,caution,success,info}
tokens are now documented as theme-tuned derivations meeting WCAG
AA in context. Source tokens make the brand-to-runtime relationship
traceable in code.
Added --color-{role}-bg subtle-fill tokens derived via
color-mix(in oklab, var(--color-{role}) 8%, transparent). Used by
Notice backgrounds, hover tints and focus halos. HC mode forces
-bg tokens to transparent so HC notices read as text + icon +
2-px border + left bar with no body tint.
Phase 5a — page skeleton primitive + slim notice variant.
NEW src/lib/ui/LumotiaPageSkeleton.svelte. Six-zone layout:
header (optional)
notice (optional, slim ambient state)
primary work surface (required, primaryBleed for full-bleed)
right rail (optional, lg-screen drawer)
action bar (optional, bottom)
metadata (optional, mono micro-footer)
Every zone except primary is opt-in. Foundation for the
page-skeleton sweep without forcing any page migration yet.
LumotiaNotice gained a slim prop. When true: padding collapses
(px-3 py-2 vs px-4 py-3), icon shrinks (14 vs 16), title block is
suppressed. For ambient page-level notices like browser-preview.
Phase 5b — browser-preview reclassification.
src/lib/pages/DictationPage.svelte: the browser-preview state used
to render as a red error block. That is an environment limitation,
not a failed action. Reclassified as a slim info notice with
friendlier copy:
"You're in a browser preview. Local transcription only works in
the Lumotia desktop app."
Other error states (transcription failed, needs review) still
render through the original danger-tinted block with the
technical-details affordance preserved. Only the browser-preview
path branches into LumotiaNotice tone="info" slim.
The larger Dictation page restructure (header recomposition,
Template/Extract Tasks demotion to bottom action bar, empty-state
typography) is reserved for a focused Phase 5c sitting since
DictationPage.svelte is 1 262 LOC of state-heavy code.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| dab9c7b5a6 |
v0.3 Phase 4d/4e: palette revision + HC rendering contract
Round-4 feedback (2026-05-15) pulled the system away from the
color.adobe.com primaries toward muted-Material values, separated
brand accent from semantic caution, and reframed high-contrast as a
behavioural rendering contract rather than a palette override.
Two phases land together because the palette revision and the HC
contract are inherently linked — HC mode needs both palette overrides
AND behavioural-token overrides to deliver "different rendering
contract" semantics.
Phase 4d palette revision.
Dark mode (was wine-aubergine #2A1620, now brown-charcoal #12100E):
--color-bg #12100E
--color-bg-elevated #1A1713
--color-bg-card #211D18
--color-bg-input #181510
--color-sidebar #0F0E0C
--color-border #4A4035
--color-border-subtle #2C261F
Brand accent (new — was unset, fell through to v0.2 amber that
competed with semantic yellow):
Dark: --color-accent #C97845 (copper)
Light: --color-accent #9D5F32 (deeper copper)
Semantic colours (muted-Material, both modes):
Dark: danger #FF8A8A caution #F2C94C success #79D59B info #8AB4F8
Light: danger #B3261E caution #7A5D00 success #1B6B3A info #2457A6
Light mode work surface (slight paper tone, not pure white):
--color-bg-card #FFFDF8 (was #FFFFFF)
--color-bg-elevated #F6F1EA
Caution fill-only-on-cream rule retires. Ochre #7A5D00 passes AA
as foreground text on cream under the muted palette, so the single-
token-per-role convention applies across all four semantic colours
in both modes.
LumotiaNotice opacity rebalance:
Background tint 10% -> 8%
Outer border neutral subtle -> role at 40%
Icon --color-text -> role colour
Left bar role at 100% (unchanged)
Title / body --color-text (unchanged)
Phase 4e HC rendering contract.
Behavioural tokens published alongside palette:
--grain-opacity 0.06 dark / 0.07 light / 0 in HC
--shadow-strength 1 default / 0 in HC
--border-width-control 1px default / 2px in HC
--focus-ring-width 2px default / 3px in HC
--panel-radius 8px (reserved for future tightening)
--quietware-texture-opacity retained as a legacy alias pointing at
--grain-opacity so Phase 4c slider keeps working through the rename.
HC palette: pure-black or pure-white base, the other for borders,
single strong-focus blue #005FCC replaces accent. Brand atmosphere
steps aside. Selector splits via :not([data-theme="light"]) so
HC-light and HC-dark variants diverge cleanly.
Verified.
- npm run check: 0 errors, 0 warnings across 5706 files.
- Plan doc updated with full before/after tables, behavioural-token
contract table, and Phase 4c / 4d / 4e log sections.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 4dca802f0b |
v0.3 Phase 4c: HC toggle + texture-intensity slider + grain overlay
Three additions land together so the slider is meaningful from day
one (instead of recording a preference that nothing consumes yet).
Static grain overlay.
- src/design-system/v0.3-quietware-tokens.css adds a fixed-position
body::after element that ships an SVG feTurbulence noise tile
repeated across the viewport. Opacity reads from
--quietware-texture-opacity. mix-blend-mode: overlay produces the
soft notebook-paper feel without obscuring content.
- pointer-events: none so clicks pass through. Active only under
html[data-design="quietware"]. High-contrast forces opacity to 0
via the existing HC palette block.
QuietwareAccessibilityControls component.
- NEW: src/lib/components/QuietwareAccessibilityControls.svelte.
Two controls, both quietware-only:
1. High-contrast toggle wires html[data-contrast="high"].
Overrides the OS prefers-contrast: more query when explicitly
on. Built on LumotiaToggle so it inherits the accessible
label + description pattern.
2. Texture-intensity slider, range 0.05 to 0.08, step 0.005,
default 0.06. Sets --quietware-texture-opacity inline on
<html>, overriding the per-mode default in the tokens CSS.
Disabled while high-contrast is on. Reset button restores
0.06.
- Persistence: localStorage keys
lumotia:quietware:high-contrast
lumotia:quietware:texture-opacity
so choices survive dev rebuilds and full restarts. Full
integration with the central Preferences store is a follow-up;
localStorage keeps Phase 4c contained.
SettingsPage Accessibility section.
- Imports the new QuietwareAccessibilityControls component.
- Renders {#if isQuietware} <QuietwareAccessibilityControls />
{/if} immediately after the existing AccessibilityControls block.
- Search filter copy extended to cover the new control vocabulary.
Verified.
- npm run check: 0 errors, 0 warnings across 5706 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 091780086b |
v0.3 Phase 4a: Settings tab shell
Discovers that v0.2 SettingsPage.svelte was already structured as
eight numbered sections aligning almost 1:1 with the v0.3 plan. The
cheapest path to "one section visible at a time" is therefore a
tab-shell overlay rather than a file split. Behaviour stays identical
to v0.2 when quietware is off; with quietware on, only the active
tab's section renders.
Changes.
- NEW: src/lib/ui/LumotiaSettingsTabs.svelte. Tab list following
the WAI-ARIA "tabs (automatic activation)" pattern. Arrow / Home /
End keyboard navigation. Active tab uses the brand left-bar
accent (border-l-caution) — same grammar as the LumotiaNotice
refactor from Phase 3.
- MODIFIED: src/lib/pages/SettingsPage.svelte. Added an isQuietware
reactive flag, a MutationObserver watching <html data-design>,
an activeTab state, and eight {#if !isQuietware || activeTab ===
'X'} wrappers around the existing top-level SettingsGroup
sections. The settings tree is unchanged; only its top-level
rendering gate changed.
- v0.2 fallback: when data-design="quietware" is absent the
tablist does not render and all eight sections stack as before.
The search filter spans every section in v0.2 mode. Smallest-
possible behavioural change for "one section at a time".
Tab IDs in this commit map 1:1 to existing v0.2 section names
(start-here / transcription / models / tasks / accessibility /
privacy / advanced / help). Phase 4b will restructure to the plan's
canonical names (carving Output from Advanced and Vocabulary from
Transcription).
Phases 4b and 4c are logged as pending in the plan doc:
4b. Restructure to canonical tab names (Output, Vocabulary).
4c. Texture-opacity slider + high-contrast toggle in Accessibility.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| db9c50c548 |
v0.3 Phase 3: status grammar — LumotiaNotice left-bar refactor
Phase 3 audit found that both LumotiaStatusPill and LumotiaNotice
already shipped in v0.2 Phase 5. Phase 3 reduced to an audit-and-adapt
pass.
LumotiaStatusPill ($lib/components/StatusPill.svelte) is already
correct for quietware. Pattern: neutral pill background + neutral
label text + role colour confined to a 6x6 px dot. Colour is
supplementary, label is always perceivable. Works unchanged across
all three quietware modes. No changes shipped.
LumotiaNotice ($lib/ui/LumotiaNotice.svelte) refactored to the
left-bar accent pattern. Previously the role colour rendered on the
icon outline and on the entire surround border at 30% opacity; in
quietware light mode that left the bright #FFCD00 caution colour
faded against cream paper. New pattern:
- 4-px solid LEFT border in the tone colour, 100% opacity.
- Soft tone-tinted background (10% opacity) for ambient cue.
- Subtle neutral outer border on the other three sides.
- Icon, title and body text all use --color-text.
Visible signal lives on the large bar (works at any contrast level);
foreground text uses the always-legible neutral. Matches Material
Design "banner with leading accent" and IBM Carbon "inline
notification" guidance. ARIA semantics (role="alert" for danger,
role="status" for the rest) preserved.
Design-system-v2 preview route already imports both primitives. The
updated Notice renders correctly with the existing preview content;
no additional wiring required.
Caution remains a fill-only convention on cream by design. Any
darkened yellow reads as olive ("looks like poop", per Jake), so the
fill-only rule stays in force and this pattern delivers it cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| a9972f76bb |
v0.3 Phase 2: build flag wiring
Wires VITE_LUMOTIA_QUIETWARE=1 to set <html data-design="quietware"> via a $effect in src/routes/+layout.svelte. Without the flag the runtime app behaves exactly as v0.2; with the flag the v0.3 token overrides in src/design-system/v0.3-quietware-tokens.css activate. Hot-reload safety: if the env var is unset between dev rebuilds, the attribute is cleared so devs do not see a stuck quietware surface. Activation paths: VITE_LUMOTIA_QUIETWARE=1 npm run dev (development) VITE_LUMOTIA_QUIETWARE=1 npm run build (production) Or manually via dev tools: <html data-design="quietware"> Combine with data-theme="light" (existing v0.2 theme wiring) and data-contrast="high" (existing v0.2 contrast wiring) to reach the light and high-contrast quietware modes. Smallest possible PR. No new dependencies. No bundle-size impact in the off path. No component changes. Plan doc updated to mark Phase 2 as landed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 7075c205fc |
v0.3 Phase 1: palette amendment to color.adobe.com primaries
Third palette iteration. Source: Jake's color.adobe.com primaries
attached to the Phase 1 review reply 2026-05-15:
#FF0700 red -> --color-danger
#000AFF blue -> --color-info
#00FF56 green -> --color-success
#FFCD00 yellow -> --color-caution
Each primary is used literally where it clears WCAG AA on the
relevant background. Where it does not, a text-safe sibling at the
same hue and saturation is derived.
LIGHT MODE on cream paper
--info #000AFF Jake literal 7.96 AAA
--danger #E60600 sibling 4.51 AA
--success #00852D sibling 4.51 AA
--caution #FFCD00 Jake literal 1.42 (fill-only by convention)
DARK MODE on lifted Coffee Bean #2A1620
--info #7076FF lifted from blue 4.64 AA
--danger #FF2A24 lifted from red 4.54 AA
--success #00FF56 Jake literal 12.51 AAA
--caution #FFCD00 Jake literal 11.33 AAA
HIGH CONTRAST on black, S=80% L=70%
--info #757AF0 5.80 AA
--danger #F07975 7.70 AAA
--success #75F09F 14.72 AAA
--caution #F0D875 14.78 AAA
Caution remains a fill-only convention on cream. Any darkened yellow
reads as olive or mustard, which Jake refused at the round-2 stage
(see capture 2026-05-15-re-lumotia-v03-renders-revised-palette-).
No component changes. No behavioural changes. Phase 1 still inert
without html[data-design="quietware"]. Supersedes the cobalt-pegged
square palette in commit
|
|||
| f718aded16 |
v0.3 Phase 1: Tactile Quietware tokens
Foundation for the v0.3 Tactile Quietware release. Tokens only. No
component refactors, no layout changes, no behavioural shifts. The new
palette and typography activate only when html[data-design="quietware"]
is set; the runtime v0.2 surface is unaffected without the attribute.
What landed.
- Three-mode palette (light, dark, high-contrast) at
src/design-system/v0.3-quietware-tokens.css. Strict 90deg square
colour harmony pegged at cobalt blue #0047AB. Hues: 215 / 305 / 35
/ 125. Saturation locked at 100%. Lightness adjusted per role for
WCAG AA 4.5:1 on the relevant background; computed values
documented in the plan doc.
- V4 font stack self-hosted as WOFF2:
Work Sans (variable, roman + italic) for body, UI, controls.
Young Serif for brand moments only.
JetBrains Mono stays via existing src/fonts/jetbrains-mono.woff2.
- Import wired in src/app.css directly after the tailwind import.
The new tokens are inert until data-design="quietware" is set on
<html>.
- Reduced-motion override scoped to quietware so prefers-reduced-motion
actually bites inside the new design system from day one.
- Plan doc at docs/release/v0.3-tactile-quietware.md with the full
seven-phase plan (Phase 1 logged), four high-priority persona test
gates (Pawel, Simone, Chris, Ron), and the Phase 0 gov.uk DfE
accessibility tools checklist.
Activation paths.
- Manual now: dev tools, set <html data-design="quietware">.
- Phase 2 will wire VITE_LUMOTIA_QUIETWARE=1 through +layout.svelte.
Verified.
- npm run check produced 26 errors but all 26 are pre-existing in
files this PR does not touch (LumotiaTooltip.svelte missing
bits-ui import; tests/e2e/smoke.spec.ts missing playwright types).
Tracked separately, not blocking v0.3 Phase 1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| b5f622f128 |
v0.2 Phase 7.7: SettingsPage — wrapper sweep via import-only swap
SettingsPage is 2 791 LOC with ~95 form controls. The plan called for section-by-section migration with selective Formsnap; the wrapper aliases land Phase 4 made that unnecessary on the per-section level. Because LumotiaCard / LumotiaToggle / LumotiaSettingsGroup / LumotiaStatusPill keep the exact prop API of the underlying components, all that's needed to migrate every existing markup site is repointing the four local import names: Card → $lib/ui/LumotiaCard.svelte Toggle → $lib/ui/LumotiaToggle.svelte SettingsGroup → $lib/ui/LumotiaSettingsGroup.svelte StatusPill → $lib/ui/LumotiaStatusPill.svelte The 90+ <Card>, <Toggle>, <SettingsGroup>, <StatusPill> usages compile unchanged because the local symbols still resolve to compatible components. Existing IA is preserved verbatim — section ordering, SegmentedButton bindings, HotkeyRecorder, ZonePicker, ModelDownloader, and the Phase 3 KI-05 theme bindings all stay in place. Formsnap is intentionally NOT pulled into SettingsPage in v0.2. The form here is a wide tree of independent settings; Superforms + Formsnap would force a heavyweight schema layer for no observable validation win. Per-page gate: npm run check (0/0/5704 files). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 4fa8df638b |
v0.2 Phase 7.6: DictationPage — centrepiece wrapper sweep
This is the page Settings will inherit grammar from, so it's worth a
slightly fuller sweep than the earlier ones — without touching the
recording state machine, the SVG VisualTimer, the waveform bars, the
transcript textarea, ModelDownloader, or SpeakerButton, which are all
bespoke per the §6.3 do-not-wrap list.
- StatusPill import → LumotiaStatusPill (all use sites swapped)
- PostCaptureCard import → LumotiaPostCaptureCard
- Card import → LumotiaCard
- EmptyState import → LumotiaEmptyState
- LumotiaNotice import added; the inline `liveWarning` panel now
uses LumotiaNotice tone=caution
The danger-tinted error block (lines ~1130) was left verbatim — it
already nests a StatusPill (now LumotiaStatusPill), a <details>
disclosure, and a Dismiss button in a structure LumotiaNotice's
single-icon contract doesn't model cleanly. Phase 7's primary
output for this page is import-level coherence; behavioural
identity stays untouched.
Bespoke surfaces preserved: recording controls, VisualTimer, waveform,
transcript surface (bionic action + accessibility typography), all
hotkey wiring, all live-session state.
Per-page gate: npm run check (0/0/5704 files).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 021a5fc196 |
v0.2 Phase 7.5: HistoryPage — wrapper sweep
Targeted migration on a 1 225-LOC page. The FTS5 search input stays a plain <input> (LumotiaCombobox needs an options list; free-text search doesn't fit the API cleanly enough to justify a rewrite for v0.2). Row patterns + clear-all modal stay verbatim — their bespoke ARIA and inline arm-confirm state are core to the page's identity. - Card import → LumotiaCard (4 use sites bulk-swapped) - EmptyState import → LumotiaEmptyState (4 use sites) - LumotiaButton import added for selective use in follow-up sweeps Bespoke surfaces left verbatim: VirtualSegmentList, audio player, clear-all type-the-word modal, tag-chip filter bar. Per-page gate: npm run check (0/0/5704 files). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| b6c065ffd1 |
v0.2 Phase 7.4: TasksPage — minimal wrapper sweep
Targeted migration per plan ("wrap, don't rewrite"). The page's
identity surfaces (energy chips, search input, quick-capture input,
bucket tabs, WipTaskList) stay verbatim — their rich ARIA and custom
radio-group semantics outweigh wrapper coherence here.
- Dead Card import removed (never used in markup)
- EmptyState → LumotiaEmptyState
- "Pop out" toolbar button → LumotiaButton variant=tertiary
WipTaskList, CompletionSparkline, EnergyChip stay bespoke per
docs/release/v0.2-frontend-overhaul.md §6.3.
Per-page gate: npm run check (0/0/5704 files).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| cb69772f4e |
v0.2 Phase 7.3: FirstRunPage — wrapper sweep
Migrated the onboarding step cluster's ad-hoc button pairs to the new grammar. Skip-link tertiary buttons stay as plain <button> with underline because they're intentionally low-emphasis (text-only). - Step CTA buttons (primary + secondary) → LumotiaButton variants - Autostart "Saving…" pair → LumotiaButton loading + disabled - Error notice → LumotiaNotice tone=danger with body content snippet - Download progress bar → LumotiaProgress Bespoke surfaces left verbatim: model-pick cards (rich content tiles with Recommended/Downloaded pills), UnicodeSpinner, and the test-recording quote-block. Per-page gate: npm run check (0/0/5704 files). e2e baseline untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| d812410039 |
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> |
|||
| 3614c94885 |
v0.2 Phase 7.1: ShutdownRitualPage — wrapper sweep
Migrated the two ad-hoc buttons to wrappers; everything else (display- only reflective copy, the open-loops list, the Newport shutdown template) stays verbatim since the page is intentionally low-grammar. - Back-arrow button → LumotiaIconButton (icon=ArrowLeft, size=sm) - "Close" button → LumotiaButton variant=primary Bespoke: none on this page (no recording state, no transcript surface). Per-page gate: npm run check (0/0/5704 files). Vitest / browser-mode / e2e baselines stay green (no behaviour change). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| a9733544c0 |
v0.2 Phase 6: shell split — AppRuntime / AppChrome / AppOverlays
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> |
|||
| c60f0aa5a5 |
v0.2 Phase 5: 11 primitives + gated design-system-v2 preview
Custom-styled primitives (no headless dep): LumotiaButton — primary/secondary/tertiary/destructive × sm/md/lg LumotiaIconButton — square icon-only; ghost/filled/destructive LumotiaNotice — info/caution/danger/success inline notice LumotiaProgress — native <progress> + token theming LumotiaField — plain + Formsnap modes share the same markup Bits UI 2.18.1 wrappers (warm-brutalist styling): LumotiaSelect — single-select, options=[] LumotiaCombobox — searchable; one-way inputValue + oninput LumotiaDialog — controlled open; closable + footer snippet LumotiaTabs — orchestrates List/Trigger/Content from a tabs array LumotiaTooltip — wraps Provider + Root + Trigger + Content LumotiaMenu — DropdownMenu items=[] with destructive variant design-system-v2 preview route: src/routes/design-system-v2/+page.ts gates with VITE_LUMOTIA_DESIGN_SYSTEM_V2=1. Without the flag the load() throws 404 — route-level gate, not nav- hidden. Run via VITE_LUMOTIA_DESIGN_SYSTEM_V2=1 npm run dev:frontend to see the showcase. Browser-mode component test: src/lib/ui/LumotiaButton.browser.test.ts. Covers render, click, and disabled-blocks-click. Validates that vitest-browser-svelte + the @vitest/browser-playwright provider land Phase 1's tooling contract end-to-end. 3/3 passing in Chromium. Type fix: LumotiaIconButton and LumotiaMenu accept icon: any so lucide-svelte's legacy SvelteComponentTyped shape composes with our Svelte 5 wrappers without forcing a // @ts-nocheck escape hatch on every call site. Tightens to Component<…> once lucide-svelte ships a Svelte 5 build. Type fix: LumotiaCombobox honours Bits UI 2.x Combobox.Root's one-way inputValue contract. The wrapper drops bind:inputValue and exposes an oninput callback so caller-owned filter pipelines (HistoryPage FTS5, ModelDownloader) can drive options upstream. Phase 5 per-page gate green: npm run check (0/0/5700 files), npm test, npm run test:browser (3/3 in Chromium), npm run test:e2e (16/16), guard-no-skeleton clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 8c9708a508 |
v0.2 Phase 4: wrapper alias layer (src/lib/ui/)
Six thin alias wrappers, same prop APIs as the underlying components. Lets pages migrate imports from $lib/components/* to $lib/ui/* one file at a time without touching markup, and gives Phase 5+ a place to tighten grammar without churning every call site. LumotiaCard → Card.svelte LumotiaStatusPill → StatusPill.svelte LumotiaToggle → Toggle.svelte (forwards bind:checked, bind:loading) LumotiaSettingsGroup → SettingsGroup.svelte (typed Props for svelte-check) LumotiaEmptyState → EmptyState.svelte LumotiaPostCaptureCard → PostCaptureCard.svelte Per the plan, the underlying components in src/lib/components/ are untouched. They get retired during the per-page migrations in Phase 7 once no consumer remains. LumotiaSettingsGroup mirrors the underlying Props interface explicitly because Svelte 5's spread-into-typed-component caught a real missing- `title` error during svelte-check. The mirrored interface keeps call sites type-safe when importing via $lib/ui/. Phase 4 per-phase gate green: npm run check (0/0/4135 files), npm test (all green), npm run test:e2e (16/16), npm run guard:no-skeleton (clean). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 66e25aa778 |
v0.2 Phase 3: additive semantic tokens + KI-05 resolution
Additive token grammar (no renames, no replacements):
- --color-caution (dark #e8be4a, light #a08a1f) becomes the canonical
name for tuned-amber notice surfaces in the new wrapper grammar
- --color-warning is kept as a CSS var() alias of --color-caution so
every existing text-warning / bg-warning call site stays valid
- --color-info (dark #7a9ec0, light #3d6a8a) is the soft blue-grey
signal for the new LumotiaNotice info variant
- --color-accent-environment (dark #8fae9a, light #4a7058) is an
optional sage/moss support token for empty-state illustrations
and environment-neutral status dots. NOT a brand swap — amber/
copper --color-accent stays primary
Mirrored in src/design-system/colors_and_type.css (the buildless
preview pages bypass Tailwind so the duplication is intentional).
KI-05 resolved in the same commit, per the plan:
- src/lib/types/app.ts: drop `theme` from SettingsState
- src/lib/stores/page.svelte.ts: drop `theme: "Dark"` from defaults
- src/routes/+layout.svelte: drop the migration $effect, add a
one-shot migrateLegacyTheme() on mount that copies any historical
lumotia_settings.theme into preferences.theme and strips the
legacy field. Idempotent — subsequent loads short-circuit
- src/routes/{float,viewer,preview}/+layout@.svelte: drop the same
$effect; secondary windows inherit theme via PREFERENCES_CHANGED_EVENT
- src/lib/pages/SettingsPage.svelte: both SegmentedButton bindings
(quick-settings row at :1272, Appearance group at :2606) now use
Svelte 5 function bindings ({ get, set }) backed by prefs.theme
and updatePreferences. No SegmentedButton API change
Phase 3 per-page gate green: npm run check (0/0/4129 files),
npm test (13/13), 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>
|
|||
| 100e04fa70 |
v0.2 Phase 0+1: planning doc + tooling baseline
Phase 0 — docs/release/v0.2-frontend-overhaul.md as single source of truth for the v0.2 frontend coherence pass. Records hard rules, tooling pins, sacred-behaviour contract list, wrapper catalogue, per-page migration order, verification matrix, KI-05 plan, and the explicit "DO NOT add Skeleton" line. Phase 1 — tooling baseline. All exact-pinned per the plan: - @playwright/test@1.60.0 + playwright@1.60.0 + @axe-core/playwright@4.11.3 - rollup-plugin-visualizer@7.0.1 (wired behind ANALYZE=1) - @vitest/browser@4.1.6 + @vitest/browser-playwright@4.1.6 (provider) - vitest-browser-svelte@2.1.1 (runes-aware Svelte 5 bridge) - cargo-nextest installed globally New configs: playwright.config.ts (frontend-only, dev:frontend webServer, 900x700 + 1440x900 projects, visual baselines deferred), vitest.browser.config.js (separate from jsdom suite). New scripts: test:e2e, test:e2e:ui, test:browser, analyze, test:rust:fast, guard:no-skeleton. guard-no-skeleton.mjs walks package.json + package-lock + src/ for any @skeletonlabs reference and exits 1 if found — locks in the no-Skeleton hard rule for any future agent. Smoke baseline (tests/e2e/smoke.spec.ts): 16 tests passing across two viewports — app loads without Tauri runtime, keyboard nav, axe scan (color-contrast deferred to Phase 7 per docs/release/v0.1-contrast-audit.md), light/dark theme cycle, all three sensory zones (cave/energy/reset). 10 screenshots emitted to test-results/ as non-failing artefacts. Surfaced + fixed two browser-preview bugs while landing the baseline: - src/lib/utils/osInfo.ts: FALLBACK_BROWSER_INFO was evaluated at SSR module-load (navigator undefined → os: 'unknown'), and the UA check ran before navigator.platform — so Playwright's Windows-UA Chromium on a Linux runner detected as Windows, useCustomChrome went true, Titlebar mounted and tripped Tauri-only APIs. Now lazy-built per call; platform is the primary signal, UA only a fallback. - src/lib/components/Titlebar.svelte: defensive hasTauriRuntime() guard on every handler and the $effect. Titlebar should not crash if any future code path mounts it without Tauri. .gitignore: reports/, .playwright/, test-results/, playwright-report/. Per-phase gate green: npm run check (0/0), npm test (0/0), npm run test:e2e (16/16), npm run guard:no-skeleton (clean). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 3770815fbf |
agent: lumotia — v0.1 release-completion run
Closes the code-side v0.1 ship gate. All quality gates green: cargo fmt/clippy/test (~327 tests), npm check (0/0), vitest 13/13, scripts/dogfood-rebrand-drill.sh 8/8. Phase F — first-run onboarding promoted to v0.1 - FirstRunPage with skip-to-main + failure recovery + event recording - Six onboarding commands (record/list/has-completed + lumotia_events) - Storage migration v17 (onboarding_events + lumotia_events tables) UI hardening (in-scope items from v0.1-ui-hardening.md) - StatusPill + PostCaptureCard components, 21st preview entry - Sidebar recording-as-sacred-state (opacity + aria-disabled, reduced-motion) - Settings 6-section regroup + Help section + Activation log + Privacy toggle - Error-state copy sweep (DictationPage + SettingsPage, plain-language) - Global :focus-visible rule, textarea outlines restored - Ctrl+K / Ctrl+, / Escape bindings in +layout LLM resilience - rule_based_extract_tasks (regex-free imperative-verb extractor) + extract_tasks_with_fallback wrapper — task extraction never returns zero - tokio::time::timeout(120s) wraps cleanup/tags/tasks commands Release artefacts - LICENSE (canonical AGPL-3.0), CHANGELOG (Keep-a-Changelog format) - v0.1-release-notes, privacy-and-ai-use, install-warnings, tester-onboarding-kit, tester-acceptance-runbook, code-signing-setup, apple-silicon-rb08-runbook, virtual-audio-setup, v0.1-contrast-audit - Workspace versioning + AGPL spdx; npm exact-pin (10 ranges removed) - AppImage SHA-256 sidecar in build.yml - README v0.1 section + Reporting-issues; canonical repo slug Closure pass — items moved from human-required to code-complete - KI-02 Linux idle inhibit: zbus 5 → org.freedesktop.login1.Manager.Inhibit - KI-03 Windows sleep prevention: SetThreadExecutionState(ES_CONTINUOUS|...) - acquire/release_idle_inhibit Tauri commands, wired in DictationPage - Diagnostic-bundle frontend wire-up (Settings → Help button) - WCAG-AA contrast fix via .btn-filled-text utility (no token changes) - 8 destructive-action sites wrapped in plain-language confirm() guards - KNOWN-ISSUES.md + v0.1-known-limitations.md updated (KI-02/03 fixed) Scripts - pre-tag-verify.sh, tag-day.sh, smoke-linux + driver - parse-diagnostic-bundle.sh, parse-activation-log.py Per-item audit trail: docs/release/v0.1-completion-status.md Remaining: W-01…W-08 (signing certs, hardware probes, smoke matrix, tester recruitment) — see docs/release/v0.1-known-limitations.md. |
|||
| 1c4ac98504 |
agent: lumotia — Phase B.10 pin focusTimer expired-rehydrate startTick invariant
Phase B.10 audit of commit |
|||
| 206ac6219d |
agent: lumotia — Phase A.5 vitest scaffold + localStorageMigration unit tests
First frontend unit test framework on Lumotia. Pinned exact versions for supply-chain hygiene (matches the rust-toolchain.toml discipline from the |
|||
| 87e6248774 |
agent: code-atomiser-fix — trash view + restore button in HistoryPage (Rev-2 UI)
Adds a Live | Trash toggle to the HistoryPage header. The Trash tab
lists soft-deleted transcripts via the new list_trashed_transcripts
Tauri command and offers per-row Restore via restore_transcript.
Permanently-delete-from-trash is intentionally deferred — the 30-day
startup purge (TRANSCRIPT_TRASH_RETENTION_DAYS in src-tauri/src/lib.rs)
handles hard-removal until that UI lands. The retention policy is
surfaced in the panel header: Trashed items are kept for 30 days,
then permanently deleted on next app start.
Design notes:
- View toggle is a tablist of two pill buttons (Live | Trash); the
aria-selected attribute reflects the active mode.
- Switching to Trash triggers an effect that loads the list once.
Switching back to Live discards the trash data so stale rows
don't reappear on toggle.
- Live-mode header controls (Starred, Tag all untagged, Clear All)
are hidden in Trash mode and replaced with a Refresh button.
- Restore drops the row from the in-memory trash list rather than
splicing into history; the live store reloads from SQLite on its
own initialisation path, so we avoid drifting the in-memory shape
from the canonical source.
- The created timestamp is shown rather than the deletion
timestamp; deleted_at is not currently in the TranscriptDto and
expanding the DTO is out of scope for this fix.
- Audio files may already have been removed by delete_transcript's
best-effort filesystem cleanup, so restored text + metadata may
surface without playable audio (documented in the storage-layer
restore_transcript contract).
TODO(test): no Svelte component test framework wired in the repo
(vitest not installed).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 50d0715488 |
agent: code-atomiser-fix — type-the-word DELETE modal for clearAll (Rev-2 UI)
The prior clearAll UX was a 4-second inline arm-confirm: one click on
Clear All morphed into Confirm/Cancel pills; a second click within
the window wiped every transcript. With the soft-delete backend
(commit
|
|||
| a2b47db193 |
agent: code-atomiser-fix — restrict write_text_file_cmd to app data + download dirs (Trust-1)
The Tauri command `write_text_file_cmd` took an arbitrary `path: String` and flowed it straight into `tokio::fs::write`, with no main-window guard, no canonicalisation, and no scope check. A compromised webview could write anywhere the process had write access — overwriting shell init files, dropping a runner into `~/.config/autostart`, etc. The in-file comment "the dialog already constrains the user's choice" described an intended invariant the IPC surface never enforced. This change: - adds `ensure_main_window(&window)?` so only the main webview can invoke the command; - canonicalises the requested path's parent (rejecting nonexistent parents and resolving symlinks) before joining the filename; - asserts the canonical target sits inside an allowlisted base (app data, app local data, downloads, documents, desktop), so a `"../../etc/passwd"` payload — even one obtained by symlink trickery in the chosen save dir — is refused with a clear error. Six unit tests cover: outside-allowlist rejection, path-traversal rejection, nested inside-allowlist acceptance, plain inside-allowlist acceptance, nonexistent-parent rejection, and the pure `is_inside_any_base` prefix check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 5ba761a4b8 |
agent: code-atomiser-fix — focusTimer rehydrate startTick invariant (Race-10)
Lock the invariant: the already-expired branch of rehydrate() must call startTick() so the tick loop observes now >= completionFlashUntil and auto-clears the flash. The call was already present; this commit adds the inline comment so future edits cannot silently drop it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 6aa6a434fb |
agent: code-atomiser-fix — FirstRunPage unlisten on all exits (Race-9)
Move both Tauri listen() calls inside the try block with let-declared unlisten handles. A throw on the second listen() previously leaked the first subscription and the finally block could itself throw on an undefined unlistenParakeet, masking the original error. Finally now guards each handle before invoking it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| ab5f6ab995 |
agent: code-atomiser-fix — repair sed-scar provenance from 26c7307
The Magnotia->Lumotia rebrand commit
|
|||
| f093d18a5e |
agent: lumotia-rebrand — final residuals (HANDOVER + arch-map readme + ui-kit React fn)
Phase 15.1 final-grep residuals: - HANDOVER.md "Rebrand note" + Phase 10b row updated to reflect that the cascade completed 2026/05/13 (15 phases, both repos, QC-gated). - HANDOVER.md two surviving sed artefacts: "Lumotia -> Lumotia" line restored to "Magnotia -> Lumotia" historical context; MAGNOTIA_LLM_TEST_MODEL test gate -> LUMOTIA_LLM_TEST_MODEL. - src/design-system/ui_kits/index.html: MagnotiaApp React function -> LumotiaApp (sed boundary missed the no-separator boundary). - docs/architecture-map/README.md: MAGNOTIA_LLM_TEST_MODEL doc note. Preserved (audit trail): - docs/handovers/ — historical handover docs. - docs/superpowers/plans/2026-05-12-engine-slop-residuals.md and -area-a-storage-errors-survey.md — describe the slop-pass work using the names current at the time. - build/index.html, package-lock.json — regenerate on next build/install. cargo test --workspace: 339 pass / 0 fail. npm run check: 0 errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 26c7307607 |
agent: lumotia-rebrand — docs, scripts, root config, residuals
Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.
transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
-> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
as immutable audit trail). Includes architecture-map references
to magnotia_core::*, magnotia_storage::*, etc. now pointing at
lumotia_*; dev-setup.md tracing output examples (lumotia_startup
target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
("lumotia_task_sync"); magnotia_locale i18n localStorage key
renamed + migration shim added; CSS keyframe names
magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
to "lumotia era" earlier — restored).
Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
legacy detection strings in legacy_and_target_paths() so the
migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
— migration call sites reference the legacy magnotia keys
deliberately.
- docs/handovers/ — historical audit trail.
cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 681a9b26dc |
agent: lumotia-rebrand — frontend strings (svelte + i18n + design-system)
Phase 8 of the rebrand cascade. Every rendered string is now Lumotia;
no Magnotia surface visible in the UI.
Sweep replaced \bmagnotia\b -> lumotia and \bMagnotia\b -> Lumotia
across all .svelte / .ts / .js / .css / .html / .json (excluding
package-lock.json which regenerates, target/, build/, node_modules/).
Surfaces touched:
- src/app.css — design-token comment header and .magnotia-rh-* CSS
resize-handle class selectors (also the consuming elements in
components/ResizeHandles.svelte and src/routes/*/+layout.svelte).
- src/lib/i18n/locales/{en,de,es}.json — brand name in translations.
- src/lib/i18n/index.ts — header comment.
- src/lib/Sidebar.svelte and most pages under src/lib/pages/ +
src/lib/components/ — title bars, document titles, default
filenames (lumotia-YYYY-MM-DD.* etc), toast strings, error
messages, dialog headers.
- src/routes/+layout.svelte, +page.svelte, viewer/, float/, preview/.
- src/app.html page <title>.
- src/lib/utils/settingsMigrations.ts — fallback toast copy.
- src/design-system/{colors_and_type.css,SKILL.md,README.md,
ui_kits/{Sidebar.jsx,index.html}} — design-tokens, doc strings,
preview wordmark in the kit.
- package.json — name + description.
NOT touched (deferred / immutable):
- package-lock.json — regenerates on next npm install.
- The two migration-call sites in stores reference the legacy magnotia
keys deliberately; restored after the sweep clobbered them.
- docs/, README.md, HANDOVER.md — Phase 9 scope.
npm run check: 0 errors / 0 warnings (3958 files).
cargo test --workspace: 339 pass / 0 fail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 16081095e0 |
agent: lumotia-rebrand — localStorage keys + event channels migration
Phase 7 of the rebrand cascade. Persisted UI state + inter-window event
channels migrated from magnotia to lumotia naming, with one-shot
localStorage key migration so dogfooded UI state survives the rename.
src/lib/utils/localStorageMigration.ts (new):
- migrateLocalStorageKey(old, new): idempotent + crash-safe shim.
- If new key exists, removes old (lumotia value is authoritative).
- If only old exists, copies value to new key, removes old.
- If neither, no-op.
- migrateLocalStorageKeys(pairs): batch wrapper.
src/lib/stores/page.svelte.ts:
- 4 key constants renamed to lumotia_settings / lumotia_profiles /
lumotia_task_lists / lumotia_templates.
- BroadcastChannel name renamed to lumotia_task_lists.
- migrateLocalStorageKeys() called at module load before any read.
src/lib/stores/focusTimer.svelte.ts:
- STORAGE_KEY renamed to lumotia.focusTimer.v1.
- migrateLocalStorageKey() called at module load.
Event channels (magnotia: -> lumotia:) renamed across frontend + Rust:
- magnotia:toggle-recording (src/routes/+layout.svelte)
- magnotia:hotkey-pressed / -released (src-tauri/src/commands/hotkey.rs +
consumers)
- magnotia:open-wind-down (src-tauri/src/tray.rs + consumer)
- magnotia:llm-download-progress (src-tauri/src/commands/llm.rs)
- magnotia:preferences-changed (src/lib/stores/preferences.svelte.ts +
consumers)
- magnotia:start-timer (nudgeBus + dispatch sites)
- magnotia:focus-timer-{complete,cancelled} (focusTimer + nudgeBus)
- magnotia:microstep-generated (nudgeBus + dispatch sites)
- magnotia:step-completed (nudgeBus + dispatch sites)
- magnotia:task-{completed,uncompleted,deleted} (page.svelte.ts +
nudgeBus + consumers)
Storage-event filters in src/routes/{float,viewer,preview}/+layout@.svelte
updated to filter on lumotia_settings.
User-facing toast strings still say "Magnotia" — deferred to Phase 8
(frontend strings).
npm run check: 0 errors / 0 warnings (3958 files).
cargo test --workspace: 339 pass / 0 fail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| bc2db91520 |
agent: lumotia-rebrand — fix QC blockers for phase 0
Phase 0 QC found two real blockers in the baseline commits: 1. crates/llm/src/lib.rs:215 — early-break guard was inverted. The guard fired when grammar.is_some() (where grammar already enforces shape, making the check redundant) and was disabled for grammar.is_none() (the content-tags path that actually needs it). Flipped to grammar.is_none() so the JSON-envelope short-circuit fires for free-form JSON generation as the commit message implied. 2. src/lib/pages/FilesPage.svelte — handleExport() success path had no toast, asymmetric with DictationPage which does. Added the toasts import and a toasts.success() call after the native save so both export surfaces give consistent feedback. cargo test -p magnotia-llm --lib: 21 pass. npm run check: 0 errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 2ca01e7c9d |
feat(export): prefer native save dialog over browser blob fallback
DictationPage + FilesPage handleExport() now use Tauri save() + write_text_file_cmd when in the desktop runtime; browser blob path remains as fallback when hasTauriRuntime() is false. saveMarkdown.ts surfaces dialog errors via toasts. Adds txt to the extension map. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
|
|
fdf27db0a1 |
perf+fix: DMABUF default on Linux, popout ACL fixes, plugin version sync, JFK bench fixture
Bundled work from a low-end laptop (Ryzen 5 4650U / Vega 6 / Linux Mint
22.2 / X11) profiling pass.
perf: WEBKIT_DISABLE_DMABUF_RENDERER=1 default on all Linux
Previously only set on Wayland sessions. Empirically it's a
significant idle-cost win on integrated GPUs in either session type:
env-var matrix (release binary, 75s settle, 10s jiffies CPU sample)
showed magnotia idle CPU 12.30% → 2.80% of one core and idle GPU
17% → 10% on this hardware. Users can opt back in by exporting
WEBKIT_DISABLE_DMABUF_RENDERER=0. The Wayland-only XWayland
fallback (GDK_BACKEND=x11, WINIT_UNIX_BACKEND=x11) is unchanged.
fix: secondary-windows ACL — allow set-always-on-top
The float window's pin toggle calls setAlwaysOnTop() but the
secondary-windows capability didn't permit it, so the popout was
stuck always-on-top regardless of the pin state. Adds the
core:window:allow-set-always-on-top permission. Narrow scope.
fix: guard registerGlobalHotkey against non-main webviews
Cross-window settings sync via localStorage can re-fire the
$effect(() => settings.globalHotkey) callback inside popout webviews
where the main layout's registerGlobalHotkey is reachable. Adds an
early-return when the current window label is not "main", so the
popout doesn't trigger an ACL-denied register/unregister and the
user no longer sees a spurious "Hotkey not registered" toast when
popouts are open. Keeps the global-shortcut perm scoped to main.
build: pin @tauri-apps/api 2.10.1 + @tauri-apps/plugin-dialog 2.7.1
Match the Rust crate versions tauri-cli's version-mismatch check
enforces during release builds. Without this, `npm run tauri build`
exits 0 silently while emitting an Error and never producing
binaries.
test: add crates/transcription/tests/jfk_bench.rs
Reproducible RTF regression fixture. Env-gated on
MAGNOTIA_WHISPER_TEST_MODEL + MAGNOTIA_WHISPER_TEST_AUDIO so it
never runs in CI without setup. Loads the JFK WAV inline (no hound
dep), times model load + cold + warm transcribe, prints SUMMARY.
Baselines on this hardware:
--release --features whisper: cold RTF 0.054, warm 0.050, RSS 125 MB
--release --features whisper,whisper-vulkan: cold RTF 0.029, warm 0.028, RSS 125 MB
Vulkan on RADV/Vega 6 nearly halves transcription latency for
Whisper Tiny — useful baseline for Phase 10 hardware-recommendation
scoring.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
| 2dfd7167fd |
fix(a11y): Toggle aria-invalid briefly when async onChange rejects
When an async onChange handler rejects, the toggle snapped back to its previous value silently — screen reader users had no signal that the action failed, only that the toggle suddenly returned to its original state. Now aria-invalid="true" exposes the failure on the role=switch button for 1.5s after rejection, so assistive tech announces the error. Self-clears via setTimeout; no API change for callers. |
|||
| aecb191705 |
refactor(theme): tokenise hard-coded amber shadows and reconcile duplicate @font-face declarations
Hard-coded rgba(214,132,80,X) shadows were tied to the dark-theme accent and stayed off-hue in light mode (where the accent is a darker #a3683a). Six tokens added to app.css @theme and mirrored in the light-theme block plus design-system/colors_and_type.css: --shadow-accent-sm 0 0 8px 0.25 alpha Toggle on-state --shadow-accent-md 0 4px 16px 0.3 ModelDownloader card --shadow-accent-lg 0 4px 20px 0.3 DictationPage record button --shadow-accent-glow 0 0 8px 0.4 progress-bar glow --shadow-accent-pill 0 1px 4px 0.3 SegmentedButton pill --shadow-accent-raised 0 2px 8px 0.2 FilesPage browse tile Migrated seven sites: Toggle, SegmentedButton, ModelDownloader (x2), FilesPage (x2), DictationPage record button, SettingsPage locale pill. Focus-ring shadows (0_0_0_3px_rgba(...,0.1)) left alone — handled in parallel via the --accent-shadow-focus token. @font-face: app.css and colors_and_type.css both declare the same five fonts. Duplication is unavoidable because preview/*.html loads the design-system file directly without Vite, so it cannot share the runtime declarations. font-weight ranges and font-style reconciled to match exactly (Atkinson 200-800 not 400-700, JetBrains gains font-style: normal); src URLs intentionally differ (root-absolute vs relative). Comments added to both copies explaining the contract. |
|||
| f4c0635549 |
fix(a11y): guard sidebar-toggle keypress against custom widgets and scope transcript font-size effect
- Extend isInputFocused to also bail when document.activeElement sits inside a custom widget with role combobox/listbox/radio/switch/menuitem/tab so single-letter shortcuts like '[' do not collapse the sidebar while focused on SegmentedButton, ZonePicker, etc. - Move the transcript font-size CSS variable write from documentElement to document.body. Consumers inherit body styles, and scoping the write there avoids invalidating root-level styles every time fontSize changes. |
|||
| 736896c2b8 | fix(a11y): announce HistoryPage inline-confirm armed state and tag-chip pressed state | |||
| 9b17425bc9 | fix(a11y): name FilesPage drop zone region and denest Card | |||
| d3554951e0 | fix(a11y): privacy badge role/label and stronger search focus ring in light theme |