# 1.1 — App Shell **Next Step:** → [Status Bar](../1.2-status-bar/1.2-status-bar.md) --- ## Page Metadata | Property | Value | |----------|-------| | **Scenario** | 01 — Workspace Shell | | **Page Number** | 1.1 | | **Platform** | Web (PWA), portable to macOS/Windows | | **Page Type** | Full Application Shell | | **Viewport** | Desktop-first, responsive to mobile | | **Interaction** | Mouse + keyboard (primary), touch (secondary) | | **Visibility** | Public (no auth required) | --- ## Overview **Page Purpose:** The app shell is the top-level container that defines the spatial structure of the entire CalcText workspace. It arranges all panels (sidebar, editor, results), the tab bar, header, and status bar into a cohesive layout that persists across all user interactions. **User Situation:** User opens CalcText in a browser. They expect a professional workspace where they can write calculations, manage files, and personalize their environment. First-time users should immediately understand the layout. Returning users should find their documents and preferences exactly as they left them. **Success Criteria:** - User understands the 3-panel layout within 3 seconds - All panels are resizable and collapsible - Layout state persists across sessions (sidebar width, panel visibility) - Feels native — not like a web page **Entry Points:** - Direct URL (calctext.app or localhost) - PWA launch from desktop/dock - Returning session (restores last state from localStorage) **Exit Points:** - Close browser/PWA (state auto-saves) - All navigation is within the shell (no page transitions) --- ## Reference Materials **Strategic Foundation:** - [Product Brief](../../../A-Product-Brief/project-brief.md) — Workspace evolution, web-first - [Brownfield Analysis](../../../A-Product-Brief/01-brownfield-analysis.md) — Current CSS tokens, components, gaps **Related Pages:** - [Status Bar](../1.2-status-bar/1.2-status-bar.md) — Bottom status strip - Tab Bar (Scenario 03) — Document tabs above editor - Sidebar (Scenario 04) — File tree panel - Editor (Scenario 02) — Calculation editor - Results Panel (Scenario 02) — Results display --- ## Layout Structure The app shell uses a 4-region layout: Header, Sidebar, Main Area (tabs + editor + results), and Status Bar. ### Desktop (>= 768px) ``` ┌─────────────────────────────────────────────────────────┐ │ Header [Logo] [Theme] [Settings] [⌘] │ 40px ├────────┬────────────────────────────────────────────────┤ │ │ Tab Bar [Budget ×] [Invoice ×] [+] │ 36px │ ├─────────────────────────┬──┬──────────────────┤ │ Side │ │ │ │ │ bar │ Editor │ D│ Results │ │ │ (CodeMirror 6) │ iv│ Panel │ │ 240px │ │ │ │ │ (coll │ │ │ │ │ apsi │ │ │ │ │ ble) │ │ │ │ │ │ │ │ │ ├────────┴─────────────────────────┴──┴──────────────────┤ │ Status Bar [Ln 12, Col 8] [Engine ●] [Dark 🎨] │ 24px └─────────────────────────────────────────────────────────┘ ``` ### Tablet (768px — 1024px) ``` ┌─────────────────────────────────────────┐ │ Header [Logo] [Theme] [≡] │ 40px ├─────────────────────────────────────────┤ │ Tab Bar [Budget ×] [Invoice ×] [+] │ 36px ├─────────────────────────┬──┬────────────┤ │ │ │ │ │ Editor │ D│ Results │ │ (CodeMirror 6) │ iv│ Panel │ │ │ │ │ ├─────────────────────────┴──┴────────────┤ │ Status Bar │ 24px └─────────────────────────────────────────┘ Sidebar: overlay drawer via hamburger [≡] ``` ### Mobile (< 768px) ``` ┌─────────────────────────┐ │ Header [Logo] [≡] │ 44px (touch) ├─────────────────────────┤ │ Tab Bar (scrollable) │ 36px ├─────────────────────────┤ │ │ │ Editor │ │ (full width) │ │ │ │ │ ├─────────────────────────┤ │ Results Tray (toggle) │ 48px collapsed / 40vh expanded ├─────────────────────────┤ │ Status Bar │ 24px └─────────────────────────┘ Sidebar: full-screen drawer Results: bottom tray with drag handle ``` --- ## Spacing **Scale:** [Spacing Scale](../../../D-Design-System/00-design-system.md#spacing-scale) | Property | Token | Pixels (proposed) | |----------|-------|--------------------| | Page padding (horizontal) | space-zero | 0px (panels fill edge-to-edge) | | Header padding (horizontal) | space-md | 12px | | Header padding (vertical) | space-xs | 6px | | Sidebar width (default) | — | 240px | | Sidebar min width | — | 180px | | Sidebar max width | — | 400px | | Divider width (sidebar ↔ editor) | — | 1px visible, 8px hit area | | Divider width (editor ↔ results) | — | 1px visible, 8px hit area | | Tab bar height | — | 36px | | Tab padding (horizontal) | space-sm | 8px | | Status bar height | — | 24px | | Status bar padding (horizontal) | space-md | 12px | --- ## Typography **Scale:** [Type Scale](../../../D-Design-System/00-design-system.md#type-scale) | Element | Semantic | Size | Weight | Typeface | |---------|----------|------|--------|----------| | App title (header) | — | text-sm | 600 | system sans | | Tab label | — | text-xs | 400 (normal), 500 (active) | system sans | | Status bar text | — | text-3xs | 400 | system mono | | Sidebar section title | H3 | text-2xs | 600 | system sans | | Sidebar file name | — | text-xs | 400 | system sans | | Editor content | — | text-md | 400 | system mono | | Results value | — | text-md | 400 | system mono | --- ## Page Sections ### Section: Header **OBJECT ID:** `shell-header` | Property | Value | |----------|-------| | Purpose | App identity, global actions, theme quick-switch | | Height | 40px (desktop/tablet), 44px (mobile — touch target) | | Background | var(--bg) | | Border | bottom 1px solid var(--border) | | Layout | Horizontal: logo-left, actions-right | #### Logo Group **OBJECT ID:** `shell-header-logo` | Property | Value | |----------|-------| | Content | CalcText icon + wordmark | | Icon size | 20px × 20px | | Wordmark | "CalcText" in text-sm, weight 600 | | Gap | space-xs (6px) between icon and wordmark | | Mobile | Wordmark hidden < 480px, icon only | #### Header Actions **OBJECT ID:** `shell-header-actions` | Property | Value | |----------|-------| | Layout | Horizontal, space-xs gap | | Items | Theme toggle, Settings button, Keyboard shortcuts (⌘) | | Button size | 28px × 28px (icon buttons) | | Icon size | 16px | | Style | Ghost buttons — transparent bg, var(--text) icon, hover → var(--accent-bg) | #### Theme Toggle (Header) **OBJECT ID:** `shell-header-theme-toggle` | Property | Value | |----------|-------| | Component | Icon button with dropdown | | Icon | Sun (light), Moon (dark), Terminal (matrix), Palette (custom) | | Click | Opens theme picker dropdown | | Tooltip | "Switch theme (Ctrl+Shift+T)" | #### ↕ `shell-header-v-space-zero` — Header sits flush against tab bar below --- ### Section: Sidebar **OBJECT ID:** `shell-sidebar` | Property | Value | |----------|-------| | Purpose | File navigation, document organization, templates | | Width | 240px default, resizable (180–400px), collapsible to 0 | | Background | var(--bg-secondary) | | Border | right 1px solid var(--border) | | Toggle | Cmd/Ctrl+B to show/hide | | Resize | Drag right edge, cursor col-resize | | Persistence | Width and visibility stored in localStorage | #### Sidebar Sections **OBJECT ID:** `shell-sidebar-sections` | Section | Icon | Content | |---------|------|---------| | **Recent** | 🕐 | Last 5 opened documents, sorted by time | | **Favorites** | ⭐ | User-pinned documents | | **Files** | 📁 | Full folder tree with nested structure | | **Templates** | 📋 | Pre-built starting points (Budget, Invoice, Unit Converter, Trip Planner, Blank) | Each section is collapsible with a chevron toggle. #### File Tree Item **OBJECT ID:** `shell-sidebar-file-item` | Property | Value | |----------|-------| | Height | 28px | | Padding left | 12px + (depth × 16px) for nesting | | Icon | 📄 file / 📁 folder (closed) / 📂 folder (open) | | Label | File/folder name, text-xs, ellipsis on overflow | | Hover | var(--accent-bg) background | | Active | var(--accent-bg) + left 2px accent border | | Right-click | Context menu: Rename, Delete, Duplicate, Move to folder, Add to favorites | | Double-click | Opens document in new tab | | Drag | Reorder within folder, drag between folders | #### Sidebar Footer **OBJECT ID:** `shell-sidebar-footer` | Property | Value | |----------|-------| | Content | [+ New Document] button, [+ New Folder] button | | Layout | Horizontal, full width, space-xs gap | | Button style | Ghost, text-2xs, var(--text), hover → var(--accent) | | Position | Sticky bottom of sidebar | | Padding | space-sm | | Border | top 1px solid var(--border) | --- ### Section: Tab Bar **OBJECT ID:** `shell-tabbar` | Property | Value | |----------|-------| | Purpose | Multi-document navigation, quick tab management | | Height | 36px | | Background | var(--bg-secondary) | | Border | bottom 1px solid var(--border) | | Layout | Horizontal scroll when tabs overflow | | Position | Between header and editor area | #### Tab Item **OBJECT ID:** `shell-tabbar-tab` | Property | Value | |----------|-------| | Min width | 100px | | Max width | 200px | | Padding | 0 space-sm (0 8px) | | Height | 36px (fills bar) | | Label | Document title, text-xs, ellipsis on overflow | | Modified indicator | Dot (6px) before title when unsaved changes | | Close button | × icon, 14px, visible on hover or active tab | | Active state | var(--bg) background, no bottom border (connected to editor) | | Inactive state | var(--bg-secondary), bottom border 1px solid var(--border) | | Hover (inactive) | var(--bg-secondary) lightened slightly | | Drag | Reorder tabs via drag-and-drop | | Middle-click | Close tab | | Double-click | Rename document inline | #### New Tab Button **OBJECT ID:** `shell-tabbar-new` | Property | Value | |----------|-------| | Icon | + (16px) | | Size | 36px × 36px (square, fills bar height) | | Style | Ghost, var(--text), hover → var(--accent) | | Click | Creates "Untitled" document and switches to it | | Position | After last tab, before overflow | #### Tab Overflow **OBJECT ID:** `shell-tabbar-overflow` | Property | Value | |----------|-------| | Trigger | When tabs exceed container width | | Behavior | Horizontal scroll with mouse wheel or trackpad | | Indicators | Fade gradient on edges when scrollable | | Keyboard | Ctrl+Tab / Ctrl+Shift+Tab to cycle tabs | --- ### Section: Main Area **OBJECT ID:** `shell-main` | Property | Value | |----------|-------| | Purpose | Contains the active document's editor and results panel | | Layout | Horizontal flex: editor (flex: 3) + divider + results (flex: 1) | | Background | var(--bg) | | Content | Delegates to Scenario 02 (Editor + Results Panel) | #### Editor Pane **OBJECT ID:** `shell-main-editor` | Property | Value | |----------|-------| | Flex | 3 (default ~75%) | | Min width | 300px | | Content | CodeMirror 6 instance (see Scenario 02) | | Overflow | Vertical scroll (editor handles internally) | #### Pane Divider (Editor ↔ Results) **OBJECT ID:** `shell-main-divider` | Property | Value | |----------|-------| | Width | 1px visible line | | Hit area | 8px (invisible padding for easy grabbing) | | Cursor | col-resize | | Color | var(--border), hover → var(--accent) | | Transition | background 0.15s | | Double-click | Reset to default 75/25 split | | Persistence | Position stored in localStorage | #### Results Pane **OBJECT ID:** `shell-main-results` | Property | Value | |----------|-------| | Flex | 1 (default ~25%) | | Min width | 120px | | Content | Results panel (see Scenario 02) | | Scroll sync | Mirrors editor scroll position | --- ### Section: Status Bar **OBJECT ID:** `shell-statusbar` | Property | Value | |----------|-------| | Purpose | Contextual info: cursor position, engine status, theme indicator | | Height | 24px | | Background | var(--bg-secondary) | | Border | top 1px solid var(--border) | | Font | text-3xs, monospace | | Color | var(--text) | | Layout | Horizontal: left-info + right-info | Full specification in [1.2 — Status Bar](../1.2-status-bar/1.2-status-bar.md). --- ## Page States | State | When | Appearance | Actions | |-------|------|------------|---------| | **First Launch** | No localStorage data | Sidebar open with Templates section expanded. Single tab "Welcome" with demo calctext. Theme follows OS preference. | User can start typing, explore templates, or create new doc | | **Returning User** | localStorage has documents | Restores: last open tabs, active tab, sidebar state, theme, divider positions | Resume exactly where they left off | | **Empty Workspace** | All documents deleted | Editor shows subtle placeholder: "Create a new document or choose a template to get started" | + New Document button prominent, Templates section highlighted | | **Engine Loading** | WASM initializing | Status bar shows "Engine loading..." with pulse animation. Editor is editable. Results show "—" | Editor works, results appear once engine is ready | | **Offline** | No network | Subtle indicator in status bar. All features work (localStorage). Currency rates may be stale. | Full functionality, offline banner only if currency conversion attempted | --- ## Interactions & Keyboard Shortcuts | Shortcut | Action | |----------|--------| | Cmd/Ctrl + B | Toggle sidebar | | Cmd/Ctrl + N | New document | | Cmd/Ctrl + W | Close active tab | | Cmd/Ctrl + Tab | Next tab | | Cmd/Ctrl + Shift + Tab | Previous tab | | Cmd/Ctrl + 1–9 | Switch to tab N | | Cmd/Ctrl + Shift + T | Open theme picker | | Cmd/Ctrl + , | Open settings | | Cmd/Ctrl + S | Force save (visual confirmation — auto-save is default) | --- ## Responsive Behavior | Breakpoint | Layout Changes | |------------|----------------| | **>= 1024px** | Full 3-panel: sidebar + editor + results | | **768–1023px** | Sidebar becomes overlay drawer (hamburger toggle). Editor + results remain side-by-side | | **< 768px** | Single column. Sidebar = full-screen drawer. Results = bottom tray (collapsible). Tabs = horizontal scroll. Header = 44px (touch). | ### Mobile Results Tray | Property | Value | |----------|-------| | Collapsed height | 48px (shows last result + drag handle) | | Expanded height | 40vh | | Drag handle | 32px × 4px pill, centered, var(--border) | | Swipe up | Expand tray | | Swipe down | Collapse tray | | Tap collapsed | Expand tray | ### Mobile Sidebar Drawer | Property | Value | |----------|-------| | Width | 85vw (max 320px) | | Background | var(--bg) | | Overlay | 50% black backdrop | | Animation | Slide from left, 200ms ease-out | | Close | Tap backdrop, swipe left, or X button | --- ## Theme Integration The app shell's colors are entirely driven by CSS custom properties. Switching themes means swapping the property values on `:root`. No component changes needed. | Theme | --bg | --bg-secondary | --text | --accent | Special | |-------|------|----------------|--------|----------|---------| | **Light** | #fff | #f8f9fa | #6b6375 | #6366f1 | — | | **Dark** | #16171d | #1a1b23 | #9ca3af | #818cf8 | — | | **Matrix** | #0a0a0a | #0f0f0f | #00ff41 | #00ff41 | Monospace everywhere. Subtle scanline overlay. Cursor blink green. | | **Custom** | User-defined | User-defined | User-defined | User-defined | Accent color picker + base tone (warm/cool/neutral) | Theme selection persisted in localStorage as `calctext-theme`. --- ## localStorage Schema ```typescript interface CalcTextStorage { // Documents documents: Document[] folders: Folder[] activeTabId: string openTabIds: string[] // Layout sidebarWidth: number sidebarVisible: boolean dividerPosition: number // percentage // Preferences theme: 'light' | 'dark' | 'matrix' | string // string for custom customTheme?: ThemeTokens accentColor?: string // State lastOpenedAt: string // ISO timestamp } interface Document { id: string title: string content: string folderId: string | null isFavorite: boolean createdAt: string updatedAt: string } interface Folder { id: string name: string parentId: string | null order: number } ``` --- ## Technical Notes - **Cross-platform portability:** All layout patterns map to native equivalents. Sidebar → NavigationView (SwiftUI) / side_panel (iced). Tab bar → TabView. Status bar → standard OS status bar pattern. - **Performance:** Only the active tab's CodeMirror instance should be in DOM. Inactive tabs store content in memory, restore on switch. - **Auto-save:** Documents save to localStorage on every change (debounced 500ms). No explicit "save" needed, but Cmd+S provides visual confirmation. - **Sidebar resize:** Use ResizeObserver + mouse events. Store width in localStorage. Minimum 180px, maximum 400px. - **Tab management:** Maximum suggested tabs: 20. Beyond that, show "too many tabs" hint. No hard limit. --- ## Open Questions | # | Question | Context | Status | |---|----------|---------|--------| | 1 | Should Matrix theme have a subtle CRT scanline effect? | Could be fun but might impact readability | 🔴 Open | | 2 | Should we support tab groups / workspaces? | Multiple sets of tabs for different projects | 🔴 Open — defer to v2 | | 3 | Max localStorage size for documents? | ~5MB browser limit. Need strategy for large collections. | 🟡 In Discussion — may need IndexedDB | --- ## Checklist - [x] Page purpose clear - [x] All Object IDs assigned - [x] Layout structure defined (desktop, tablet, mobile) - [x] Spacing tokens documented - [x] Typography scale applied - [x] States documented (first launch, returning, empty, loading, offline) - [x] Keyboard shortcuts defined - [x] Responsive breakpoints specified - [x] Theme integration documented - [x] localStorage schema defined - [x] Cross-platform portability noted - [x] Open questions captured --- **Next Step:** → [Status Bar](../1.2-status-bar/1.2-status-bar.md) --- _Created using Whiteport Design Studio (WDS) methodology_