Moves phases 08–11 execution artifacts from .planning/phases/ to .planning/milestones/v0.2-phases/ to keep .planning/phases/ clean for the next milestone. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9.4 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10-ux-interaction | 02 | execute | 0 |
|
true |
|
|
Purpose: Per D-06/D-07, every zero-content context gets its own icon + headline + subtext + optional CTA slot. No per-view "no items" text remains in the app after Wave 1 wiring.
Output: EmptyState.vue (Options API, props: icon/headline/subtext/size, #cta slot) + Vitest unit tests covering prop rendering, slot rendering, and size variants.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@CLAUDE.md @.planning/phases/10-ux-interaction/10-CONTEXT.md @.planning/phases/10-ux-interaction/10-RESEARCH.md @.planning/phases/10-ux-interaction/10-PATTERNS.md @frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js @frontend/src/views/SharedView.vue @frontend/src/components/layout/AppSidebar.vue Per D-06, D-07 (CONTEXT.md): - Props: - `icon` (String, default null) — name from AppIcon registry (e.g. 'folder', 'inbox', 'cloud', 'search') - `headline` (String, required) — main message text - `subtext` (String, default '') — secondary description - `size` (String, default 'md') — accepts 'sm' for sidebar micro states or 'md' for default centered layout - Named `#cta` slot — renders nothing when slot is empty (use `$slots.cta` check or `` with no fallback content) - Component is Options API (CLAUDE.md non-negotiable for new components) - Depends on AppIcon.vue (from 10-01) — import as child componentSize class mapping (from 10-PATTERNS.md):
| size | container | icon | headline | subtext |
|---|---|---|---|---|
| md (default) | text-center py-10 px-4 |
w-8 h-8 mx-auto mb-3 text-gray-300 |
text-sm font-medium text-gray-500 |
text-xs text-gray-400 mt-1 |
| sm | flex items-center gap-2 py-1 text-xs text-gray-400 |
w-3.5 h-3.5 shrink-0 |
'' (empty — inherits from container) |
'hidden' (sidebar micro states show no subtext) |
- Test 3: `renders AppIcon when icon prop is set; renders no icon when null` — mount with icon='folder' and stubs AppIcon, assert AppIcon component is found; mount with icon=null, assert no AppIcon - Test 4: `renders nothing in the CTA area when #cta slot is empty` — mount with no slots, assert wrapper does NOT contain any or elements - Test 5: `renders the #cta slot content when provided` — mount with slots: { cta: 'Upload' }, assert wrapper.find('[data-test="cta-btn"]').exists() === true - Test 6: `size='sm' applies the sidebar micro layout (flex container with gap-2)` — mount with size='sm', assert root element classList contains 'flex' and 'gap-2' - Test 7: `default size (md) applies the centered layout (text-center py-10)` — mount default, assert classList contains 'text-center' and 'py-10' Create `frontend/src/components/ui/__tests__/EmptyState.test.js`. Use Vitest + @vue/test-utils. Stub the AppIcon component via `global.stubs: { AppIcon: true }` in mount options so tests don't depend on Wave 0 task ordering. Tests will fail until Task 2 creates EmptyState.vue. Write all 7 tests above as concrete `it(...)` blocks. cd frontend && npm run test -- --run EmptyState Expected: tests collected; all 7 FAIL with module-not-found (RED phase). - File `frontend/src/components/ui/__tests__/EmptyState.test.js` exists - File contains exactly 7 `it(...)` blocks - Running `cd frontend && npm run test -- --run EmptyState` shows 7 failing tests - Tests stub AppIcon via mount options (no hard dependency on AppIcon.vue existing) Test file exists with 7 failing tests describing the EmptyState contract. Task 2: Implement EmptyState.vue frontend/src/components/ui/EmptyState.vue - frontend/src/components/ui/__tests__/EmptyState.test.js (the failing tests) - .planning/phases/10-ux-interaction/10-PATTERNS.md §"EmptyState.vue" (full target structure incl. class table) - frontend/src/views/SharedView.vue (existing inline empty-state pattern being replaced) - frontend/src/components/layout/AppSidebar.vue (existing sidebar micro pattern: pl-7 py-1 text-xs text-gray-400) - Options API component named `EmptyState` - Registers `AppIcon` as a child component (imported from `./AppIcon.vue`) - Props: `icon` (String, default null), `headline` (String, required), `subtext` (String, default ''), `size` (String, default 'md') - Computed `containerClass`, `iconClass`, `headlineClass`, `subtextClass` returning the strings from the class table in 10-PATTERNS.md - Template renders, in order: container `
`, subtext `
` (when subtext truthy AND size !== 'sm' — sidebar micro hides subtext via the `hidden` class), `` Create `frontend/src/components/ui/EmptyState.vue` using the Options API target structure from `10-PATTERNS.md §"EmptyState.vue"`. Import `AppIcon` from `./AppIcon.vue`. Use the exact class mapping table from PATTERNS: - size='md' container: `'text-center py-10 px-4'`; icon: `'w-8 h-8 mx-auto mb-3 text-gray-300'`; headline: `'text-sm font-medium text-gray-500'`; subtext: `'text-xs text-gray-400 mt-1'` - size='sm' container: `'flex items-center gap-2 py-1 text-xs text-gray-400'`; icon: `'w-3.5 h-3.5 shrink-0'`; headline: `''`; subtext: `'hidden'`
Template structure:
```
<template>
<div :class="containerClass">
<AppIcon v-if="icon" :name="icon" :class="iconClass" />
<p :class="headlineClass">{{ headline }}</p>
<p v-if="subtext" :class="subtextClass">{{ subtext }}</p>
<slot name="cta" />
</div>
</template>
```
Do NOT add explanatory comments. Use Options API (CLAUDE.md).
<success_criteria>
EmptyState.vue is ready to be wired into all 9 empty-state contexts identified in 10-RESEARCH.md §Component Inventory §3. Wave 1 plans 10-06, 10-07, 10-08 will replace inline empty-state divs with <EmptyState icon="..." headline="..." subtext="..." /> blocks (plus #cta slot where applicable).
</success_criteria>