Skip to content

Mobile: complete PWA experience with Liquid Glass UI#61

Merged
jcanizalez merged 11 commits intomainfrom
feat/mobile-keyboard-pwa
Mar 18, 2026
Merged

Mobile: complete PWA experience with Liquid Glass UI#61
jcanizalez merged 11 commits intomainfrom
feat/mobile-keyboard-pwa

Conversation

@jcanizalez
Copy link
Copy Markdown
Owner

Summary

Complete mobile experience for VibeGrid's web app — from first touch to installable PWA.

9 commits across 2 branches (feat/mobile-improvementsfeat/mobile-keyboard-pwa):

Foundation (6 commits)

  • Touch targets (44px min), tap delay removal, hover-only interaction fixes
  • Safe area insets with viewport-fit=cover and CSS env() variables
  • Virtual keyboard handling (VirtualKeyboard API + visualViewport fallback)
  • Terminal typography optimization for mobile readability
  • Bottom tab navigation (Sessions / Tasks / Settings)
  • Single-pane layout with swipe navigation between terminals

Keyboard & PWA (2 commits)

  • Extended terminal keyboard bar (Termux-style): ESC, Tab, Ctrl (sticky toggle), arrow keys, pipe, slash, tilde, dash, underscore
  • PWA support: vite-plugin-pwa with Workbox (Cache-First static, Network-First API), offline fallback page, enhanced manifest with display_override and orientation

Liquid Glass + Redesign (1 commit)

  • Liquid Glass material ported from Framework7 v9 / iOS 26 — mobile viewports only (@media max-width: 767px), desktop completely untouched
  • CSS variables: --glass-bg, --glass-blur, --glass-shadow, --glass-shadow-thumb (8-layer inset box-shadow stack)
  • MobileBottomTabs: floating glass capsule pill (32px radius), inset from screen edges, glass thumb highlight on active tab
  • MobileTerminalKeybar: redesigned from flat single-row to two-row iOS-native pill layout (modifiers + d-pad arrows / symbol pills)
  • MobileSinglePane: rewritten from swipe nav to scrollable session card list with tap-to-expand
  • FocusedTerminal: full-screen on mobile with back button, hides desktop-only chrome
  • Toast, ConfirmPopover, CardContextMenu: glass material on mobile via useIsMobile hook
  • App.tsx: glass hamburger + "+" buttons on mobile

Files changed

  • 18 files, +405 -222 lines (Liquid Glass commit)
  • 10 files, +2840 -154 lines (Keyboard + PWA commits)
  • 6 files across foundation commits

Test plan

  • Mobile viewport (< 768px): verify glass material on tab bar, keyboard bar, toast, context menu, popover
  • Desktop viewport (>= 768px): verify zero visual changes
  • PWA installability: Chrome DevTools > Application > Manifest shows "installable"
  • Keyboard bar: test all keys (ESC, Tab, Ctrl+C, arrows, symbols) send correct escape sequences
  • Session card list: tap card opens FocusedTerminal, back button returns to list
  • Floating tab bar: doesn't overlap content, respects safe-area-inset-bottom
  • Offline fallback: disconnect network, verify offline.html renders

🤖 Generated with Claude Code

- Add touch-action: manipulation globally to all interactive elements
  (kills 300ms tap delay on mobile browsers)
- Add @media (hover: none) rules to show hover-revealed action buttons
  on touch devices (pin, archive, rename, sidebar actions)
- Increase traffic light dots to 22px on touch devices for better
  tap targets
- Add active: states across all buttons for visual touch feedback
- Increase button padding on mobile (p-2 -> p-2.5 for action buttons,
  py-1.5 -> py-2.5 for menu items)
- Update Tooltip to skip on touch devices (prevents blocking taps),
  use ref callback for positioning instead of setState in effect
- Migrate outside-click listeners from mousedown to pointerdown for
  unified mouse+touch handling in ConfirmPopover, CardContextMenu,
  and ProjectSidebar context menus
- Increase scroll-to-bottom button from w-6 h-6 to w-8 h-8
- AgentCard: always show pin/archive on touch (no hover needed)
…ainment

- Add viewport-fit=cover to web index.html for iOS notch/Dynamic Island
- Define CSS custom properties --safe-top/right/bottom/left from env()
- Switch root container from h-screen to h-dvh with safe area padding
- Update all fixed-position overlays (Toast, FocusedTerminal, Settings,
  DiffSidebar, TaskDiffReview, WorkflowEditor, ProjectSidebar mobile)
  to respect safe area insets
- Add overscroll-behavior: contain to prevent iOS rubber-band overscroll
- Sync web package global.css with touch-action and hover:none rules
…sualViewport fallback

