openpencil/openspec/changes/mobile-layout/proposal.md
Anton Soldatov 168c25c189
feat: mobile layout, PWA support (#27) (#27)
- Mobile-responsive editor with bottom drawer, ribbon nav, HUD overlay
- Touch support: single-finger tools, two-finger pinch-zoom
- PWA: manifest, service worker, installability
- Extract LayerTree from LayersPanel, shared utils (colorToCSS, initials, toolIcons)
- Constants moved to src/constants.ts, clipboard state to editor store
- reka-ui Popover/DropdownMenu in MobileHud

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-03-05 19:51:51 +03:00

47 lines
3.3 KiB
Markdown

## Why
The editor has a fixed three-column desktop layout (layers | canvas | properties) using reka-ui Splitter. On mobile/tablet viewports (<768px), the side panels consume all usable space, making the canvas unusable. There's no responsive behavior, no breakpoint detection, and no mobile-optimized UI. The canvas already handles touch pinch-zoom, so the rendering layer is ready — the chrome needs to adapt.
## What Changes
- Detect mobile viewport via `useMediaQuery('(max-width: 767px)')` from `@vueuse/core` in EditorView
- On mobile: hide desktop side panels, show canvas fullscreen with HUD overlay
- Add a custom bottom drawer (CSS translateY + transition) that slides up to reveal panel content. Snap points: closed, half (~3/7 viewport), full (viewport minus HUD area)
- Fixed ribbon tab bar at viewport bottom — always visible and thumb-reachable
- Ribbon tabs: Layers and Design as separate buttons (with label when active), Code and AI as icon-only buttons on the right
- Extract layer tree into `LayerTree.vue` for reuse in both desktop LayersPanel and mobile drawer
- Render DesignPanel, CodePanel, ChatPanel directly in mobile drawer via `v-show` (preserve ChatPanel state)
- PagesPanel in compact drawer header; AppMenu hidden on mobile
- MobileHud: undo/redo buttons, active tool indicator, online badge with peers dropdown, action toast, Share button, burger menu (New/Open/Save/Export/Zoom to fit)
- Mobile toolbar with 3 categories (Tools/Edit/Arrange), arrow navigation, animated width transitions
- Touch-to-mouse event synthesis for non-HAND tools in canvas input
- Rulers hidden on mobile
- Internal clipboard buffer for copy/paste (mobile browser clipboard API limitations)
- Fix `showUI` initialization to `true` (was gated by matchMedia)
- ⌘J shortcut bridges mobile/desktop: toggles `activeRibbonTab` on mobile
- Mobile state (`activeRibbonTab`, `panelMode`, `mobileDrawerSnap`, `actionToast`) in editor store
- Z-index layering: canvas < toolbar (z-10) < ribbon (z-40) < drawer (z-30) < popovers (z-50)
- Desktop layout completely unchanged
## Capabilities
### New Capabilities
- `mobile-layout`: Responsive mobile/tablet layout with custom bottom drawer, fixed ribbon tabs, MobileHud overlay, touch tool support, and adaptive panel switching
### Modified Capabilities
- `editor-ui`: EditorView gains responsive breakpoint detection and conditional rendering of desktop vs mobile chrome
## Impact
- `src/views/EditorView.vue` — conditional desktop/mobile layout
- `src/components/MobileDrawer.vue` — new: custom drawer with translateY transitions and drag gestures
- `src/components/MobileRibbon.vue` — new: fixed bottom tab bar
- `src/components/MobileHud.vue` — new: overlay with undo/redo, tool indicator, online badge, toast, burger menu
- `src/components/LayerTree.vue` — new: extracted from LayersPanel
- `src/components/LayersPanel.vue` — refactored to use LayerTree
- `src/components/Toolbar.vue` — 3 mobile categories with animated width, select-none, touch-friendly
- `src/stores/editor.ts` — new state: `activeRibbonTab`, `panelMode`, `mobileDrawerSnap`, `actionToast`; fix `showUI` init
- `src/composables/use-keyboard.ts` — ⌘J mobile bridge
- `src/composables/use-canvas-input.ts` — touch→mouse event synthesis for non-HAND tools
- `src/composables/use-canvas.ts` — rulers hidden on mobile