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>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
e008bf7dae
commit
123ae5b29b
@@ -0,0 +1,138 @@
|
||||
# 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*
|
||||
Reference in New Issue
Block a user