---
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