feat(web): implement complete workspace with themes, tabs, sidebar, and mobile
Transform CalcText from a single-document calculator into a full workspace application with multi-document support, theming, and responsive mobile experience. - Theme system: 5 presets (Light, Dark, Matrix, Midnight, Warm) + accent colors - Document model with localStorage persistence and auto-save - Tab bar with keyboard shortcuts (Ctrl+N/W/Tab/1-9), rename, close - Sidebar with search, recent, favorites, folders, templates, drag-and-drop - 5 templates: Budget, Invoice, Unit Converter, Trip Planner, Loan Calculator - Status bar with cursor position, engine status, dedication to Igor Cassel - Results panel: type-specific colors, click-to-copy, error hints - Format toolbar: H, B, I, //, color labels with live preview toggle - Syntax highlighting using theme CSS variables - Error hover tooltips - Mobile: bottom results tray, sidebar drawer, touch targets, safe areas - Docker multi-stage build (Rust WASM + Vite + Nginx) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
# 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_
|
||||
Reference in New Issue
Block a user