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:
2026-03-18 09:12:05 -04:00
parent 806e2f1ec6
commit 0d38bd3108
78 changed files with 8175 additions and 421 deletions

View File

@@ -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 |
| 7681023px | 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_

View File

@@ -0,0 +1,219 @@
# 4.2 — Templates
**Previous Step:** ← [Sidebar](../4.1-sidebar/4.1-sidebar.md)
**Next Step:** → [Theme System](../../05-theming/5.1-theme-system/5.1-theme-system.md)
---
## Page Metadata
| Property | Value |
|----------|-------|
| **Scenario** | 04 — File Organization |
| **Page Number** | 4.2 |
| **Platform** | Web (PWA), portable to macOS/Windows |
| **Page Type** | Sidebar Section + Modal (template preview) |
---
## Overview
**Page Purpose:** Provide ready-made starting documents that showcase CalcText's capabilities and help users get productive immediately. Templates are the product's best onboarding tool — they show by example.
**Success Criteria:**
- First-time user finds a relevant template within 10 seconds
- Templates demonstrate the product's unique features (variables, units, currencies, aggregators)
- Using a template creates a new document (never modifies the template)
---
## Template Library
| Template | Description | Showcases |
|----------|-------------|-----------|
| **Budget** | Monthly income/expenses with categories | Variables, aggregators (sum, total), percentages |
| **Invoice** | Service invoice with line items and tax | Variables, multiplication, percentages, currency |
| **Unit Converter** | Common conversions with examples | Unit expressions (kg to lb, km to mi, °C to °F) |
| **Trip Planner** | Travel budget with currency conversion | Currency conversion, date math, variables |
| **Loan Calculator** | Mortgage/loan with monthly payments | Financial functions, percentages, variables |
| **Blank** | Empty document | — (clean start) |
---
## Sidebar Templates Section
**OBJECT ID:** `sidebar-templates`
| Property | Value |
|----------|-------|
| Section header | "Templates" with 📋 icon |
| Collapsible | Yes |
| Default | Expanded on first launch, collapsed after first document created |
| Item height | 32px (slightly taller than files — more padding) |
| Item icon | Colored dot per template (visual distinction) |
| Item label | Template name, text-xs |
| Item sublabel | Brief description, text-3xs, muted, truncated |
### Template Item Interaction
| Action | Behavior |
|--------|----------|
| Click | Create new document from template. Title = template name. Opens in new tab. |
| Hover | Show full description in tooltip |
| Right-click | "Preview" option |
---
## Template Colors (Icon Dots)
| Template | Dot Color |
|----------|-----------|
| Budget | #10b981 (emerald) |
| Invoice | #6366f1 (indigo) |
| Unit Converter | #0d9488 (teal) |
| Trip Planner | #f59e0b (amber) |
| Loan Calculator | #7c3aed (violet) |
| Blank | var(--border) (gray) |
---
## Template Content
### Budget Template
```
# Monthly Budget
// Income
salary = 5000
freelance = 1200
total_income = salary + freelance
// Housing
rent = 1500
utilities = 150
insurance = 80
// Living
groceries = 400
transport = 120
subscriptions = 45
// Summary
total_expenses = sum
savings = total_income - total_expenses
savings_rate = savings / total_income
```
### Invoice Template
```
# Invoice #001
// Client: [Client Name]
// Date: [Date]
// Services
web_design = 2500
development = 4000
consulting = 150 * 8
// Expenses
hosting = 29.99
domain = 12.00
subtotal = sum
// Tax
tax_rate = 10%
tax = subtotal * tax_rate
total = subtotal + tax
```
### Unit Converter Template
```
# Unit Converter
// Weight
75 kg in lb
2.5 lb in kg
100 g in oz
// Distance
10 km in mi
26.2 mi in km
5280 ft in m
// Temperature
100 °C in °F
72 °F in °C
0 °C in K
// Data
1 GB in MB
500 MB in GB
1 TB in GB
```
### Trip Planner Template
```
# Trip Planner
// Budget
budget = $3000
// Flights
flight_out = $450
flight_back = $380
// Hotel
nights = 7
rate_per_night = $120
hotel_total = nights * rate_per_night
// Daily expenses
daily_food = $50
daily_transport = $20
daily_activities = $35
daily_total = daily_food + daily_transport + daily_activities
trip_expenses = daily_total * nights
// Summary
total_cost = flight_out + flight_back + hotel_total + trip_expenses
remaining = budget - total_cost
```
### Loan Calculator Template
```
# Loan Calculator
// Loan Details
principal = 250000
annual_rate = 6.5%
years = 30
// Monthly Calculation
monthly_rate = annual_rate / 12
num_payments = years * 12
// Monthly Payment
monthly_payment = principal * (monthly_rate * (1 + monthly_rate) ^ num_payments) / ((1 + monthly_rate) ^ num_payments - 1)
// Total Cost
total_paid = monthly_payment * num_payments
total_interest = total_paid - principal
// Summary
interest_ratio = total_interest / principal
```
---
## Technical Notes
- Templates are hardcoded in the app (not fetched from server). Stored as string constants.
- Creating from template: deep copy content, assign new id/title, save to documents array.
- Future: user-created templates (save document as template). Defer to v2.
- Cross-platform: same template content across all platforms.
---
_Created using Whiteport Design Studio (WDS) methodology_