feat: shared backlog filter popover + sprint header polish (v1.3.3) (#184)

- Move sprint switcher into sprint header, centered between title and actions
- Extract BacklogFilterPopover as shared component used by sprint and product backlog
- Add sort options (code/priority/status) with single-pill asc/desc toggle
- Default sprint backlog status filter to OPEN, remove "alleen niet klaar" button
- Persist collapsed state and filter popover open in localStorage
- Fix hydration flicker: defer localStorage read to useEffect with prefsLoaded gate for writes
- Increase sprint switcher text size for readability

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-10 11:12:04 +02:00 committed by GitHub
parent a9b53dedf0
commit 1f8cbacb0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 424 additions and 330 deletions

View file

@ -73,7 +73,7 @@ export function SprintSwitcher({
<TooltipProvider>
<Tooltip>
<TooltipTrigger
className="text-xs text-muted-foreground/50 px-2 cursor-not-allowed select-none"
className="text-sm text-muted-foreground/50 px-2 cursor-not-allowed select-none"
aria-disabled="true"
>
Geen sprints
@ -90,7 +90,7 @@ export function SprintSwitcher({
<DropdownMenu>
<DropdownMenuTrigger
disabled={isPending}
className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors px-2 py-1 rounded-md hover:bg-surface-container focus:outline-none"
className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors px-2 py-1 rounded-md hover:bg-surface-container focus:outline-none"
>
<span className="truncate max-w-[160px]">
{activeSprint ? activeSprint.code : 'Selecteer sprint'}
@ -98,7 +98,7 @@ export function SprintSwitcher({
{activeSprint && (
<span
className={cn(
'text-[10px]',
'text-sm',
buildingSet.has(activeSprint.id) ? 'text-warning' : 'text-muted-foreground',
)}
>
@ -114,7 +114,7 @@ export function SprintSwitcher({
e.preventDefault()
setShowClosed(v => !v)
}}
className="flex items-center gap-2 w-full px-2 py-1.5 text-xs text-muted-foreground hover:bg-surface-container rounded-md"
className="flex items-center gap-2 w-full px-2 py-1.5 text-sm text-muted-foreground hover:bg-surface-container rounded-md"
>
<span
className={cn(
@ -128,7 +128,7 @@ export function SprintSwitcher({
</button>
<DropdownMenuSeparator />
{visibleSprints.length === 0 ? (
<div className="px-2 py-2 text-xs text-muted-foreground/70 italic">
<div className="px-2 py-2 text-sm text-muted-foreground/70 italic">
Geen open sprints
</div>
) : (
@ -141,11 +141,11 @@ export function SprintSwitcher({
s.id === activeSprint?.id && 'bg-primary-container text-primary-container-foreground font-medium',
)}
>
<span className="text-xs font-medium shrink-0">{s.code}</span>
<span className="text-xs truncate flex-1">{s.sprint_goal}</span>
<span className="text-sm font-medium shrink-0">{s.code}</span>
<span className="text-sm truncate flex-1">{s.sprint_goal}</span>
<span
className={cn(
'text-[10px] shrink-0',
'text-sm shrink-0',
buildingSet.has(s.id) ? 'text-warning' : 'text-muted-foreground',
)}
>