From 0c34a29367b45ec41468f83e3a2342aad8849ad5 Mon Sep 17 00:00:00 2001 From: Jake Date: Fri, 24 Apr 2026 11:50:45 +0100 Subject: [PATCH] =?UTF-8?q?feat(focus-timer):=20Phase=201=20=E2=80=94=20vi?= =?UTF-8?q?sual=20countdown=20ring=20+=20just-start=20timer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the Core MVP gap in docs/brief/feature-set.md ("visual time representation") and wires the dangling kon:start-timer emit that MicroSteps.svelte has been firing into the void since the stub was written. Implements phase 1 of the 2026-04-23 feature-complete roadmap. New: - src/lib/stores/focusTimer.svelte.ts — singleton timer store with localStorage persistence so a timer started in Dictation survives page nav, window close, and reopen. Gentle WebAudio chime at completion (no bundled asset). 250 ms tick. Completion flash for 3 s before auto-clear. - src/lib/components/FocusTimer.svelte — floating top-right overlay with SVG progress ring (shrinking colour: accent -> warning in the final 15% -> success on completion). Cancel + "+1 min" on hover. Renders nothing when idle. Wired in +layout.svelte next to ToastViewport. Two triggers now in the app: - MicroSteps row 2-min button (pre-existing emit, previously no listener) - WipTaskList row 5-min button (new; the brief's "just-start" from the Now column) Respects prefers-reduced-motion via the existing [data-reduce-motion] attribute. Out of scope, carried to later phases: rhythmic voice anchoring (Phase 6), custom-duration picker, multi-timer UI, native OS notification (deferred to Phase 6 with the full nudge pipeline). --- src/lib/components/FocusTimer.svelte | 270 ++++++++++++++++++++++++++ src/lib/components/WipTaskList.svelte | 18 +- src/lib/stores/focusTimer.svelte.ts | 230 ++++++++++++++++++++++ src/routes/+layout.svelte | 8 + 4 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 src/lib/components/FocusTimer.svelte create mode 100644 src/lib/stores/focusTimer.svelte.ts diff --git a/src/lib/components/FocusTimer.svelte b/src/lib/components/FocusTimer.svelte new file mode 100644 index 0000000..4fcdc0f --- /dev/null +++ b/src/lib/components/FocusTimer.svelte @@ -0,0 +1,270 @@ + + +{#if focusTimer.active || focusTimer.showingCompletionFlash} +
+
+ +
+ {#if focusTimer.showingCompletionFlash} + done + {:else} + {formatRemaining(focusTimer.remainingMs)} + {/if} +
+
+ +
+ {#if focusTimer.showingCompletionFlash} + + {:else} + + + {/if} +
+ + {#if focusTimer.label} + + {/if} +
+{/if} + + diff --git a/src/lib/components/WipTaskList.svelte b/src/lib/components/WipTaskList.svelte index fe416e6..eca3863 100644 --- a/src/lib/components/WipTaskList.svelte +++ b/src/lib/components/WipTaskList.svelte @@ -1,7 +1,13 @@