Tasks: TickTick history sync (export + idempotent import, start_at/time_zone); trackers ordered tasks, money, books with single-noun names
All checks were successful
Deploy production / deploy (push) Successful in 2m33s

This commit is contained in:
2026-10-24 03:05:05 +00:00
parent 9d08e6af23
commit 6a127de950
11 changed files with 15974 additions and 52 deletions

View File

@@ -59,6 +59,9 @@
let areaFilter = $state('all');
let priorityFilter = $state<'any' | 'flagged' | 'high'>('any');
let search = $state('');
// Long areas (years of TickTick history) render the first PAGE rows until expanded.
const PAGE = 40;
let expanded = $state<Record<string, boolean>>({});
const isOpen = (t: Task) => t.status === 'todo' || t.status === 'in_progress';
const matches = (t: Task) =>
@@ -431,8 +434,20 @@
<span style:width={`${(g.done / g.total) * 100}%`}></span>
</div>{/if}
<ul class="divide-y divide-[var(--site-border)]">
{#each g.tasks as t (t.id)}{@render taskRow(t, 0)}{/each}
{#each expanded[g.key] ? g.tasks : g.tasks.slice(0, PAGE) as t (t.id)}{@render taskRow(
t,
0
)}{/each}
</ul>
{#if g.tasks.length > PAGE && !expanded[g.key]}
<Button
type="button"
variant="ghost"
size="sm"
class="mt-2"
onclick={() => (expanded[g.key] = true)}>Show all {g.tasks.length}</Button
>
{/if}
</section>
{:else}
<p class="text-[var(--site-muted)]">No tasks match these filters.</p>