# 4.1 — Sidebar & File Organization **Previous Step:** ← [Tab Bar](../../03-document-management/3.1-tab-bar/3.1-tab-bar.md) **Next Step:** → [Templates](../4.2-templates/4.2-templates.md) --- ## Page Metadata | Property | Value | |----------|-------| | **Scenario** | 04 — File Organization | | **Page Number** | 4.1 | | **Platform** | Web (PWA), portable to macOS/Windows | | **Page Type** | Collapsible Side Panel (within App Shell) | --- ## Overview **Page Purpose:** Organize and navigate calctext documents. The sidebar provides a persistent file tree with folders, recent files, favorites, and templates — transforming CalcText from a single-use calculator into a workspace where calculations are organized and retrievable. **Success Criteria:** - Users find any document in < 3 seconds - Folder hierarchy is intuitive (create, nest, rename, delete) - Recent and Favorites provide quick access without browsing - Sidebar never feels cluttered even with 50+ documents --- ## Layout Structure ``` ┌──────────────────────┐ │ 🔍 Search... │ 32px — search bar ├──────────────────────┤ │ │ │ ▸ Recent │ section header (collapsible) │ 📄 Budget │ │ 📄 Quick Math │ │ 📄 Invoice #42 │ │ │ │ ▸ Favorites │ section header │ ⭐ Monthly Budget │ │ ⭐ Tax Calculator │ │ │ │ ▾ Files │ section header (expanded) │ 📁 Work │ folder │ │ 📄 Budget │ file in folder │ │ 📄 Invoice │ │ 📁 Personal │ folder │ │ 📁 Travel │ nested folder │ │ │ 📄 Trip Cost │ │ 📄 Scratch │ root-level file │ │ │ ▸ Templates │ section header │ │ ├──────────────────────┤ │ [+ Doc] [+ Folder] │ sticky footer └──────────────────────┘ ``` --- ## Spacing | Property | Token | Pixels | |----------|-------|--------| | Sidebar padding top | space-xs | 6px | | Search bar height | — | 32px | | Search bar margin | space-xs | 6px all sides | | Section header height | — | 28px | | Section header padding left | space-sm | 8px | | File item height | — | 28px | | File item padding left (root) | space-md | 12px | | File item indent per depth | — | 16px | | File icon size | — | 16px | | File icon-to-label gap | space-xs | 6px | | Section gap | space-xs | 6px | | Footer height | — | 40px | | Footer padding | space-xs | 6px | --- ## Typography | Element | Size | Weight | Color | |---------|------|--------|-------| | Search placeholder | text-xs | 400 | var(--text) at 50% | | Section header | text-2xs | 600 | var(--text) at 70% | | File name | text-xs | 400 | var(--text) | | File name (active) | text-xs | 500 | var(--text-h) | | Folder name | text-xs | 500 | var(--text) | | Footer buttons | text-2xs | 400 | var(--text), hover → var(--accent) | | File count badge | text-3xs | 400 | var(--text) at 40% | --- ## Search Bar **OBJECT ID:** `sidebar-search` | Property | Value | |----------|-------| | Placeholder | "Search documents..." | | Background | var(--bg) | | Border | 1px solid var(--border), focus → var(--accent-border) | | Border radius | 4px | | Icon | 🔍 magnifier, 14px, var(--text) at 40% | | Padding | 4px 8px 4px 28px (icon offset) | | Behavior | Filters file tree in real-time as user types | | Clear | × button appears when text entered | | Keyboard | Ctrl/Cmd+P opens/focuses search (like VS Code quick open) | | Results | Flat list of matching files, ranked by recency. Highlights matching text. | | Empty state | "No documents match '{query}'" | --- ## Section: Recent **OBJECT ID:** `sidebar-recent` | Property | Value | |----------|-------| | Content | Last 5 opened documents, sorted by lastOpened timestamp | | Collapsible | Yes, chevron toggle | | Default state | Expanded on first launch, remembers toggle | | Item display | File icon + name only (no folder path) | | Empty state | "No recent documents" in text-3xs, muted | | Update trigger | Opening any document pushes it to top, bumps oldest | --- ## Section: Favorites **OBJECT ID:** `sidebar-favorites` | Property | Value | |----------|-------| | Content | User-pinned documents, ordered manually (drag) | | Collapsible | Yes | | Default state | Collapsed if empty, expanded if has items | | Item display | ⭐ icon + name | | Add to favorites | Right-click file → "Add to Favorites", or drag file into section | | Remove | Right-click → "Remove from Favorites" | | Empty state | "Drag files here or right-click → Add to Favorites" | --- ## Section: Files (Tree) **OBJECT ID:** `sidebar-files` | Property | Value | |----------|-------| | Content | Complete folder tree with all documents | | Collapsible | Yes (section level) | | Default state | Expanded | | Sort | Folders first, then files. Alphabetical within each group | | Max depth | 3 levels (root → folder → subfolder → files). Prevents over-nesting | ### Folder Item **OBJECT ID:** `sidebar-folder` | Property | Value | |----------|-------| | Icon | 📁 (closed) / 📂 (open) — or chevron ▸/▾ | | Click | Toggle expand/collapse | | Double-click | Rename inline | | Right-click | Context menu | | Drag | Reorder within parent. Drop files into folder. | | Drop target | Highlight with var(--accent-bg) + 2px dashed var(--accent) border | | Badge | File count in parentheses: `Work (3)` — text-3xs, muted | ### File Item **OBJECT ID:** `sidebar-file` | Property | Value | |----------|-------| | Icon | 📄 (default) — could be themed per type later | | Click | Open in tab (or switch to existing tab if already open) | | Double-click | Open + rename inline | | Hover | var(--accent-bg) background | | Active | var(--accent-bg) + left 2px solid var(--accent) border | | Active = | Currently open in active tab | | Open indicator | Subtle dot or underline if open in any tab (even if not active) | | Drag | Move between folders. Drag to tab bar to open. | | Right-click | Context menu | ### File Context Menu | Item | Action | |------|--------| | Open | Open in new tab | | Open in New Tab | Open without closing current | | — | separator | | Rename | Inline rename | | Duplicate | Copy with "(copy)" suffix | | Add to Favorites | Toggle ⭐ | | — | separator | | Move to... | Submenu with folder list | | — | separator | | Delete | Confirm dialog → 5-second undo toast | ### Folder Context Menu | Item | Action | |------|--------| | New Document Here | Create file inside this folder | | New Subfolder | Create nested folder (max depth 3) | | — | separator | | Rename | Inline rename | | — | separator | | Delete Folder | Must be empty. If not: "Move contents to root first." | --- ## Section: Templates **OBJECT ID:** `sidebar-templates` | Property | Value | |----------|-------| | Collapsible | Yes | | Default state | Expanded on first launch | | Content | Pre-built starting documents | Full specification in [4.2 — Templates](../4.2-templates/4.2-templates.md). --- ## Sidebar Footer **OBJECT ID:** `sidebar-footer` | Property | Value | |----------|-------| | Position | Sticky bottom | | Background | var(--bg-secondary) | | Border top | 1px solid var(--border) | | Layout | Two buttons side-by-side | | Buttons | `[+ Document]` `[+ Folder]` — ghost style | | New Document | Creates at root level, opens in tab | | New Folder | Creates at root level, inline rename active | --- ## Drag and Drop | Drag Source | Drop Target | Behavior | |-------------|-------------|----------| | File | Folder | Move file into folder | | File | Between files | Reorder within same folder | | File | Tab bar | Open file in new tab | | File | Favorites section | Add to favorites | | Folder | Between folders | Reorder at same depth | | Tab | Sidebar folder | Move document to folder | ### Drop Visual Feedback | State | Appearance | |-------|------------| | Valid target hover | var(--accent-bg) background, 2px dashed var(--accent) border | | Invalid target | No visual change (drop not accepted) | | Insertion line | 2px solid var(--accent) horizontal line at insertion point | | Dragging item | 60% opacity, subtle shadow | --- ## Resize Handle | Property | Value | |----------|-------| | Position | Right edge of sidebar | | Width | 1px visible, 8px hit area | | Cursor | col-resize | | Color | var(--border), hover/drag → var(--accent) | | Constraints | Min 180px, max 400px | | Double-click | Reset to default 240px | | Persistence | Width stored in localStorage | --- ## Responsive Behavior | Breakpoint | Behavior | |------------|----------| | >= 1024px | Persistent side panel, resizable | | 768–1023px | Overlay drawer, hamburger toggle in header | | < 768px | Full-screen drawer (85vw, max 320px) | ### Mobile Drawer | Property | Value | |----------|-------| | Trigger | Hamburger menu (≡) in header | | Width | 85vw, max 320px | | Overlay | 50% black backdrop | | Animation | Slide from left, 200ms ease-out | | Close | Tap backdrop, swipe left, or × button top-right | | File tap | Opens document, auto-closes drawer | --- ## Page States | State | When | Behavior | |-------|------|----------| | **Empty** | No documents or folders | Show: "Welcome! Create your first document or pick a template." + prominent buttons | | **Few files** (<5) | Early usage | All sections visible, Templates expanded to encourage exploration | | **Many files** (>20) | Power user | Search becomes critical. Sections collapsed by default except Files | | **Search active** | User typed in search | Tree replaced by flat filtered list. Sections hidden. | | **Dragging** | File/folder being moved | Drop targets highlighted. Invalid areas dimmed. | --- ## Technical Notes - **Virtual scrolling:** Not needed until 500+ items. Standard DOM rendering is fine for typical usage. - **Folder persistence:** `folders: Folder[]` in localStorage with `parentId` for tree structure. - **Sort stability:** Alphabetical sort is stable — user manual ordering within a folder stored as `order` field. - **Cross-platform:** Maps to NSOutlineView (macOS), Tree widget (iced/Windows). Same data model. --- _Created using Whiteport Design Studio (WDS) methodology_