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>
This commit is contained in:
@@ -953,42 +953,49 @@
|
|||||||
|
|
||||||
The v0.2 path stays unchanged for non-quietware users.
|
The v0.2 path stays unchanged for non-quietware users.
|
||||||
================================================================= -->
|
================================================================= -->
|
||||||
<LumotiaPageSkeleton primaryBleed>
|
<LumotiaPageSkeleton>
|
||||||
{#snippet header()}
|
{#snippet header()}
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-5">
|
||||||
|
<!-- Record control + status block grouped tightly so they read
|
||||||
|
as one capture component. Timer pushed to far right. -->
|
||||||
|
<div class="flex items-center gap-3 flex-1 min-w-0">
|
||||||
<button
|
<button
|
||||||
class="relative flex items-center justify-center w-[72px] h-[72px] rounded-full shrink-0
|
class="relative flex items-center justify-center w-[64px] h-[64px] rounded-full shrink-0
|
||||||
text-[var(--button-record-fg)]
|
text-[var(--button-record-fg)]
|
||||||
focus-visible:outline-none focus-visible:ring-[var(--wire-width-focus,2px)]
|
focus-visible:outline-none focus-visible:ring-[var(--wire-width-focus,2px)]
|
||||||
focus-visible:ring-[var(--button-record-bg)] focus-visible:ring-offset-2
|
focus-visible:ring-[var(--button-record-bg)] focus-visible:ring-offset-2
|
||||||
|
transition-colors duration-150
|
||||||
{page.recording
|
{page.recording
|
||||||
? 'bg-danger animate-pulse-warm'
|
? 'bg-danger animate-pulse-warm'
|
||||||
: modelLoading
|
: modelLoading
|
||||||
? 'bg-warning opacity-60 cursor-wait'
|
? 'bg-warning/30 cursor-wait border border-[color-mix(in_srgb,var(--color-caution)_55%,transparent)]'
|
||||||
: !tauriRuntimeAvailable
|
: !tauriRuntimeAvailable
|
||||||
? 'bg-bg-elevated text-text-tertiary cursor-not-allowed'
|
? 'bg-transparent border-2 border-[color-mix(in_srgb,var(--button-record-bg)_45%,transparent)] cursor-not-allowed opacity-80'
|
||||||
: 'bg-[var(--button-record-bg)] hover:bg-[var(--button-record-border)]'}"
|
: 'bg-[var(--button-record-bg)] hover:bg-[var(--button-record-border)]'}"
|
||||||
onclick={toggleRecording}
|
onclick={toggleRecording}
|
||||||
disabled={modelLoading || !tauriRuntimeAvailable}
|
disabled={modelLoading || !tauriRuntimeAvailable}
|
||||||
aria-label={page.recording ? "Stop recording" : "Start recording"}
|
aria-label={page.recording ? "Stop recording" : (tauriRuntimeAvailable ? "Start recording" : "Record (desktop app only)")}
|
||||||
>
|
>
|
||||||
{#if page.recording}
|
{#if page.recording}
|
||||||
<span class="w-[20px] h-[20px] rounded-[3px] bg-white"></span>
|
<span class="w-[18px] h-[18px] rounded-[3px] bg-white"></span>
|
||||||
{:else if modelLoading}
|
{:else if modelLoading}
|
||||||
<Loader2 size={24} class="animate-spin" aria-hidden="true" />
|
<Loader2 size={22} class="animate-spin text-[var(--color-caution)]" aria-hidden="true" />
|
||||||
|
{:else if !tauriRuntimeAvailable}
|
||||||
|
<!-- Disabled but still reads as "record": muted red dot. -->
|
||||||
|
<span class="w-[18px] h-[18px] rounded-full bg-[color-mix(in_srgb,var(--button-record-bg)_55%,transparent)]"></span>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="w-[20px] h-[20px] rounded-full bg-white/90"></span>
|
<span class="w-[18px] h-[18px] rounded-full bg-white/90"></span>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
<h1 class="font-display italic text-[22px] text-text leading-tight">
|
<h1 class="text-[18px] font-medium text-text leading-tight">
|
||||||
{#if page.recording}Recording…
|
{#if page.recording}Recording…
|
||||||
{:else if modelLoading}Loading model
|
{:else if modelLoading}Loading model
|
||||||
{:else if !tauriRuntimeAvailable}Desktop preview mode
|
{:else if !tauriRuntimeAvailable}Desktop preview mode
|
||||||
{:else}Ready to capture
|
{:else}Ready to capture
|
||||||
{/if}
|
{/if}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-[13px] text-text-secondary mt-0.5">
|
<p class="text-[12px] text-text-secondary mt-0.5">
|
||||||
{#if page.recording}Press to stop, or use the global hotkey.
|
{#if page.recording}Press to stop, or use the global hotkey.
|
||||||
{:else if modelLoading}One moment.
|
{:else if modelLoading}One moment.
|
||||||
{:else if !tauriRuntimeAvailable}Local transcription needs the Lumotia desktop app.
|
{:else if !tauriRuntimeAvailable}Local transcription needs the Lumotia desktop app.
|
||||||
@@ -996,16 +1003,10 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-[20px] font-mono tabular-nums text-text-secondary shrink-0">
|
</div>
|
||||||
|
<div class="text-[18px] font-mono tabular-nums text-text-secondary shrink-0">
|
||||||
{page.timerText || "00:00"}
|
{page.timerText || "00:00"}
|
||||||
</div>
|
</div>
|
||||||
{#if page.recording}
|
|
||||||
<LumotiaStatusPill status="recording" />
|
|
||||||
{:else if modelLoading}
|
|
||||||
<LumotiaStatusPill status="transcribing" />
|
|
||||||
{:else if tauriRuntimeAvailable}
|
|
||||||
<LumotiaStatusPill status="ready" />
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
@@ -1022,7 +1023,11 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{#snippet primary()}
|
{#snippet primary()}
|
||||||
<div class="h-full flex flex-col px-8 py-6">
|
<div class="h-full flex flex-col">
|
||||||
|
<!-- Transcript canvas. Action dock below sits inside the same
|
||||||
|
surface so it reads as transcript actions, not a generic
|
||||||
|
page footer. -->
|
||||||
|
<div class="flex-1 flex flex-col px-8 py-8 min-h-0 overflow-hidden">
|
||||||
{#if !transcript.trim()}
|
{#if !transcript.trim()}
|
||||||
<div class="flex-1 flex flex-col items-center justify-center text-center gap-4 text-text-tertiary">
|
<div class="flex-1 flex flex-col items-center justify-center text-center gap-4 text-text-tertiary">
|
||||||
<Mic size={56} class="opacity-50" aria-hidden="true" />
|
<Mic size={56} class="opacity-50" aria-hidden="true" />
|
||||||
@@ -1036,10 +1041,7 @@
|
|||||||
>{transcript}</div>
|
>{transcript}</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
<div class="flex items-center gap-2 justify-end px-6 py-3 border-t border-border-subtle bg-bg-elevated/40">
|
||||||
|
|
||||||
{#snippet actionBar()}
|
|
||||||
<div class="flex items-center gap-2 justify-end">
|
|
||||||
<LumotiaButton variant="tertiary" size="sm" onclick={copyAll} disabled={!transcript.trim()}>Copy</LumotiaButton>
|
<LumotiaButton variant="tertiary" size="sm" onclick={copyAll} disabled={!transcript.trim()}>Copy</LumotiaButton>
|
||||||
<LumotiaButton variant="primary" size="sm" onclick={saveTypedText} disabled={!transcript.trim()}>Save</LumotiaButton>
|
<LumotiaButton variant="primary" size="sm" onclick={saveTypedText} disabled={!transcript.trim()}>Save</LumotiaButton>
|
||||||
<LumotiaButton variant="secondary" size="sm" onclick={manualExtractTasks} disabled={!transcript.trim()}>Extract Tasks</LumotiaButton>
|
<LumotiaButton variant="secondary" size="sm" onclick={manualExtractTasks} disabled={!transcript.trim()}>Extract Tasks</LumotiaButton>
|
||||||
@@ -1057,12 +1059,12 @@
|
|||||||
onclick={() => invoke("open_viewer_window").catch(() => {})}
|
onclick={() => invoke("open_viewer_window").catch(() => {})}
|
||||||
>Open Viewer</LumotiaButton>
|
>Open Viewer</LumotiaButton>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{#snippet metadata()}
|
{#snippet metadata()}
|
||||||
<div class="flex items-center justify-between gap-4">
|
<div class="flex items-center justify-end">
|
||||||
<span>Smart · {settings.modelSize} · {tauriRuntimeAvailable ? "Local only" : "Browser preview"}</span>
|
{settings.formatMode} · {settings.modelSize} · {tauriRuntimeAvailable ? "Local only" : "Browser preview"} · {page.activeProfile === "None" ? "No profile" : page.activeProfile}
|
||||||
<span>{settings.formatMode} · {page.activeProfile === "None" ? "No profile" : page.activeProfile}</span>
|
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</LumotiaPageSkeleton>
|
</LumotiaPageSkeleton>
|
||||||
|
|||||||
@@ -118,7 +118,9 @@
|
|||||||
role={ariaRole}
|
role={ariaRole}
|
||||||
class="rounded-r-lg rounded-l-sm border border-l-4 text-[13px] flex gap-2.5
|
class="rounded-r-lg rounded-l-sm border border-l-4 text-[13px] flex gap-2.5
|
||||||
{slim ? 'px-3 py-2 items-center' : 'px-4 py-3 items-start'}
|
{slim ? 'px-3 py-2 items-center' : 'px-4 py-3 items-start'}
|
||||||
{tonePal.bar} {tonePal.border} {tonePal.bg} {counterline ? tonePal.shadow : ''} {classes}"
|
{tonePal.bar}
|
||||||
|
{slim ? 'border-border-subtle' : tonePal.border}
|
||||||
|
{tonePal.bg} {counterline ? tonePal.shadow : ''} {classes}"
|
||||||
>
|
>
|
||||||
<ToneIcon size={slim ? 14 : 16} class="shrink-0 {slim ? '' : 'mt-0.5'} {tonePal.iconColor}" aria-hidden="true" />
|
<ToneIcon size={slim ? 14 : 16} class="shrink-0 {slim ? '' : 'mt-0.5'} {tonePal.iconColor}" aria-hidden="true" />
|
||||||
<div class="flex-1 min-w-0 leading-relaxed text-text">
|
<div class="flex-1 min-w-0 leading-relaxed text-text">
|
||||||
|
|||||||
Reference in New Issue
Block a user