feat(tts): Phase 4 — Read Page Aloud with OS-native voices
Platform-dispatched TTS (spd-say + espeak-ng fallback on Linux, say on macOS, PowerShell System.Speech on Windows) with a shared SpeakerButton component. Tap to speak, tap again to stop; only one button speaks at a time so two surfaces don't talk over each other. Text always travels via argv (or a PowerShell here-string delivered through -EncodedCommand on Windows) so user content never enters a shell string. Mount points: DictationPage transcript footer, transcript viewer header, per-step in MicroSteps. Settings gains a "Read aloud" accordion with voice picker (lazy-loaded from the OS synth), rate slider 0.5-2.0x, and a British-English test utterance. Rust tests cover rate mapping, NaN handling, and Windows here-string terminator safety. No pause/resume, no SSML, no cloud voices — that stays out of scope per the Layer-1 roadmap.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { ListTree, Check, Timer, Loader2, ThumbsUp, ThumbsDown, Pencil } from 'lucide-svelte';
|
||||
import { profilesStore } from '$lib/stores/profiles.svelte.ts';
|
||||
import SpeakerButton from '$lib/components/SpeakerButton.svelte';
|
||||
|
||||
let { parentTaskId, parentTaskText = '', reduceMotion = false } = $props();
|
||||
|
||||
@@ -270,6 +271,12 @@
|
||||
>
|
||||
<Pencil size={10} aria-hidden="true" />
|
||||
</button>
|
||||
<span
|
||||
class="opacity-0 group-hover:opacity-100"
|
||||
style={reduceMotion ? '' : 'transition: opacity var(--duration-ui)'}
|
||||
>
|
||||
<SpeakerButton text={step.text} label="Read this step aloud" size={10} />
|
||||
</span>
|
||||
<button
|
||||
class="opacity-0 group-hover:opacity-100 flex items-center gap-1 text-[10px] text-text-tertiary hover:text-accent"
|
||||
onclick={() => startTimer(step.id)}
|
||||
|
||||
Reference in New Issue
Block a user