ff379ad6e3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
391 lines
22 KiB
Markdown
391 lines
22 KiB
Markdown
---
|
||
phase: 4
|
||
slug: folders-sharing-quotas-document-ux
|
||
status: draft
|
||
shadcn_initialized: false
|
||
preset: none
|
||
created: 2026-05-25
|
||
---
|
||
|
||
# Phase 4 — UI Design Contract
|
||
|
||
> Visual and interaction contract for Phase 4: Folders, Sharing, Quotas & Document UX.
|
||
> Generated by gsd-ui-researcher, verified by gsd-ui-checker.
|
||
> Source: existing codebase scan + 04-CONTEXT.md decisions.
|
||
|
||
---
|
||
|
||
## Design System
|
||
|
||
| Property | Value |
|
||
|----------|-------|
|
||
| Tool | none |
|
||
| Preset | not applicable |
|
||
| Component library | none (inline SVG icons, Tailwind utility classes only) |
|
||
| Icon library | Inline SVG (Heroicons stroke style, w-4 h-4 / w-5 h-5) — do not add an icon package |
|
||
| Font | System font stack (Tailwind default — no custom font loaded) |
|
||
|
||
No design system change for Phase 4. All new components extend the existing Tailwind utility pattern established in Phase 2/3.
|
||
|
||
---
|
||
|
||
## Spacing Scale
|
||
|
||
Declared values (multiples of 4 only). Source: existing component scan — `p-4`, `px-6 py-5`, `gap-3`, `px-3 py-2`.
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| xs | 4px | Icon gaps, topic badge gaps (`gap-1`) |
|
||
| sm | 8px | Compact element spacing, inline button padding (`py-1.5`) |
|
||
| md | 16px | Default element spacing, card padding (`p-4`) |
|
||
| lg | 24px | Section padding (`px-6 py-5`), page section breaks |
|
||
| xl | 32px | Page content padding (`p-8`) |
|
||
| 2xl | 48px | Major empty-state vertical padding (`py-12`) |
|
||
| 3xl | 64px | Not used in Phase 4 |
|
||
|
||
Exceptions:
|
||
- Touch targets (icon-only buttons): minimum 44px height enforced via `min-h-[44px]` (established in ConfirmBlock.vue — apply to all icon-only action buttons in this phase).
|
||
- Breadcrumb segment gap: 8px (`gap-2`) with a separator chevron (SVG, w-3 h-3).
|
||
- Modal overlay: full-viewport fixed overlay `inset-0`, modal panel `max-w-md w-full` centered with `p-6` internal padding.
|
||
- Breadcrumb truncation ellipsis button: `px-1 py-0.5` compact.
|
||
|
||
---
|
||
|
||
## Typography
|
||
|
||
Extend existing scale — do not introduce new sizes. Source: DocumentCard.vue, AppSidebar.vue, DocumentView.vue.
|
||
|
||
| Role | Size | Weight | Line Height | Tailwind classes |
|
||
|------|------|--------|-------------|-----------------|
|
||
| Page heading | 24px (text-2xl) | 700 (font-bold) | 1.2 | `text-2xl font-bold text-gray-900` |
|
||
| Section heading | 18px (text-lg) | 600 (font-semibold) | 1.3 | `text-lg font-semibold text-gray-800` |
|
||
| Body / card label | 14px (text-sm) | 500 (font-medium) | 1.5 | `text-sm font-medium text-gray-900` |
|
||
| Caption / metadata | 12px (text-xs) | 400 (normal) | 1.4 | `text-xs text-gray-400` |
|
||
|
||
Weights in use: 400 (normal), 500 (medium), 600 (semibold), 700 (bold). No new weights added.
|
||
|
||
Monospace (extracted text panel): `text-xs font-mono` at `text-gray-600` on `bg-gray-50` — established in DocumentView.vue, reuse for audit log detail cells.
|
||
|
||
Section label / nav category: `text-xs font-semibold text-gray-400 uppercase tracking-wider` — established pattern, reuse for folder section header in sidebar.
|
||
|
||
---
|
||
|
||
## Color
|
||
|
||
Source: AppSidebar.vue, QuotaBar.vue, DocumentCard.vue, DocumentView.vue. No new colors introduced.
|
||
|
||
| Role | Tailwind value | Hex (approx) | Usage |
|
||
|------|---------------|--------------|-------|
|
||
| Dominant (60%) | `bg-white` | #ffffff | Page background, cards, sidebar background |
|
||
| Secondary (30%) | `bg-gray-50` / `border-gray-200` | #f9fafb / #e5e7eb | Card hover surface, extracted text block background, modal backdrop inner panel, table row stripes |
|
||
| Accent (10%) | `indigo-600` / `indigo-50` / `indigo-700` | #4f46e5 | Reserved-for list below |
|
||
| Destructive | `red-600` / `red-700` | #dc2626 | Destructive action buttons only |
|
||
| Warning — quota amber | `amber-500` / `amber-600` | #f59e0b | QuotaBar 80–95% (pre-existing, do not change) |
|
||
| Warning — quota red | `red-500` / `red-600` | #ef4444 | QuotaBar ≥95% (pre-existing, do not change) |
|
||
|
||
**Accent (indigo) reserved for:**
|
||
- Active nav link background: `bg-indigo-50 text-indigo-700`
|
||
- Primary action buttons (filled): `bg-indigo-600 hover:bg-indigo-700 text-white`
|
||
- Document icon background: `bg-indigo-50` with `text-indigo-500` icon
|
||
- Logo text: `text-indigo-600`
|
||
- User avatar background: `bg-indigo-100 text-indigo-700`
|
||
- QuotaBar fill (normal state): `bg-indigo-500`
|
||
- Link text (back navigation, inline links): `text-indigo-600 hover:underline`
|
||
- Checkbox / radio checked state: `text-indigo-600` (Tailwind form plugin default)
|
||
- Share badge (shared indicator on document card): `bg-indigo-50 text-indigo-600` pill
|
||
|
||
Accent is NOT used on: hover states of neutral UI, sort controls, breadcrumb separators, audit log rows, sidebar section labels, permission badges (use gray), or any informational text.
|
||
|
||
**Shared indicator badge** (SHARE-05): small `bg-indigo-50 text-indigo-600 text-xs font-medium px-2 py-0.5 rounded-full` pill labeled "Shared" — shown inline in DocumentCard below the metadata line when `doc.share_count > 0`.
|
||
|
||
**"Shared with me" virtual folder entry** (D-06): rendered with a distinct inbox-style icon (`bg-purple-50 text-purple-500`) to visually separate it from user-owned folders. Purple is used ONLY for this one sidebar entry to signal "received from others" vs. "my own". No other UI element uses purple.
|
||
|
||
Folder row icons in main content: `bg-gray-100 text-gray-500` (neutral — folders are structural, not accent).
|
||
|
||
---
|
||
|
||
## Component Inventory
|
||
|
||
New components required for Phase 4. All follow existing utility-class patterns.
|
||
|
||
### FolderRow.vue
|
||
- Used in HomeView main content area to render sub-folders within a folder.
|
||
- Layout: `flex items-center gap-3 px-4 py-3 bg-white border border-gray-200 rounded-xl hover:border-indigo-300 hover:shadow-sm transition-all cursor-pointer`
|
||
- Left: folder icon `w-9 h-9 rounded-lg bg-gray-100 flex items-center justify-center` with `text-gray-500` SVG folder icon (w-5 h-5).
|
||
- Middle: folder name `font-medium text-gray-900 text-sm`, sub-label `text-xs text-gray-400` showing document count (e.g., "3 documents").
|
||
- Right: three-dot menu button `text-gray-400 hover:text-gray-600` with dropdown for Rename and Delete actions.
|
||
|
||
### FolderBreadcrumb.vue
|
||
- Rendered above document list when inside a folder.
|
||
- Segments: `flex items-center gap-2 text-sm`.
|
||
- Each clickable segment: `text-indigo-600 hover:underline font-medium`.
|
||
- Separator: SVG chevron-right `w-3 h-3 text-gray-400 shrink-0`.
|
||
- Truncation rule (D-02): when depth > 4, show first segment + `…` button (plain text, `px-1 py-0.5 text-gray-400 hover:text-gray-600`) + last 2 segments.
|
||
- Current (non-clickable) final segment: `text-gray-900 font-medium`.
|
||
|
||
### ShareModal.vue
|
||
- Triggered by share icon button on DocumentCard.
|
||
- Modal overlay: `fixed inset-0 bg-black/40 flex items-center justify-center z-50`.
|
||
- Panel: `bg-white rounded-2xl shadow-xl p-6 max-w-md w-full mx-4`.
|
||
- Title: `text-lg font-semibold text-gray-900 mb-4` — "Share document".
|
||
- Handle input row: `flex gap-2` — `<input type="text" placeholder="Enter username handle" class="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">` + primary button "Share" `bg-indigo-600 hover:bg-indigo-700 text-white text-sm px-4 py-2 rounded-lg`.
|
||
- Separator: `border-t border-gray-100 my-4`.
|
||
- Recipients list: each row `flex items-center justify-between py-2`.
|
||
- Left: handle `text-sm text-gray-900` + permission badge `text-xs bg-gray-100 text-gray-600 px-2 py-0.5 rounded-full font-medium ml-2` (shows "view").
|
||
- Right: "Revoke" `text-xs text-red-500 hover:text-red-700 font-medium` button.
|
||
- Empty state: `text-sm text-gray-400 italic py-2` — "Not shared with anyone yet."
|
||
- Close button: top-right `absolute top-4 right-4`, `text-gray-400 hover:text-gray-600`, SVG X icon w-5 h-5.
|
||
|
||
### FolderDeleteModal.vue
|
||
- Triggered when deleting a non-empty folder (D-03).
|
||
- Reuses ConfirmBlock.vue pattern but rendered in a modal panel (same overlay style as ShareModal).
|
||
- Warning icon: `w-10 h-10 bg-red-50 rounded-full flex items-center justify-center` with `text-red-500` exclamation SVG, centered at top of modal.
|
||
- Heading: `text-lg font-semibold text-gray-900 mt-4 text-center` — "Delete folder?"
|
||
- Body: `text-sm text-gray-600 text-center mt-2 mb-6` — "This folder contains {N} documents. Deleting it will permanently delete all documents inside. This cannot be undone."
|
||
- Buttons: `flex gap-3 justify-end`. Cancel: `text-sm text-gray-600 hover:text-gray-800 px-4 py-2`. Confirm: `bg-red-600 hover:bg-red-700 text-white text-sm font-semibold px-4 py-2 rounded-lg min-h-[44px]` — "Delete folder and documents".
|
||
|
||
### DocumentPreviewModal.vue (in-app mode only)
|
||
- Used when `user.pdf_open_mode === 'in_app'` (D-10).
|
||
- Overlay: `fixed inset-0 bg-black/60 z-50 flex flex-col`.
|
||
- Header bar: `bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between`.
|
||
- Left: document name `text-sm font-medium text-gray-900 truncate max-w-xs`.
|
||
- Right: close button `text-gray-400 hover:text-gray-600`, SVG X w-5 h-5.
|
||
- Content: `flex-1 overflow-hidden` — `<iframe class="w-full h-full border-0" :src="proxyUrl" title="Document preview">`.
|
||
- No loading spinner needed — browser handles iframe load state.
|
||
|
||
### SearchBar.vue (inline in HomeView/FolderView)
|
||
- Rendered above the document list, right-aligned alongside sort controls.
|
||
- `<input type="search" placeholder="Search documents…" class="border border-gray-300 rounded-lg px-3 py-2 text-sm w-56 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent">`.
|
||
- Debounced 300 ms. Minimum 2 characters before firing. Clears on Escape key.
|
||
- While searching (debounce pending): no spinner — results just update.
|
||
- No results: inline empty state text below the list area (see copywriting below).
|
||
|
||
### SortControls.vue (inline in HomeView/FolderView)
|
||
- Three text buttons: "Name" / "Date" / "Size" — `text-xs text-gray-500 hover:text-gray-900 font-medium px-2 py-1 rounded`.
|
||
- Active sort: `text-indigo-600 font-semibold`. Direction indicator: `↑` or `↓` suffix appended to active label.
|
||
|
||
### AuditLogTab.vue (extends AdminView)
|
||
- New tab added to AdminView alongside existing Users, Quotas, AI Config tabs.
|
||
- Filter bar: `flex flex-wrap gap-3 mb-4 items-end`.
|
||
- Date range: two `<input type="date">` fields with `text-sm border border-gray-300 rounded-lg px-3 py-2 focus:ring-indigo-500`.
|
||
- User dropdown: `<select>` with same styling — "All users" default.
|
||
- Action type dropdown: same styling — "All actions" default.
|
||
- Apply button: `bg-indigo-600 text-white text-sm px-4 py-2 rounded-lg hover:bg-indigo-700`.
|
||
- Export button: `border border-gray-300 text-gray-700 text-sm px-4 py-2 rounded-lg hover:bg-gray-50` — "Export CSV".
|
||
- Table: `w-full text-sm border-collapse`.
|
||
- Header row: `text-xs font-semibold text-gray-400 uppercase tracking-wider` on `bg-gray-50 border-b border-gray-200`.
|
||
- Columns: Timestamp | User | Action Type | IP Address.
|
||
- Body row: `border-b border-gray-100 hover:bg-gray-50`. Cells: `px-4 py-3 text-sm text-gray-700`.
|
||
- Timestamp: monospace `font-mono text-xs text-gray-500`.
|
||
- Action type: pill badge `text-xs px-2 py-0.5 rounded-full font-medium` — color-coded by category: auth=`bg-blue-50 text-blue-600`, document=`bg-gray-100 text-gray-600`, folder/share=`bg-purple-50 text-purple-600`, admin=`bg-amber-50 text-amber-700`.
|
||
- Pagination: `flex items-center justify-between mt-4`. "Previous" / "Next" text buttons. Page indicator `text-sm text-gray-500`.
|
||
- Empty state: centered `py-12 text-gray-400 text-sm` — "No audit log entries match the selected filters."
|
||
|
||
---
|
||
|
||
## AppSidebar Extensions
|
||
|
||
Extend AppSidebar.vue with new sections (D-01, D-06). Order top to bottom:
|
||
|
||
1. Logo section (unchanged)
|
||
2. Nav links: Home, All Topics (unchanged)
|
||
3. **NEW — "Shared with me" entry** (fixed, above folders): rendered with inbox icon `bg-purple-50 text-purple-500`. If `sharedCount > 0`, show count badge `ml-auto bg-purple-100 text-purple-600 text-xs font-semibold rounded-full px-1.5 min-w-[18px] text-center`. Route: `/shared`.
|
||
4. **NEW — Folders section**: section label `text-xs font-semibold text-gray-400 uppercase tracking-wider mb-1` — "Folders". "New folder" inline button: `text-xs text-indigo-600 hover:underline` — appears to the right of the section label. Each top-level folder: `nav-link` style (same as topic links) with folder SVG icon `w-4 h-4 mr-2` and truncated name. Active when `$route.params.folderId === folder.id`.
|
||
5. Topics list (unchanged)
|
||
6. QuotaBar (unchanged)
|
||
7. Settings + Admin footer (unchanged)
|
||
|
||
---
|
||
|
||
## DocumentCard Extensions
|
||
|
||
Extend DocumentCard.vue with two additions (D-05, SHARE-05):
|
||
|
||
1. **Share button**: icon-only button, appears on card hover (`opacity-0 group-hover:opacity-100 transition-opacity`). Add `group` class to outer div. Button: `p-1.5 rounded-md text-gray-400 hover:text-indigo-600 hover:bg-indigo-50 transition-colors min-h-[44px] min-w-[44px] flex items-center justify-center` — share/export SVG icon w-4 h-4. Position: absolute top-right within the card header row, alongside a potential future menu.
|
||
2. **Shared indicator pill** (SHARE-05): `bg-indigo-50 text-indigo-600 text-xs font-medium px-2 py-0.5 rounded-full` — "Shared" — shown inline below the metadata line when `doc.share_count > 0`.
|
||
|
||
---
|
||
|
||
## Copywriting Contract
|
||
|
||
Source: 04-CONTEXT.md `<specifics>` block + requirement descriptions.
|
||
|
||
### Folders
|
||
|
||
| Element | Copy |
|
||
|---------|------|
|
||
| New folder CTA | "New folder" |
|
||
| Folder rename action | "Rename" |
|
||
| Folder delete action | "Delete folder" |
|
||
| Empty folder state (no documents, no sub-folders) | "This folder is empty." / "Upload documents or create sub-folders to organize your files." |
|
||
| Non-empty folder delete heading | "Delete folder?" |
|
||
| Non-empty folder delete body | "This folder contains {N} document{s}. Deleting it will permanently delete all documents inside. This cannot be undone." |
|
||
| Non-empty folder delete confirm button | "Delete folder and documents" |
|
||
| Non-empty folder delete cancel button | "Cancel" |
|
||
| Move document action | "Move to folder" |
|
||
| Move document success (no toast — inline list refresh only) | n/a |
|
||
|
||
### Sharing
|
||
|
||
| Element | Copy |
|
||
|---------|------|
|
||
| Share button aria-label | "Share document" |
|
||
| Share modal title | "Share document" |
|
||
| Handle input placeholder | "Enter username handle" |
|
||
| Share submit CTA | "Share" |
|
||
| User not found error (D-04) | "User not found. Check the handle and try again." |
|
||
| Already shared error | "This document is already shared with that user." |
|
||
| Share success (no toast — list refreshes inline) | n/a |
|
||
| Revoke action label | "Revoke" |
|
||
| Revoke confirm (inline, no modal) | None — single click revokes immediately (low-stakes, immediately visible in list) |
|
||
| Empty recipients state | "Not shared with anyone yet." |
|
||
| "Shared with me" sidebar label | "Shared with me" |
|
||
| "Shared with me" empty state heading | "No documents shared with you yet." |
|
||
| "Shared with me" empty state body | "When someone shares a document with you, it will appear here." |
|
||
|
||
### Document List & Search
|
||
|
||
| Element | Copy |
|
||
|---------|------|
|
||
| Search placeholder | "Search documents…" |
|
||
| No results state (after search) | "No documents match "{query}"." / "Try a different search term." |
|
||
| Document list empty state (no documents, no search) | "No documents yet. Upload one above." (pre-existing, unchanged) |
|
||
| Sort label prefix | "Sort by:" — rendered as accessible visually-hidden label; buttons labeled "Name", "Date", "Size" |
|
||
|
||
### PDF Preview
|
||
|
||
| Element | Copy |
|
||
|---------|------|
|
||
| Document preferences section heading | "Document Preferences" |
|
||
| PDF open mode radio option 1 | "Open documents in-app" |
|
||
| PDF open mode radio option 2 | "Open documents in new tab" |
|
||
| Preview close button aria-label | "Close preview" |
|
||
|
||
### Audit Log
|
||
|
||
| Element | Copy |
|
||
|---------|------|
|
||
| Audit log tab label | "Audit Log" |
|
||
| Filter apply CTA | "Apply filters" |
|
||
| Export CTA | "Export CSV" |
|
||
| Empty state (no results) | "No audit log entries match the selected filters." |
|
||
| Date range label | "From" / "To" |
|
||
| User filter label | "User" with default option "All users" |
|
||
| Action type filter label | "Action" with default option "All actions" |
|
||
| Pagination previous | "Previous" |
|
||
| Pagination next | "Next" |
|
||
|
||
### Error States (general)
|
||
|
||
| Element | Copy |
|
||
|---------|------|
|
||
| Generic API failure | "Something went wrong. Please try again." |
|
||
| Network error | "Unable to connect. Check your connection and try again." |
|
||
| 404 (folder or document not found) | "This {folder/document} no longer exists." |
|
||
| Quota rejection on upload (pre-existing, do not change) | As implemented in Phase 3 UploadProgress.vue |
|
||
|
||
---
|
||
|
||
## Interaction Contracts
|
||
|
||
### Folder Navigation
|
||
- Clicking a top-level folder in the sidebar navigates to `/folders/{id}`.
|
||
- Within a folder view, sub-folder rows are rendered above document cards.
|
||
- Clicking a sub-folder row navigates deeper: `/folders/{id}`.
|
||
- Breadcrumb segments are anchor/router-link elements — keyboard navigable.
|
||
- "New folder" triggers an inline text field directly in the folder list (not a modal), pre-focused, Escape cancels, Enter submits, empty name submits are rejected client-side with `text-red-500 text-xs mt-1` error inline.
|
||
|
||
### Folder Rename
|
||
- Three-dot menu on FolderRow opens a `position: absolute` dropdown `bg-white border border-gray-200 rounded-lg shadow-md py-1 min-w-[120px] z-10` with two items: "Rename" and "Delete folder". Menu closes on outside click.
|
||
- Rename: replaces folder name text with an inline `<input>` pre-filled with current name. Same commit behavior as new folder (Enter = save, Escape = cancel).
|
||
|
||
### Document Sort
|
||
- Default sort: Date, descending (newest first).
|
||
- Sort state lives in local view state (not URL params) for Phase 4 MVP.
|
||
- Sort change triggers immediate re-fetch with `?sort=name|date|size&order=asc|desc` query params.
|
||
|
||
### Search Debounce
|
||
- 300 ms debounce. Fires only when input length >= 2.
|
||
- While a search request is in-flight, a `text-gray-400 text-xs` "Searching…" message appears inline below the search bar (not a spinner).
|
||
- Clearing the search input (empty string) immediately restores the full document list without an API call.
|
||
|
||
### Share Modal
|
||
- Share modal does not close after a successful share — the handle input clears and the recipient list updates inline, allowing additional shares without reopening.
|
||
- "Revoke" removes the row immediately (optimistic UI — if API fails, row re-appears with `text-red-500 text-xs` error appended to it).
|
||
|
||
### PDF Preview (in-app mode)
|
||
- Clicking a PDF document card opens DocumentPreviewModal.vue if `pdf_open_mode === 'in_app'`.
|
||
- Non-PDF documents continue to navigate to DocumentView (metadata/extracted text).
|
||
- PDFs also show metadata/extracted text in DocumentView when accessed via direct URL (modal is a shortcut, not the only path).
|
||
- Clicking outside the modal panel (on the overlay) closes the modal.
|
||
- Pressing Escape closes the modal.
|
||
|
||
### Audit Log Pagination
|
||
- Page size: 50 rows per page.
|
||
- Pagination via `?page=N&page_size=50` query params on the audit log API endpoint.
|
||
- Filter changes reset to page 1.
|
||
|
||
---
|
||
|
||
## Accessibility Contracts
|
||
|
||
- All icon-only buttons (share, close, three-dot menu, revoke) have `aria-label` attributes.
|
||
- Modal overlays set `role="dialog" aria-modal="true" aria-labelledby="{modal-title-id}"`.
|
||
- Modal opening focuses the first interactive element inside the panel.
|
||
- Modal closing returns focus to the trigger element.
|
||
- Sort buttons set `aria-pressed="true"` on the active sort. Direction change is conveyed via visible `↑`/`↓` character plus `aria-label` including direction (e.g., `aria-label="Sort by name, ascending"`).
|
||
- Breadcrumb wrapper: `<nav aria-label="Folder navigation">` with `<ol>` list structure.
|
||
- Search input: `role="search"` on the wrapping `<div>`, `aria-label="Search documents"` on the input.
|
||
- QuotaBar: `role="progressbar"` already implemented — no change.
|
||
- Audit log table: `<table>` with `<thead>`, `<th scope="col">` headers.
|
||
- FolderDeleteModal, ShareModal: trap focus within modal while open.
|
||
|
||
---
|
||
|
||
## Registry Safety
|
||
|
||
| Registry | Blocks Used | Safety Gate |
|
||
|----------|-------------|-------------|
|
||
| shadcn official | none | not applicable — no shadcn in this project |
|
||
| Third-party | none | not applicable |
|
||
|
||
No third-party component registries. All new components are hand-authored Tailwind utility classes following established project patterns. No new npm packages for UI components.
|
||
|
||
---
|
||
|
||
## New Files Required
|
||
|
||
| File | Purpose |
|
||
|------|---------|
|
||
| `frontend/src/components/folders/FolderRow.vue` | Folder row in main content area |
|
||
| `frontend/src/components/folders/FolderBreadcrumb.vue` | Breadcrumb navigation |
|
||
| `frontend/src/components/folders/FolderDeleteModal.vue` | Non-empty folder delete confirmation |
|
||
| `frontend/src/components/sharing/ShareModal.vue` | Share by handle + revoke list |
|
||
| `frontend/src/components/documents/DocumentPreviewModal.vue` | In-app PDF preview via iframe |
|
||
| `frontend/src/components/documents/SearchBar.vue` | Debounced full-text search input |
|
||
| `frontend/src/components/documents/SortControls.vue` | Name / Date / Size sort toggle |
|
||
| `frontend/src/components/admin/AuditLogTab.vue` | Admin audit log viewer with filters + export |
|
||
| `frontend/src/views/FolderView.vue` | Folder contents view (sub-folders + documents + breadcrumb) |
|
||
| `frontend/src/views/SharedView.vue` | "Shared with me" virtual folder view |
|
||
|
||
Existing files extended (not replaced):
|
||
- `frontend/src/components/layout/AppSidebar.vue` — add Shared with me entry + Folders section
|
||
- `frontend/src/components/documents/DocumentCard.vue` — add share button + shared indicator pill
|
||
- `frontend/src/views/HomeView.vue` — add SearchBar + SortControls above document list
|
||
- `frontend/src/views/DocumentView.vue` — add PDF preview trigger logic
|
||
- `frontend/src/views/AdminView.vue` — add AuditLog tab
|
||
- `frontend/src/views/SettingsView.vue` — add Document Preferences card with pdf_open_mode radio
|
||
|
||
---
|
||
|
||
## Checker Sign-Off
|
||
|
||
- [ ] Dimension 1 Copywriting: PASS
|
||
- [ ] Dimension 2 Visuals: PASS
|
||
- [ ] Dimension 3 Color: PASS
|
||
- [ ] Dimension 4 Typography: PASS
|
||
- [ ] Dimension 5 Spacing: PASS
|
||
- [ ] Dimension 6 Registry Safety: PASS
|
||
|
||
**Approval:** pending
|