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>
This commit is contained in:
221
.planning/phases/05-search/05-01-PLAN.md
Normal file
221
.planning/phases/05-search/05-01-PLAN.md
Normal file
@@ -0,0 +1,221 @@
|
||||
---
|
||||
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>
|
||||
Reference in New Issue
Block a user