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,278 @@
# 6.1 — Mobile Experience
**Previous Step:** ← [Theme System](../../05-theming/5.1-theme-system/5.1-theme-system.md)
---
## Page Metadata
| Property | Value |
|----------|-------|
| **Scenario** | 06 — Mobile Experience |
| **Page Number** | 6.1 |
| **Platform** | Web (PWA) — mobile viewport |
| **Page Type** | Responsive Adaptation (all app shell components) |
| **Viewport** | < 768px |
| **Interaction** | Touch-first |
---
## Overview
**Page Purpose:** Define how the entire CalcText workspace adapts to mobile. This is NOT a separate app it's the same app intelligently restructured for touch and small screens. Every feature remains accessible; nothing is hidden or removed.
**Current Problem:** The existing web app hides results, toolbar, and divider on mobile effectively removing the product's value on the most common device type.
**Success Criteria:**
- All features accessible on mobile (calculations, results, file management, themes)
- Touch targets >= 44px
- One-handed operation possible for core flow (type → see result)
- Feels like a native mobile app when installed as PWA
---
## Mobile Layout (< 768px)
```
┌─────────────────────────────┐
│ Header [≡] CalcText [🎨]│ 44px (touch-sized)
├─────────────────────────────┤
│ Tab Bar (horizontal scroll) │ 40px
├─────────────────────────────┤
│ │
│ │
│ Editor │
│ (full width) │
│ │
│ │
│ │
├─────────────────────────────┤
│ ═══ Results Tray │ 48px collapsed
│ Last: $4,300 │
├─────────────────────────────┤
│ Status (simplified) │ 24px
└─────────────────────────────┘
```
---
## Component Adaptations
### Header (Mobile)
| Property | Desktop | Mobile |
|----------|---------|--------|
| Height | 40px | 44px (touch target) |
| Left content | Logo + "CalcText" | [≡] hamburger + "CalcText" |
| Right content | Theme + Settings + ⌘ | [🎨] theme only |
| Padding | 12px 12px | 8px 12px |
| Hamburger | N/A | 44px × 44px touch target, opens sidebar drawer |
### Tab Bar (Mobile)
| Property | Desktop | Mobile |
|----------|---------|--------|
| Height | 36px | 40px |
| Tab min width | 100px | 80px (more compact) |
| Close button | Visible on hover/active | Hidden — swipe left to reveal |
| New tab (+) | After last tab | Sticky far-right |
| Scroll | Mouse wheel | Touch swipe horizontal |
| Active indicator | Top 2px accent border | Bottom 2px accent border (thumb reachable) |
### Editor (Mobile)
| Property | Desktop | Mobile |
|----------|---------|--------|
| Width | Flex (shared with results) | 100vw |
| Line padding | 12px | 12px |
| Gutter | 40px (line numbers) | 32px (compact numbers) |
| Font size | 15px | 15px (same — readable on mobile) |
| Line height | 24px | 24px (same) |
| Keyboard | Physical | Virtual — editor scrolls above keyboard |
#### Virtual Keyboard Handling
| Property | Value |
|----------|-------|
| Viewport | Uses `100dvh` (dynamic viewport height) to account for keyboard |
| Scroll | Editor auto-scrolls to keep cursor visible above keyboard |
| Results tray | Hides when keyboard is open (not enough space) |
| Status bar | Hides when keyboard is open |
### Results Tray (Mobile)
Replaces the side panel with a bottom tray.
| State | Height | Content |
|-------|--------|---------|
| **Collapsed** | 48px | Drag handle + last non-empty result |
| **Expanded** | 40vh (max 60vh) | Full scrollable results list |
| **Hidden** | 0px | When virtual keyboard is open |
#### Collapsed Tray
| Property | Value |
|----------|-------|
| Background | var(--bg-secondary) |
| Border top | 1px solid var(--border) |
| Drag handle | 32px × 4px pill, var(--border), centered |
| Content | "Last: {value}" — last non-empty result, text-xs |
| Tap | Expand tray |
| Swipe up | Expand tray |
#### Expanded Tray
| Property | Value |
|----------|-------|
| Content | All results paired with expressions |
| Item format | Line number + expression snippet + result value |
| Item height | 44px (touch-friendly) |
| Active line | var(--accent-bg) highlight |
| Tap result | Copy to clipboard + brief feedback |
| Swipe down | Collapse tray |
| Tap drag handle | Collapse |
| Scroll | Independent vertical scroll |
#### Tray Interaction
```
┌──────────────────────────────┐
│ ═══ (drag handle) │ Swipe up to expand
│ Last: $4,300 │
├──────────────────────────────┤ ← expanded state below
│ 5 salary 5,000 │
│ 6 freelance 1,200 │
│ 7 total_income 6,200 │ ← highlighted (active line)
│ 9 rent 1,500 │
│ 10 groceries 400 │
│ 13 total_expenses 1,900 │
│ 14 savings 4,300 │
└──────────────────────────────┘
```
### Sidebar Drawer (Mobile)
| Property | Value |
|----------|-------|
| Trigger | Hamburger [≡] in header |
| Width | 85vw, max 320px |
| Position | Fixed left, full height |
| Background | var(--bg) |
| Backdrop | rgba(0, 0, 0, 0.5) — tap to close |
| Animation | translateX(-100%) → translateX(0), 200ms ease-out |
| Close | Tap backdrop, swipe left, × button (top-right, 44px target) |
| Content | Same sections as desktop sidebar (search, recent, favorites, files, templates) |
| File tap | Opens document → auto-closes drawer |
| Search | Full width, 44px height (touch target) |
| File items | 44px height (touch target, up from 28px desktop) |
### Theme Picker (Mobile)
| Property | Value |
|----------|-------|
| Trigger | [🎨] button in header |
| Style | Bottom sheet (slides from bottom) |
| Height | Auto (content-driven), max 60vh |
| Border radius | 12px 12px 0 0 |
| Drag handle | 32px × 4px pill, centered |
| Items | 48px height per theme (touch targets) |
| Accent swatches | 32px circles, 8px gap (larger for touch) |
| Close | Swipe down, tap backdrop |
### Status Bar (Mobile)
| Property | Value |
|----------|-------|
| Height | 24px (same) |
| Content | Cursor position + engine status dot only |
| Hidden items | Line count, theme indicator (accessible elsewhere) |
| Hidden | When virtual keyboard is open |
---
## Touch Gestures
| Gesture | Context | Action |
|---------|---------|--------|
| Swipe left on tab | Tab bar | Reveal close button |
| Swipe up on results tray | Results | Expand tray |
| Swipe down on results tray | Results | Collapse tray |
| Swipe left from right edge | Sidebar drawer | Close drawer |
| Swipe down on bottom sheet | Theme picker | Close sheet |
| Long press on file | Sidebar | Show context menu |
| Long press on tab | Tab bar | Drag to reorder |
| Tap result | Results tray | Copy to clipboard |
| Pinch | Editor | Zoom font size (optional) |
---
## Breakpoint Details
| Width | Classification | Key Adaptations |
|-------|---------------|-----------------|
| **>= 1024px** | Desktop | Full 3-panel layout |
| **7681023px** | Tablet | Sidebar → overlay drawer. Editor + results side-by-side. |
| **480767px** | Mobile | Single column. Results tray. Sidebar drawer. Touch targets 44px. |
| **< 480px** | Small mobile | Same as mobile. Tab labels may truncate. Logo text hidden. |
### Tablet Specifics (7681023px)
| Component | Behavior |
|-----------|----------|
| Sidebar | Overlay drawer (hamburger toggle) instead of persistent panel |
| Editor + Results | Side-by-side with divider (same as desktop) |
| Tab bar | Same as desktop (enough width) |
| Header | Show hamburger [≡] instead of persistent sidebar |
| Theme picker | Dropdown (same as desktop) |
---
## PWA Mobile Enhancements
| Feature | Implementation |
|---------|---------------|
| Standalone display | `display: standalone` no browser chrome |
| Status bar color | `theme-color` meta tag updates per theme |
| Safe areas | `env(safe-area-inset-*)` for notched devices |
| Splash screen | Theme-colored background + CalcText logo |
| Home screen icon | App icon with accent color ring |
| Orientation | Portrait preferred, landscape supported |
### Safe Area Padding
```css
.calcpad-app {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
```
---
## Page States (Mobile-Specific)
| State | When | Behavior |
|-------|------|----------|
| **Keyboard open** | User tapped editor | Results tray + status bar hide. Editor fills available space. |
| **Keyboard closed** | User tapped outside or pressed Done | Results tray + status bar reappear. |
| **Drawer open** | Hamburger tapped | Sidebar overlays. Backdrop captures tap to close. |
| **Tray expanded** | User swiped up | 40vh results list. Editor partially visible above. |
| **Offline** | No network | Status bar shows offline indicator. All features work. |
---
## Technical Notes
- **Viewport units:** Use `dvh` (dynamic viewport height) not `vh` to handle mobile browser chrome and virtual keyboard.
- **Touch events:** Use `touchstart`/`touchmove`/`touchend` for swipe gestures. Consider `passive: true` for scroll performance.
- **Overscroll:** Disable `overscroll-behavior: none` on app container to prevent pull-to-refresh interference.
- **iOS safe areas:** Test with iPhone notch and dynamic island. Apply `env(safe-area-inset-*)`.
- **Android back button:** In PWA mode, back button should close drawers/sheets before navigating back.
- **Font scaling:** Respect system font size on mobile. Use relative units where possible.
- **Cross-platform:** Mobile web layout does NOT need to port to native mobile (that's a separate app). But interaction patterns (swipe, long-press) inform native mobile design if built later.
---
_Created using Whiteport Design Studio (WDS) methodology_