Files
C. Cassel 0d38bd3108 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>
2026-03-18 09:12:05 -04:00

279 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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_