--- phase: 05-search plan: 01 type: execute wave: 1 depends_on: [] files_modified: - src/lib/components/SearchBar.svelte - src/lib/components/FilterBar.svelte - src/lib/types/search.ts autonomous: true must_haves: truths: - "Search input is visible at top of page" - "Filter controls (type, tags, date) are visible alongside search" - "User can type in search input" - "User can interact with filter controls" artifacts: - path: "src/lib/components/SearchBar.svelte" provides: "Text search input with debounced value binding" min_lines: 40 - path: "src/lib/components/FilterBar.svelte" provides: "Filter controls for type, tags, and date range" min_lines: 60 - path: "src/lib/types/search.ts" provides: "SearchFilters interface and default values" exports: ["SearchFilters", "defaultFilters", "hasActiveFilters"] key_links: - from: "src/lib/components/SearchBar.svelte" to: "parent component" via: "$bindable value prop" pattern: "value = \\$bindable" - from: "src/lib/components/FilterBar.svelte" to: "parent component" via: "onchange callback prop" pattern: "onchange.*SearchFilters" --- Create the search and filter UI components with type definitions. Purpose: Establish the visual search/filter interface that users interact with. These components emit filter state changes but do not perform filtering themselves. Output: SearchBar.svelte, FilterBar.svelte, and search.ts type definitions ready for integration. @/home/tho/.claude/get-shit-done/workflows/execute-plan.md @/home/tho/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/05-search/05-CONTEXT.md @.planning/phases/05-search/05-RESEARCH.md @src/lib/components/EntryList.svelte @src/lib/stores/preferences.svelte.ts Task 1: Create search types and utility functions src/lib/types/search.ts Create the SearchFilters interface and related utilities: ```typescript export interface SearchFilters { query: string; tags: string[]; type: 'task' | 'thought' | 'all'; dateRange: { start: string | null; end: string | null; }; } export const defaultFilters: SearchFilters = { query: '', tags: [], type: 'all', dateRange: { start: null, end: null } }; export function hasActiveFilters(filters: SearchFilters): boolean { return ( filters.query.length >= 2 || filters.tags.length > 0 || filters.type !== 'all' || filters.dateRange.start !== null || filters.dateRange.end !== null ); } // Date preset helper for quick date range selection export function getDatePreset(preset: 'today' | 'week' | 'month'): { start: string; end: string } { const now = new Date(); const end = now.toISOString().split('T')[0]; let start: Date; switch (preset) { case 'today': start = now; break; case 'week': start = new Date(now); start.setDate(start.getDate() - 7); break; case 'month': start = new Date(now); start.setMonth(start.getMonth() - 1); break; } return { start: start.toISOString().split('T')[0], end }; } ``` TypeScript compiles without errors: `npx tsc --noEmit` SearchFilters interface exported and importable from other files Task 2: Create SearchBar component with debounced input src/lib/components/SearchBar.svelte Create SearchBar.svelte with: - Text input with placeholder 'Search entries... (press "/")' - Debounced value binding (300ms delay, using $effect cleanup pattern) - Only trigger search when query >= 2 characters OR when cleared to empty - Bindable value prop for parent to receive debounced search term - Styling: full width, px-4 py-2, border rounded-lg, focus ring Props interface: ```typescript interface Props { value: string; // bindable - the debounced search query } ``` Implementation notes: - Use internal $state for inputValue (immediate user typing) - Use $effect with setTimeout/clearTimeout for debounce - Update the bound value only after debounce completes - Match existing Tailwind styling patterns from other components Component renders without errors when imported SearchBar accepts text input and exposes debounced value via $bindable prop Task 3: Create FilterBar component with type, tag, and date controls src/lib/components/FilterBar.svelte Create FilterBar.svelte with: 1. Type filter - three-state toggle (All / Tasks / Thoughts): - Use button group with active state highlighting - Default: 'all' 2. Tag filter - multi-select from available tags: - Re-use existing Svelecte pattern from TagInput.svelte - Multiple selection enabled - AND logic (handled by filtering logic in Plan 02) 3. Date range filter: - Quick preset buttons: Today, This week, This month - Custom range: two native date inputs (start/end) - Use getDatePreset helper from search.ts 4. Clear/Reset button: - Only visible when hasActiveFilters() returns true - Resets all filters to defaultFilters Props interface: ```typescript interface Props { filters: SearchFilters; availableTags: Tag[]; onchange: (filters: SearchFilters) => void; } ``` Layout: - Horizontal flex wrap on desktop - Stack vertically on mobile (use flex-wrap and gap) - Each filter group visually separated Styling notes: - Match existing component patterns (border-gray-200, rounded-lg, focus:ring-2) - Active type button: bg-blue-100 text-blue-700 - Inactive type button: bg-white text-gray-600 hover:bg-gray-50 Component renders with all filter controls visible and interactive FilterBar displays type toggle, tag selector, date range controls, and clear button (when filters active) - `npm run check` passes (Svelte and TypeScript) - SearchBar and FilterBar import without errors - Type definitions are correct and exported - SearchBar.svelte renders with debounced text input - FilterBar.svelte renders with all filter controls (type, tags, date range) - Clear button appears only when filters are active - All components follow existing project patterns After completion, create `.planning/phases/05-search/05-01-SUMMARY.md`