Files
kite/.planning/milestones/v0.2-phases/10-ux-interaction/10-01-PLAN.md
T
curo1305andClaude Sonnet 4.6 123ae5b29b chore: archive v0.2 phase directories to milestones/v0.2-phases/
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>
2026-06-17 14:34:52 +02:00

11 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 01 execute 0
frontend/src/components/ui/AppIcon.vue
frontend/src/components/ui/__tests__/AppIcon.test.js
true
CODE-05
truths artifacts key_links
AppIcon renders the correct <svg> path for any name in the icon map
AppIcon forwards the consumer's class attribute to the outer <svg> element
AppIcon supports both single-path and dual-path (Array) icons (cog uses two paths)
Unknown icon names trigger console.warn in dev mode and render nothing
path provides contains
frontend/src/components/ui/AppIcon.vue Centralized icon registry component ICON_PATHS
path provides
frontend/src/components/ui/__tests__/AppIcon.test.js AppIcon unit tests
from to via pattern
AppIcon.vue script ICON_PATHS map computed resolvedPaths ICON_PATHS[this.name]
Create `frontend/src/components/ui/AppIcon.vue` — the single source of truth for all SVG icon paths used in DocuVault. This is the foundation for the CODE-05 SVG migration that happens in Wave 5.

Purpose: Eliminate ~66 inline <svg> blocks across 29 files by centralizing the icon paths into one map. All existing SVGs use the same outline/stroke style (fill="none" stroke="currentColor" viewBox="0 0 24 24" with stroke-linecap="round" stroke-linejoin="round" stroke-width="2") — AppIcon matches this exactly so the migration is a drop-in replacement.

Output: AppIcon.vue (Options API, ~30 named icons including the dual-path cog) + a Vitest unit test covering name→path rendering, class forwarding, dual-path handling, and unknown-name warning.

<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/ui/AppSpinner.vue @frontend/src/components/layout/AppSidebar.vue @frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js Per D-08, D-09, D-10 (CONTEXT.md): - Props: `name` (String, required) - inheritAttrs: false - $attrs.class forwarded to outer - SVG attrs: `fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"` - Path attrs: `stroke-linecap="round" stroke-linejoin="round" stroke-width="2"` - Array path support for `cog` (dual path) - Unknown name: console.warn in import.meta.env.DEV; render nothing (v-if guard)

Project Vitest layout (verified from existing tests at frontend/src/components/folders/tests/FolderBreadcrumb.test.js):

  • Tests live in tests/ alongside the component
  • Uses @vue/test-utils mount
  • Run command: cd frontend && npm run test
Task 1: Create AppIcon.test.js with failing tests for the contract frontend/src/components/ui/__tests__/AppIcon.test.js - frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js (test style — vitest + @vue/test-utils mount) - .planning/phases/10-ux-interaction/10-PATTERNS.md (AppIcon target structure) - .planning/phases/10-ux-interaction/10-RESEARCH.md §"Component Inventory §1: SVG Audit" (full icon name list) - Test 1: `renders with the correct d attribute for a known single-path icon (folder)` — mount with name="folder", assert svg.path has d starting with "M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v9" - Test 2: `forwards consumer class to the element` — mount with name="folder" and attrs class "w-4 h-4 text-amber-500", assert wrapper.find('svg').classes() contains those classes - Test 3: `renders TWO elements for a dual-path icon (cog)` — mount with name="cog", assert wrapper.findAll('path').length === 2 - Test 4: `renders the standard SVG attrs (fill=none, stroke=currentColor, viewBox=0 0 24 24)` — mount any name, assert wrapper.find('svg').attributes('fill') === 'none' and stroke === 'currentColor' and viewBox === '0 0 24 24' - Test 5: `renders no svg and calls console.warn when name is unknown` — spy on console.warn, mount name="bogus-name", assert wrapper.find('svg').exists() === false and console.warn called once with a message containing "bogus-name" - Test 6: `path elements use stroke-linecap=round, stroke-linejoin=round, stroke-width=2` — mount name="folder", read path attributes Create `frontend/src/components/ui/__tests__/AppIcon.test.js`. Import AppIcon from `../AppIcon.vue` (file does NOT exist yet — tests will fail on import, that is correct). Use `import { describe, it, expect, vi } from 'vitest'` and `import { mount } from '@vue/test-utils'`. Follow the test-file style in `frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js`. Implement all 6 tests above as concrete assertions. For console.warn, set `import.meta.env.DEV = true` if needed via a `vi.stubGlobal` or rely on Vitest's default DEV=true environment. Do NOT create AppIcon.vue yet — this is the RED phase. cd frontend && npm run test -- --run AppIcon Expected: test file is collected; all 6 tests FAIL with "Cannot resolve module ../AppIcon.vue" or "Failed to resolve component". This is the RED state. - File `frontend/src/components/ui/__tests__/AppIcon.test.js` exists - File contains exactly 6 `it(...)` blocks inside one `describe('AppIcon', ...)` block - Running `cd frontend && npm run test -- --run AppIcon` shows 6 failing tests (RED — AppIcon.vue does not exist yet) - Tests use `mount` from `@vue/test-utils` (not `shallowMount`) - Tests use `vi.spyOn(console, 'warn')` or `vi.fn()` to assert the dev warning Test file exists with 6 failing tests describing the AppIcon contract. Task 2: Implement AppIcon.vue with the full ICON_PATHS map frontend/src/components/ui/AppIcon.vue - frontend/src/components/ui/__tests__/AppIcon.test.js (the failing tests from Task 1) - frontend/src/components/ui/AppSpinner.vue (single-purpose SVG analog) - .planning/phases/10-ux-interaction/10-PATTERNS.md §"AppIcon.vue" (full target structure) - .planning/phases/10-ux-interaction/10-RESEARCH.md §"Component Inventory §1: SVG Audit" (complete d-attr values) - Component is Options API per CLAUDE.md (project convention) - Component name: `AppIcon` - `inheritAttrs: false` - Props: `name: { type: String, required: true }` - Computed `resolvedPaths()` returns `ICON_PATHS[this.name] ?? null`; if null AND `import.meta.env.DEV`, calls `console.warn('[AppIcon] Unknown icon name: "' + this.name + '"')` - Template: ` Create `frontend/src/components/ui/AppIcon.vue` using the Options API template from `10-PATTERNS.md §"AppIcon.vue"`. Declare a module-scope `const ICON_PATHS = { ... }` with EXACTLY these 31 keys (28 single + 1 dual + 2 added):
Single-path keys (use d-values exactly from 10-RESEARCH.md §Component Inventory §1):
`plus`, `folder`, `folderMove`, `pencil`, `trash`, `share`, `document`, `fileDoc`, `chevronRight`, `chevronDown`, `tag`, `inbox`, `cloud`, `shield`, `logout`, `home`, `users`, `chartBar`, `clipboardList`, `upload`, `x`, `checkCircle`, `exclamationCircle`, `warning`, `copy`, `check`, `checkMark`, `refresh`, `pencilEdit`, `lightBulb`, `search`, `dots`.

Dual-path key (Array value, two strings — see RESEARCH.md):
`cog: ['M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z', 'M15 12a3 3 0 11-6 0 3 3 0 016 0z']`

For the `search` key, use d = `'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0'` (per D-05 Heroicons outline search). For `dots`, use the stroke replacement d = `'M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z'` (Pattern: per D-09 outline-only convention — replaces FolderRow fill-based dots).

Use the exact template structure from 10-PATTERNS.md AppIcon.vue section (lines 47-73 of the analog block). NO comments inside the file describing what the code does (CLAUDE.md non-negotiable). Do NOT add a `default` prop value for name; required is the contract.
cd frontend && npm run test -- --run AppIcon Expected: All 6 tests from Task 1 PASS (GREEN). - File `frontend/src/components/ui/AppIcon.vue` exists - File contains module-scope `const ICON_PATHS` with at least 30 keys (verify: `grep -c "':" frontend/src/components/ui/AppIcon.vue` returns ≥ 30 or count keys via parse) - File contains `inheritAttrs: false` - File contains `import.meta.env.DEV` reference - File contains `Array.isArray(resolvedPaths)` check - Running `cd frontend && npm run test -- --run AppIcon` exits 0 with 6 passing tests (GREEN) - File uses Options API (`export default { name: 'AppIcon', ... }`) per CLAUDE.md, NOT `<script setup>` - `cog` key value is an Array of length 2 AppIcon.vue exists with full icon map; all 6 tests pass. - `cd frontend && npm run test -- --run AppIcon` exits 0 - `grep -E "ICON_PATHS\\s*=" frontend/src/components/ui/AppIcon.vue` returns 1 match - `grep -E "inheritAttrs:\\s*false" frontend/src/components/ui/AppIcon.vue` returns 1 match - `grep -E "Array\\.isArray\\(resolvedPaths\\)" frontend/src/components/ui/AppIcon.vue` returns 1 match - `grep -c "'.*':.*'M" frontend/src/components/ui/AppIcon.vue` returns ≥ 28 (single-path icon count, excluding the array `cog`)

<success_criteria> AppIcon.vue is the single source of truth for icon paths. Wave 5's SVG migration (10-12) can replace every inline <svg> block with <AppIcon name="..." class="..." /> and the visual result matches the existing rendering pixel-for-pixel (same fill/stroke/viewBox/path conventions). </success_criteria>

Create `.planning/phases/10-ux-interaction/10-01-SUMMARY.md` when done with: what was built, the final ICON_PATHS key count, and any deviations from the planned key list.