# Phase 10: UX & Interaction — Research **Researched:** 2026-06-14 **Domain:** Vue 3 Options API / Composition API hybrid — frontend UX patterns **Confidence:** HIGH (all findings grounded in direct source reading of the actual component files) --- ## User Constraints (from CONTEXT.md) ### Locked Decisions **Toast Notifications (UX-10)** - D-01: Position: bottom-right, stacking upward from the corner. - D-02: Visual differentiation: colored left-border accent + inline icon per type. Green/success, red/error, amber/warning, blue/info. Toast body background white/neutral. - D-03: Injection: `ToastContainer.vue` uses ``. - D-04: The `show(message, type, duration)` signature is locked from Phase 8's stub. Phase 10 implements rendering without changing the signature or any Phase 8 call sites. **Empty States (UX-01)** - D-05: Each context gets its own icon from the existing Heroicons-style set (stroke-based 24×24 viewBox). - D-06: `EmptyState.vue` takes explicit props: `icon` (SVG path string or AppIcon name), `headline` (string), `subtext` (string). - D-07: CTA is an optional named `#cta` slot. EmptyState.vue renders nothing where slot is empty. **AppIcon SVG Centralization (CODE-05)** - D-08: AppIcon.vue uses a `name → SVG path string` map. No new dependency. - D-09: Outline/stroke only — no `variant` prop, no solid variant. - D-10: Prop interface: ``. `class` forwarded to outer ``. Unknown names 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`. - D-12: `BreadcrumbBar.vue` emits `@navigate(index)` — parent handles navigation. Last segment is non-clickable plain text. - D-13: Admin/settings/topics views provide static `segments` computed property. File manager and cloud folder views use folder store `breadcrumb` array. **Keyboard Shortcuts (UX-05 through UX-08)** - D-14: Global `keydown` listener in `mounted()` / `beforeUnmount()`. Guard: `['INPUT','TEXTAREA','SELECT'].includes(document.activeElement?.tagName) || document.activeElement?.isContentEditable` → early return. - D-15: `/` → focus search bar; `Escape` → close modals + clear search; `U` → trigger upload file picker; `N` → start new folder inline input. **Drag-and-Drop (UX-09, UX-11)** - D-16: OS drop overlay: `dataTransfer.types.includes('Files')` detection. Overlay 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. - D-18: `DocumentCard.vue` dedicated drag handle element to prevent `dragend`-then-`click` navigation. ### Claude's Discretion - Icon name assignments in AppIcon.vue's internal map (researcher resolves below) - Exact icon choices for each EmptyState context (researcher resolves below) - Keyboard shortcut global listener architectural home (researcher resolves below) - Exact query/store plumbing for `U` shortcut to reach upload input ref (researcher resolves below) - Dropdown/modal clipping audit (researcher resolves below) ### Deferred Ideas (OUT OF SCOPE) None — discussion stayed within phase scope. ## Phase Requirements | ID | Description | Research Support | |----|-------------|------------------| | UX-01 | EmptyState.vue across 7+ zero-content contexts | Component Inventory §3 maps all contexts | | UX-02 | StorageBrowser 5-col skeleton grid during loading | Architecture Patterns §Skeleton Pattern | | UX-03 | Sidebar folder tree + topics skeleton during loading | Architecture Patterns §Skeleton Pattern | | UX-04 | Admin user table + audit log table skeleton rows | Architecture Patterns §Skeleton Pattern | | UX-05 | `/` focuses search bar (no input focused) | Keyboard Shortcuts section | | UX-06 | `Escape` closes any open modal + clears search | Keyboard Shortcuts section | | UX-07 | `U` triggers file upload picker | Keyboard Shortcuts section; Upload Input Ref Chain | | UX-08 | `N` starts new folder inline input | Keyboard Shortcuts section; New-Folder Trigger Chain | | UX-09 | OS drag-onto-window → full-screen overlay → upload | Drag-and-Drop section | | UX-10 | Toast notification system — implement Phase 8 stub | Toast System section | | UX-11 | Drag-to-move end-to-end wiring + ring highlight | Drag-to-Move Current State section | | UX-12 | Shared BreadcrumbBar.vue across all views | BreadcrumbBar Extraction section | | UX-13 | Dropdown viewport-edge clipping fixes | Component Inventory §2 | | UX-14 | Remove sidebar "New" folder button | AppSidebar.vue analysis | | CODE-05 | Centralize ~66 inline SVGs into AppIcon.vue | Component Inventory §1 (full SVG audit) | --- ## Summary Phase 10 is a pure frontend UX phase. The backend is untouched. Every deliverable is a Vue component, store, or directive change. The codebase has been directly audited for this research document — all findings are from reading source files, not from training-data assumptions. The key findings: (1) `StorageBrowser.vue` already has ~80% of drag-to-move implemented — folder `@dragover` / `@drop` handlers exist, `draggingFile` ref is tracked, and `ring-2 ring-inset ring-amber-300` highlight is already wired; the missing piece is that `emit('file-move')` succeeds but the drop from OS files (UX-09) is entirely separate. (2) `FolderBreadcrumb.vue` already exists as a component — `BreadcrumbBar.vue` (UX-12) renames and universalizes it, adding static segments support for admin/settings views. (3) `AppIcon.vue` is new; the SVG audit found **66 `` elements across 29 files**, with **32 distinct path strings** mapping to **21 named icons**. (4) The folder picker dropdown in both `StorageBrowser.vue` and `DocumentCard.vue` is the primary clipping risk; `SearchableModelSelect.vue` already uses `` with `getBoundingClientRect()` and is the correct reference pattern. (5) App.vue uses ` ``` ### Global keydown handler in App.vue (Composition API) ```javascript // Source: direct audit of App.vue (uses