- Add interactive-widget=resizes-content to viewport meta (Chrome/Android)
- Create useVirtualKeyboard hook with three-tier strategy:
  1. VirtualKeyboard API (navigator.virtualKeyboard) for Chrome 94+
  2. visualViewport resize/scroll events for Safari/iOS fallback
  3. Graceful no-op on non-touch devices
- Hook sets --keyboard-height CSS custom property and refits all terminals
- Add fitAllTerminals() to terminal-registry for keyboard geometry changes
- App root bottom padding includes --keyboard-height for Safari layout shift
- Toast position accounts for --keyboard-height to stay above keyboard
- Add --keyboard-height: 0px default to both global.css files
- Enforce minimum 14px terminal font size on touch devices (was 13px)
- Add pinch-to-zoom hook for terminal font size adjustment on mobile
- Add floating font size +/- control in focused terminal view (mobile only)
- Set body text to 16px with 1.5 line-height on mobile viewports
- Boost gray-500/gray-600 text contrast on mobile for WCAG AA compliance
- Apply typography improvements to both Electron and web app CSS
- New MobileBottomTabs component with 4 tabs: Sessions, Tasks, New, Settings
- Cyan accent on active tab indicator dot and New button icon
- Hidden when virtual keyboard is open to maximize screen space
- Replaces Sessions/Tasks toggle in top bar on mobile (declutters header)
- 52px min height with 44px+ touch targets per tab
- Desktop layout completely unchanged
- New MobileSinglePane component replaces GridView on mobile
- Shows one terminal at a time, full height, instead of scrollable grid
- Swipe left/right to navigate between terminals (50px min, 300ms max)
- Dot indicators + arrow buttons when 2+ terminals are open
- Active dot highlighted in cyan, clickable for direct jump
- Uses store selectedTerminalId as source of truth (syncs with sidebar/shortcuts)
- Falls back to PromptLauncher when no sessions exist
- Desktop grid/tab layout completely unchanged
Floating bar with Esc, Tab, Ctrl (sticky toggle), arrow keys, pipe,
slash, tilde, dash, underscore. Renders inside FocusedTerminal on
mobile viewports. Uses onPointerDown + preventDefault to avoid
stealing focus from xterm.js. Ctrl auto-unsticks after 5s or next
keypress. Sends keystrokes via window.api.writeTerminal.
Install vite-plugin-pwa with Workbox for service worker generation.
Cache-First for static assets, Network-First for API calls. Adds
offline fallback page, enhanced manifest with id, display_override,
and orientation fields. Registers SW in main.tsx independently of
WebSocket connection. Enables "Add to Home Screen" installability.
Port iOS 26 Liquid Glass material to mobile viewports only (< 768px).
Desktop Electron app is completely untouched.

Glass material:
- CSS variables (--glass-bg, --glass-blur, --glass-shadow) scoped
  inside @media (max-width: 767px) in both global.css files
- Framework7 v9 dark mode values: 8-layer inset box-shadow stack,
  saturate(180%) blur(16px), rgba(50,50,50,0.5) background

Component changes:
- MobileBottomTabs: floating glass capsule pill (rounded-[32px]),
  inset from edges, glass-shadow-thumb on active tab. Removed "New"
  tab (actions moved to top bar glass buttons)
- MobileTerminalKeybar: two-row iOS 26-native layout. Row 1:
  ESC/TAB/CTL pills + arrow d-pad cluster. Row 2: 10 symbol pills.
  Pill-shaped (rounded-full) instead of rectangular
- MobileFontSizeControl: glass material via CSS variables
- MobileSinglePane: rewritten from swipe navigation to scrollable
  card list with MobileSessionCard. Tap card to open FocusedTerminal
- FocusedTerminal: full-screen on mobile (no inset/rounded), back
  button (ChevronDown), hide desktop-only elements (kbd hints,
  traffic lights, OpenInButton)
- App.tsx: glass hamburger and "+" buttons on mobile via isMobile
  guard, bottom padding for floating tab bar
- Toast, ConfirmPopover, CardContextMenu: glass on mobile via
  useIsMobile hook, desktop unchanged

QA screenshots in screenshots/ directory.
Copilot AI review requested due to automatic review settings March 18, 2026 18:48
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR upgrades VibeGrid’s web/renderer UI for a mobile-first experience and adds PWA support, including safe-area handling, virtual keyboard awareness, mobile-specific navigation/controls, and “Liquid Glass” styling applied only on small viewports.

Changes:

  • Add mobile UX foundations: safe-area insets, touch interaction tweaks, improved terminal font sizing/zoom, and keyboard-aware layout refitting.
  • Introduce mobile UI components (bottom tabs, focused terminal controls, keybar) and apply glass styling to selected overlays/menus.
  • Add PWA service worker + Workbox runtime caching, enhanced manifest metadata, and an offline page.

Reviewed changes

