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

12 KiB
Raw Blame History

Phase 10: UX & Interaction - Context

Gathered: 2026-06-14 Status: Ready for planning

## 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.

## 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)

<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>

## 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).
## Deferred Ideas

None — discussion stayed within phase scope.


Phase: 10-UX & Interaction Context gathered: 2026-06-14