From 3cadbb0f820438322b574b53ecf41110c31f89ad Mon Sep 17 00:00:00 2001 From: Jake Date: Fri, 24 Apr 2026 20:45:47 +0100 Subject: [PATCH] feat(gamification): today count + sparkline on Tasks header Badge renders when today's count > 0. Sparkline renders when the setting is enabled and any of the last 7 days has a completion. Wrapped in a narrow aria-live region so increments announce without re-reading the rest of the header. Fix: converted todayCount from $derived module export to a getter function (Svelte 5 derived_invalid_export constraint). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/pages/TasksPage.svelte | 28 +++++++++++++++++++++++- src/lib/stores/completionStats.svelte.ts | 11 ++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/lib/pages/TasksPage.svelte b/src/lib/pages/TasksPage.svelte index de9c6af..d2a4eb6 100644 --- a/src/lib/pages/TasksPage.svelte +++ b/src/lib/pages/TasksPage.svelte @@ -8,8 +8,10 @@ taskLists, addTaskList, renameTaskList, deleteTaskList, settings, saveSettings, } from "$lib/stores/page.svelte.js"; + import { recentCompletions, todayCount } from "$lib/stores/completionStats.svelte"; import WipTaskList from '$lib/components/WipTaskList.svelte'; import EmptyState from '$lib/components/EmptyState.svelte'; + import CompletionSparkline from "$lib/components/CompletionSparkline.svelte"; import EnergyChip from '$lib/components/EnergyChip.svelte'; import { SquareCheck, Search, ExternalLink, ChevronLeft, ArrowUpDown, Plus, X, ChevronRight, Zap } from 'lucide-svelte'; import Card from "$lib/components/Card.svelte"; @@ -284,7 +286,31 @@
-

Tasks

+
+

Tasks

+ + +
+ {#if todayCount() > 0} + + {todayCount()} today + + {/if} + + {#if settings.showMomentumSparkline} + + {/if} +
+
+

Add tasks manually. Automatic extraction from your transcripts is coming.

diff --git a/src/lib/stores/completionStats.svelte.ts b/src/lib/stores/completionStats.svelte.ts index 68b786c..e6961a1 100644 --- a/src/lib/stores/completionStats.svelte.ts +++ b/src/lib/stores/completionStats.svelte.ts @@ -21,10 +21,13 @@ const DAYS = 7; export const recentCompletions = $state([]); -// Reactive derived value. Svelte 5 template consumers read it as a -// plain property (no parens) and it recomputes when recentCompletions -// changes. -export const todayCount = $derived(recentCompletions.at(-1)?.count ?? 0); +// Reactive getter. Svelte 5 does not allow exporting $derived at module +// level ("derived_invalid_export"), so we expose a function instead. +// Template consumers call todayCount() in reactive contexts and it +// recomputes when recentCompletions changes. +export function todayCount(): number { + return recentCompletions.at(-1)?.count ?? 0; +} export async function refresh(): Promise { if (!hasTauriRuntime()) return;