Copilot reviewed 29 out of 39 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/renderer/lib/terminal-registry.ts Adds font-size helpers and a “fit all terminals” utility used by keyboard handling.
src/renderer/hooks/useVirtualKeyboard.ts New hook to detect virtual keyboard geometry and update CSS vars + refit terminals.
src/renderer/hooks/useTerminalPinchZoom.ts New pinch-to-zoom hook that adjusts/persists terminal font size on touch devices.
src/renderer/hooks/useSwipeNavigation.ts Adds a generic swipe gesture hook (horizontal flick detection).
src/renderer/global.css Adds safe-area variables, touch interaction adjustments, mobile typography, and glass CSS variables.
src/renderer/components/workflow-editor/WorkflowEditor.tsx Applies safe-area padding to the full-screen workflow editor overlay.
src/renderer/components/TrafficLights.tsx Shows traffic-light icons on touch devices (no hover) and tweaks interaction.
src/renderer/components/Tooltip.tsx Disables tooltips on touch devices and refactors positioning logic.
src/renderer/components/Toast.tsx Makes toast position keyboard/safe-area aware and applies glass styling on mobile.
src/renderer/components/TaskDiffReview.tsx Adds safe-area padding to the diff review sidebar overlay.
src/renderer/components/SettingsPage.tsx Adds safe-area padding to settings overlay.
src/renderer/components/ProjectSidebar.tsx Improves touch target sizes/active states; switches outside-click handling to pointer events; adds safe-area padding.
src/renderer/components/MobileTerminalKeybar.tsx New mobile terminal accessory keybar with modifiers, arrows, and symbol pills.
src/renderer/components/MobileSinglePane.tsx New mobile sessions view: scrollable card list opening a focused terminal overlay.
src/renderer/components/MobileFontSizeControl.tsx New mobile floating font-size control and persistence behavior.
src/renderer/components/MobileBottomTabs.tsx New bottom tab navigation for mobile (Sessions/Tasks/Settings).
src/renderer/components/FocusedTerminal.tsx Mobile-focused terminal overlay: safe-area padding, back affordance, pinch zoom support, mobile controls + keybar.
src/renderer/components/DiffSidebar.tsx Adds safe-area padding to diff sidebar overlay.
src/renderer/components/ConfirmPopover.tsx Uses pointer events for outside click; applies glass styling + touch-friendly padding on mobile.
src/renderer/components/CardContextMenu.tsx Uses pointer events for outside click; applies glass styling + touch-friendly padding on mobile.
src/renderer/components/AgentCard.tsx Improves touch behavior (pointerdown selection, always-visible actions on touch, larger tap targets).
src/renderer/App.tsx Integrates mobile layout (dvh, safe-area/keyboard padding), mobile session pane, bottom tabs, and virtual keyboard hook.
screenshots/desktop-no-regression.png Adds a desktop regression screenshot artifact.
packages/web/vite.config.ts Adds vite-plugin-pwa with Workbox caching strategies and navigation fallback.
packages/web/src/pwa.d.ts Adds PWA client type references for TS.
packages/web/src/main.tsx Registers the service worker before initializing the API shim/React app.
packages/web/src/global.css Mirrors mobile safe-area/touch/glass styling for the web package.
packages/web/public/offline.html Adds an offline informational fallback page.
packages/web/public/manifest.webmanifest Enhances PWA manifest (id, display_override, orientation, icon purpose).
packages/web/package.json Adds vite-plugin-pwa dev dependency.
packages/web/index.html Updates viewport meta (viewport-fit + interactive-widget) and uses 100dvh for loader layout.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines 370 to +375
/**
* Update font size on all terminals and re-fit them.
* On touch devices the minimum is enforced automatically.
*/
export function setAllTerminalsFontSize(fontSize: number): void {
const effective = getEffectiveFontSize(fontSize)
<main className="flex-1 flex flex-col overflow-hidden">
<main
className="flex-1 flex flex-col overflow-hidden"
style={isMobile ? { paddingBottom: 'calc(64px + var(--safe-bottom, 0px))' } : undefined}
Comment on lines +12 to +15
workbox: {
navigateFallback: '/app/index.html',
navigateFallbackAllowlist: [/^\/app/],
runtimeCaching: [
Tooltip.tsx called window.matchMedia at module scope without checking
if the function exists. This broke tooltip.test.tsx in jsdom (which
lacks matchMedia). Add typeof check before the call.
Main content area reserved 64px bottom padding for the floating tab
bar even when the virtual keyboard was visible (and the tab bar
hidden). Now the padding is conditional on keyboardHeight === 0.

Also fix misleading JSDoc on setAllTerminalsFontSize — callers handle
their own clamping, the function just applies getEffectiveFontSize.
@jcanizalez jcanizalez merged commit 0977a44 into main Mar 18, 2026
1 check passed
@jcanizalez jcanizalez deleted the feat/mobile-keyboard-pwa branch March 18, 2026 20:14
This was referenced Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants