Files
kite/.planning/milestones/v0.2-phases/10-ux-interaction/10-CONTEXT.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

139 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 10: UX & Interaction - Context
**Gathered:** 2026-06-14
**Status:** Ready for planning
<domain>
## Phase Boundary
Phase 10 delivers every UX interaction improvement across the app UI — (1) contextually distinct `EmptyState.vue` across 7+ zero-content contexts; (2) loading skeletons in `StorageBrowser`, sidebar trees, and admin tables; (3) four keyboard shortcuts (`/`, `Escape`, `U`, `N`) with global keydown guard; (4) OS drag-and-drop file upload with full-screen drop overlay; (5) full toast notification system wired into the Phase 8 `useToastStore` stub; (6) drag-to-move documents onto folder rows (end-to-end, including highlight); (7) a shared `BreadcrumbBar.vue` replacing per-view breadcrumb patterns; (8) dropdown/modal viewport-edge clipping fixes; (9) removal of the sidebar "New" folder button; and (10) SVG icon centralization into `AppIcon.vue` replacing ~66 inline `<svg>` blocks.
This phase is the "feel" layer — it does not change visual design (spacing, typography, color scale). That is Phase 11.
</domain>
<decisions>
## Implementation Decisions
### Toast Notifications (UX-10)
- **D-01:** Position: **bottom-right**, stacking upward from the corner. Consistent with document management apps; avoids the header and sidebar.
- **D-02:** Visual differentiation: **colored left-border accent + inline icon** per type. Green for success, red for error, amber for warning, blue for info. Toast body background is white/neutral — only the left bar and icon carry color.
- **D-03:** Injection: `ToastContainer.vue` uses **`<Teleport to="body">`**. This avoids z-index and overflow stacking issues with the sidebar, modals, and the drag-overlay. Consistent with the dropdown clipping strategy (UX-13).
- **D-04:** The `show(message, type, duration)` signature is **locked** from Phase 8's stub. Phase 10 must implement rendering without changing the signature or any Phase 8 call sites (`SettingsAccountTab.vue`, `TotpEnrollment.vue`).
### Empty States (UX-01)
- **D-05:** Each context gets its **own icon from the existing Heroicons-style set** (same stroke-based 24×24 viewBox used throughout the app). Examples: folder icon for empty folder, magnifying glass for no search results, share icon for shared-with-me, cloud icon for cloud connections, tag icon for topics, clipboard/list icon for audit log.
- **D-06:** `EmptyState.vue` takes **explicit props**: `icon` (SVG path string or AppIcon name), `headline` (string), `subtext` (string). No internal variant map to maintain.
- **D-07:** CTA is an **optional named `#cta` slot**. Parent places any action button or link inside the slot. EmptyState.vue renders nothing where the slot is empty. This keeps EmptyState.vue display-only and avoids arbitrary button-prop shapes.
### AppIcon SVG Centralization (CODE-05)
- **D-08:** AppIcon.vue uses a **`name → SVG path string` map** built from the ~66 existing inline SVGs. No new dependency. Researcher audits all inline `<path d="...">` values, deduplicates, and assigns descriptive names. AppIcon.vue renders a single `<svg>` with the resolved path.
- **D-09:** **Outline/stroke only** — no `variant` prop, no solid variant. All existing inline SVGs are stroke-based; AppIcon.vue follows the same convention.
- **D-10:** Prop interface: `<AppIcon name="folder" class="w-4 h-4 text-amber-500" />`. The `class` attribute is forwarded to the outer `<svg>` element. `name` must match a key in the internal map; unknown names should log a warning in dev mode and render nothing.
### BreadcrumbBar (UX-12)
- **D-11:** **Props-driven** — every view computes its own `segments` array and passes it to `BreadcrumbBar.vue` as a prop. Extends the pattern already established in `StorageBrowser.vue` (which already accepts `:segments="breadcrumb"` as a prop).
- **D-12:** `BreadcrumbBar.vue` emits **`@navigate(index)`** — the parent is responsible for handling navigation when a segment is clicked. The **last segment is non-clickable plain text** (current location). BreadcrumbBar stays decoupled from Vue Router.
- **D-13:** For admin views (`Admin Users`, `Admin Quotas`, etc.), settings (`Settings Account`), and topics, each view provides a static `segments` array as a computed property. For file manager and cloud folder views, segments come from the existing folder store `breadcrumb` array and the cloud `breadcrumb` computed.
### Keyboard Shortcuts (UX-05 through UX-08)
- **D-14:** Global `keydown` listener registered in `mounted()` and removed in `beforeUnmount()`. Guard pattern (locked by ROADMAP pitfall): `['INPUT','TEXTAREA','SELECT'].includes(document.activeElement?.tagName) || document.activeElement?.isContentEditable` → early return.
- **D-15:** Shortcut keys are fixed by requirements: `/` → focus search bar; `Escape` → close modals + clear search (overlay level, not inside inputs); `U` → trigger upload file picker; `N` → start new folder inline input in file manager.
### Drag-and-Drop (UX-09, UX-11)
- **D-16:** OS drop overlay: `dataTransfer.types.includes('Files')` distinguishes OS file drag from element drag. The full-screen overlay is attached at `window`/`document` level, not inside `StorageBrowser`.
- **D-17:** Drag-to-move drop highlight: `ring-2 ring-inset ring-amber-300` on valid folder targets (locked by ROADMAP).
- **D-18:** `DocumentCard.vue` drag tracking: dedicated drag handle element to prevent `dragend`-then-`click` navigation after a drag (locked by ROADMAP).
### Claude's Discretion
- Icon name assignments in AppIcon.vue's internal map (researcher audits existing SVG paths and assigns descriptive names)
- Exact icon choices for each EmptyState context (researcher picks the most semantically appropriate Heroicon per context)
- Keyboard shortcut global listener architectural home (App.vue vs dedicated AppKeyboardManager component) — researcher reads App.vue and determines the cleanest mounting point
- Exact query/store plumbing for `U` shortcut to reach the upload input ref (researcher reads FileManagerView → StorageBrowser prop chain)
- Dropdown/modal clipping audit: which specific dropdowns need `<Teleport>` vs `getBoundingClientRect()` fixed positioning (researcher audits all dropdown components)
</decisions>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Phase Goals and Requirements
- `.planning/ROADMAP.md` §"Phase 10: UX & Interaction" — goal, implementation notes (keyboard guard pattern, drag detection, drag-to-move highlight, drag handle pattern, dropdown fix strategy, AppIcon note, UX-14 removal), success criteria
- `.planning/REQUIREMENTS.md` §UX-01 through UX-14, CODE-05 — formal requirement definitions with all 15 requirements for this phase
### Toast System
- `frontend/src/stores/toast.js` — Phase 8 stub with locked `show(message, type, duration)` signature; Phase 10 implements rendering without changing this
- Phase 8 call sites that must remain unchanged: `frontend/src/components/settings/SettingsAccountTab.vue`, `frontend/src/components/auth/TotpEnrollment.vue`
### Frontend Architecture
- `.planning/codebase/ARCHITECTURE.md` — component responsibilities, data flow, View→Smart→Presentational layering
- `CLAUDE.md` §"Frontend: shared module map" — `src/utils/formatters.js`, `TreeItem.vue`, `StorageBrowser.vue` (canonical shared components)
- `CLAUDE.md` §"Component architecture" — Views are thin data-providers; smart components own interactions; no layout/grid logic in views
- `CLAUDE.md` §"No dead code" — removed components must be deleted in the same commit
### Existing Components Being Extended/Replaced
- `frontend/src/components/storage/StorageBrowser.vue` — main file listing component; breadcrumb-as-props pattern already implemented; drag-to-move partially implemented (UX-11 wires it end-to-end)
- `frontend/src/components/layout/AppSidebar.vue` — sidebar with inline "New" folder button being removed (UX-14); folder/cloud/topic inline text placeholders replaced by EmptyState.vue (UX-01, UX-03)
- `frontend/src/views/FileManagerView.vue` — receives breadcrumb from folder store; keyboard shortcuts for U and N must reach upload input and new-folder input through this view
- `frontend/src/components/documents/DocumentPreviewModal.vue` — already registers `document.addEventListener('keydown', handleKeydown)` in mounted(); pattern reference for keyboard listener registration
### Pitfall References (MANDATORY for researcher and planner)
- `.planning/research/PITFALLS.md` §Pitfall 6 — `dragend`-then-`click` fire after drag; use dedicated drag handle
- `.planning/research/PITFALLS.md` §Pitfall 7 — dropdown viewport-edge clipping; `getBoundingClientRect()` or `<Teleport to="body">`
- `.planning/research/PITFALLS.md` §Pitfall 12 — global keyboard shortcut guard pattern; must check `document.activeElement` before firing
</canonical_refs>
<code_context>
## Existing Code Insights
### Reusable Assets
- `frontend/src/components/ui/AppSpinner.vue` — existing loading spinner; skeletons are an additional pattern, not a replacement for spinner where spinner is appropriate
- `frontend/src/components/ui/TreeItem.vue` — generic expand/collapse tree node; used by sidebar folder/cloud tree; skeleton placeholders must render at the same indent level as TreeItem
- `frontend/src/stores/toast.js` — stub already wired into call sites; implement rendering without API changes
- `StorageBrowser.vue` breadcrumb props/emit pattern — `BreadcrumbBar.vue` extraction should mirror this interface exactly
### Established Patterns
- **Keydown listener registration**: `DocumentPreviewModal.vue` shows the correct `mounted()`/`beforeUnmount()` pattern for document-level keydown listeners
- **Breadcrumb as props**: Both `FileManagerView.vue` (`:breadcrumb="foldersStore.breadcrumb"`) and `CloudFolderView.vue` (`:breadcrumb="breadcrumb"` computed) already pass breadcrumb arrays to `StorageBrowser`
- **Inline SVG style**: All existing SVGs use `fill="none" stroke="currentColor" viewBox="0 0 24 24"` with `stroke-linecap="round" stroke-linejoin="round" stroke-width="2"` — AppIcon.vue must match this
- **`<Teleport to="body">`**: The drag-to-move drop highlight and dropdown clipping fix (UX-13) both use this pattern; ToastContainer uses the same
### Integration Points
- `App.vue` — ToastContainer (teleported) and drag-drop overlay mount here or as children
- `AppSidebar.vue` — EmptyState.vue replaces plain text placeholders ("No folders yet", "No topics yet", "No cloud storage connected"); inline "New" button removed
- `StorageBrowser.vue` — drag-to-move end-to-end wiring, loading skeleton overlay, EmptyState.vue integration, BreadcrumbBar.vue extraction
- All admin views (`AdminUsersView.vue`, `AdminAuditView.vue`) — skeleton table rows during loading (UX-04)
</code_context>
<specifics>
## Specific Ideas
- Toast: left-border accent color + icon inside a white/neutral pill. Consistent with how the app already uses color semantics (amber for folders, sky for cloud, indigo for admin).
- EmptyState icons: folder icon for empty folder context, magnifying glass / search icon for no search results, share/users icon for shared-with-me, cloud icon for cloud connections, tag icon for topics, clipboard-list icon for audit log, document icon for root empty file list.
- BreadcrumbBar: last segment plain text, earlier segments as clickable links separated by `` chevron. Width-constrained with text truncation on small viewports (Phase 11 owns responsive specifics but BreadcrumbBar should not overflow its container).
</specifics>
<deferred>
## Deferred Ideas
None — discussion stayed within phase scope.
</deferred>
---
*Phase: 10-UX & Interaction*
*Context gathered: 2026-06-14*