web(review): expandable Review group in sidebar, tabs become subitems

Mirrors the Tags affordance: chevron-only toggle, no /review landing
entry, navigation only via subitems (cause buckets + Stacks +
Cross-folder linked as /review?tab=<id>). Cause list reuses the
review-groups query so empty buckets stay hidden. The /review toolbar
drops the pill row and shows the active tab as a breadcrumb segment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 10:42:43 +02:00
parent e1707c314d
commit 981328faff
2 changed files with 104 additions and 57 deletions

View File

@@ -15,7 +15,6 @@
approve). The previous section is restored on unmount.
-->
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { createQuery } from '@tanstack/svelte-query';
import {
@@ -138,49 +137,18 @@
});
const activeGroup = $derived(groups.find((g) => g.cause === activeTab));
function setTab(id: Tab) {
const params = new URLSearchParams();
// First cause tab (if any) is the default — same convention as
// the old /review behaviour, so back-from-cross-folder lands on
// the user's review queue rather than the empty Stacks panel.
const defaultId = tabs[0]?.id;
if (defaultId !== undefined && id !== defaultId) params.set('tab', id);
void goto(`/review${params.size ? '?' + params : ''}`, {
keepFocus: true,
noScroll: true
});
}
const activeTabSpec = $derived(tabs.find((t) => t.id === activeTab));
</script>
<Toolbar>
<span class="rounded-md border border-border px-2 py-0.5 text-[11px] text-muted-foreground">
Review
</span>
{#if tabs.length > 0}
<div class="flex items-center gap-1">
{#each tabs as t (t.id)}
<button
type="button"
class="inline-flex items-center gap-1 rounded border px-2 py-0.5 text-[11px] {activeTab === t.id
? 'border-primary/40 bg-primary/10 text-primary'
: 'border-border text-muted-foreground hover:bg-accent hover:text-foreground'}"
onclick={() => setTab(t.id)}
>
<span>{t.label}</span>
{#if t.count !== undefined}
<span
class="flex h-4 min-w-4.5 items-center justify-center rounded px-1 text-[10px] tabular-nums {activeTab ===
t.id
? 'bg-primary/15 text-primary'
: 'bg-secondary text-muted-foreground'}"
>
{t.count}
</span>
{/if}
</button>
{/each}
</div>
{#if activeTabSpec}
<span class="text-[11px] font-medium">{activeTabSpec.label}</span>
{#if activeTabSpec.count !== undefined}
<span class="text-[11px] text-muted-foreground">{activeTabSpec.count}</span>
{/if}
{/if}
{#snippet trailing()}
<div