refactor(todo): merge TagStrip into unified filter strip

Combine the separate TagStrip and FilterStrip into one unified filter
bar. Tag chips now appear as colored pills alongside priority filters,
sort options, and completed toggle — all toggled by a single Filter pill.

- Add showTags prop + tag chip rendering to TaskFilters strip variant
- Remove TagStrip component usage and Tags pill from PillNav
- Remove showKanbanNav (dead /kanban reference)
- One pill, one strip, no duplication

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-31 13:07:34 +02:00
parent 101f20ec34
commit 52e09e4ac0
2 changed files with 53 additions and 55 deletions

View file

@ -1,5 +1,4 @@
<script lang="ts">
import { goto } from '$app/navigation';
import type { TaskPriority } from '@todo/shared';
import { getContext } from 'svelte';
import type { Project } from '@todo/shared';
@ -14,7 +13,6 @@
CaretDown,
Check,
CheckCircle,
Columns,
DotsThree,
MagnifyingGlass,
X,
@ -47,7 +45,7 @@
showSearch?: boolean;
showLabels?: boolean;
showCompleted?: boolean;
showKanbanNav?: boolean;
showTags?: boolean;
// Completed toggle
isCompletedVisible?: boolean;
@ -72,7 +70,7 @@
showSearch = false,
showLabels = false,
showCompleted = false,
showKanbanNav = false,
showTags = false,
isCompletedVisible = false,
onToggleCompleted,
}: Props = $props();
@ -140,12 +138,21 @@
<span class="pill-label">Filter</span>
</button>
<!-- Kanban View Button -->
{#if showKanbanNav}
<button class="glass-pill" onclick={() => goto('/kanban')} title="Kanban-Ansicht">
<Columns size={18} />
<span class="pill-label">Kanban</span>
</button>
<!-- Tag Chips -->
{#if showTags && tagsCtx.value.length > 0}
{#each tagsCtx.value as tag (tag.id)}
<button
class="tag-chip glass-pill"
class:selected={selectedLabelIds.includes(tag.id)}
onclick={() => toggleLabel(tag.id)}
title={tag.name}
style="--tag-color: {tag.color || '#6b7280'}"
>
<span class="tag-dot"></span>
<span class="pill-label">{tag.name}</span>
</button>
{/each}
<span class="strip-divider"></span>
{/if}
<!-- Priority Filter Pills -->
@ -491,6 +498,39 @@
color: #8b5cf6;
}
/* Tag chips */
.tag-chip .tag-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: var(--tag-color);
flex-shrink: 0;
}
.tag-chip.selected {
background: var(--tag-color) !important;
border-color: var(--tag-color) !important;
}
.tag-chip.selected .tag-dot {
background-color: white;
}
.tag-chip.selected .pill-label {
color: white;
}
.strip-divider {
width: 1px;
height: 24px;
background: rgba(0, 0, 0, 0.1);
flex-shrink: 0;
}
:global(.dark) .strip-divider {
background: rgba(255, 255, 255, 0.15);
}
/* Priority pills */
.priority-pill.selected {
background: var(--priority-color) !important;

View file

@ -3,12 +3,7 @@
import { page } from '$app/stores';
import { setContext } from 'svelte';
import { locale } from 'svelte-i18n';
import {
PillNavigation,
QuickInputBar,
ImmersiveModeToggle,
TagStrip,
} from '@manacore/shared-ui';
import { PillNavigation, QuickInputBar, ImmersiveModeToggle } from '@manacore/shared-ui';
import {
SplitPaneContainer,
setSplitPanelContext,
@ -252,13 +247,6 @@
todoSettings.toggleFilterStrip();
}
// TagStrip visibility (toggle via Tags button in PillNav)
let isTagStripVisible = $state(true);
function handleTagStripToggle() {
isTagStripVisible = !isTagStripVisible;
}
// View mode switching (state-based, not route-based)
let viewTabGroup = $derived<PillNavElement>({
type: 'tabs' as const,
@ -287,13 +275,6 @@
onClick: handleFilterToggle,
active: isFilterStripVisible,
},
{
href: '/',
label: 'Tags',
icon: 'tag',
onClick: handleTagStripToggle,
active: isTagStripVisible,
},
...($page.url.pathname === '/' || $page.url.pathname === ''
? [
{
@ -488,30 +469,7 @@
ariaLabel="Hauptnavigation"
/>
<!-- TagStrip (above PillNav, toggled via Tags pill) -->
{#if isTagStripVisible}
<TagStrip
tags={allTags.value.map((t) => ({
id: t.id,
name: t.name,
color: t.color || '#6b7280',
}))}
selectedIds={viewStore.filterLabelIds}
onToggle={(tagId) => {
const current = viewStore.filterLabelIds;
if (current.includes(tagId)) {
viewStore.setFilterLabelIds(current.filter((id) => id !== tagId));
} else {
viewStore.setFilterLabelIds([...current, tagId]);
}
}}
onClear={() => viewStore.setFilterLabelIds([])}
managementHref="/tags"
aboveFilterStrip={isFilterStripVisible}
/>
{/if}
<!-- TaskFilters strip (shown when Filter pill is active in PillNav) -->
<!-- Unified filter strip (tags + priorities + sort, toggled via Filter pill) -->
{#if isFilterStripVisible}
<TaskFilters
variant="strip"
@ -528,7 +486,7 @@
onSortChange={(s: SortBy) => viewStore.setSort(s, viewStore.sortOrder)}
showSort={true}
showCompleted={true}
showKanbanNav={true}
showTags={true}
isCompletedVisible={viewStore.showCompleted}
onToggleCompleted={() => viewStore.toggleShowCompleted()}
/>