Files
taskplaner/.planning/phases/05-search/05-01-PLAN.md
Thomas Richter f6144f4edf docs(05): create phase plan
Phase 05: Search
- 3 plans in 2 waves
- Wave 1: 05-01 (UI components), 05-02 (filtering logic) — parallel
- Wave 2: 05-03 (integration + recent searches + "/" shortcut)
- Ready for execution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 14:15:38 +01:00

222 lines
6.5 KiB
Markdown

---
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"
---
<objective>
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.
</objective>
<execution_context>
@/home/tho/.claude/get-shit-done/workflows/execute-plan.md
@/home/tho/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.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
</context>
<tasks>
<task type="auto">
<name>Task 1: Create search types and utility functions</name>
<files>src/lib/types/search.ts</files>
<action>
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
};
}
```
</action>
<verify>TypeScript compiles without errors: `npx tsc --noEmit`</verify>
<done>SearchFilters interface exported and importable from other files</done>
</task>
<task type="auto">
<name>Task 2: Create SearchBar component with debounced input</name>
<files>src/lib/components/SearchBar.svelte</files>
<action>
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
</action>
<verify>Component renders without errors when imported</verify>
<done>SearchBar accepts text input and exposes debounced value via $bindable prop</done>
</task>
<task type="auto">
<name>Task 3: Create FilterBar component with type, tag, and date controls</name>
<files>src/lib/components/FilterBar.svelte</files>
<action>
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
</action>
<verify>Component renders with all filter controls visible and interactive</verify>
<done>FilterBar displays type toggle, tag selector, date range controls, and clear button (when filters active)</done>
</task>
</tasks>
<verification>
- `npm run check` passes (Svelte and TypeScript)
- SearchBar and FilterBar import without errors
- Type definitions are correct and exported
</verification>
<success_criteria>
- 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
</success_criteria>
<output>
After completion, create `.planning/phases/05-search/05-01-SUMMARY.md`
</output>