Skip to content

[Feat] PWA native mobile UI overhaul with gesture support and device identity fix#183

Merged
samzong merged 2 commits intomainfrom
feat/pwa-native-ui
Mar 26, 2026
Merged

[Feat] PWA native mobile UI overhaul with gesture support and device identity fix#183
samzong merged 2 commits intomainfrom
feat/pwa-native-ui

Conversation

@samzong
Copy link
Copy Markdown
Collaborator

@samzong samzong commented Mar 26, 2026

Summary

Complete visual and functional overhaul of the PWA mobile companion. Transforms the generic web app into a native iOS chat app feel (ChatGPT-style) while fixing critical device identity, pairing, and i18n bugs.

Type of change

  • [Feat] new feature
  • [Fix] bug fix
  • [UI] UI or UX change

Why is this needed?

The PWA was functionally complete but looked like a generic web app. Multiple bugs blocked real-world usage: shared device identity caused desktop disconnection, QR pairing auth mode was lost, settings button was non-functional, icons were placeholders, and i18n only had English.

What changed?

  • Native UI: OLED dark theme (#000000), pill-shaped input bar, right-aligned user bubbles, clean assistant layout, typing dots indicator
  • Gesture support: Edge-swipe to open drawer, drag-to-close drawer, swipe-down-to-dismiss on all bottom sheets via framer-motion drag API with useDragControls
  • Device identity architecture fix: Each device now registers its own Ed25519 keypair with OpenClaw. QR shares only a scope ID (desktop device ID string) for session filtering — no crypto keys shared. Prevents node registry collision that was kicking the desktop offline.
  • QR auth mode fix: Desktop now encodes authMode (m, t, p, c fields) in QR payload instead of sending everything as a token
  • Settings sheet: New bottom sheet with theme toggle, 8-language selector, sign-out
  • i18n: Added zh, zh-TW, ja, ko, de, es, pt locale files + language detection from localStorage/browser
  • Authorization flow: Post-scan waiting screen with reconnect button; BrowserGatewayClient.reconnect() method resets attempts
  • Icons: Replaced placeholder blue "L" icons with proper claw logo from desktop
  • Touch fix: Added touchAction: manipulation/pan-y to bottom sheet children to prevent framer-motion drag from swallowing tap events
  • Desktop: Fixed PairMobileDialog UI contract violations (semantic tokens), wired getDeviceIdentity IPC handler

Architecture impact

  • Owning layer: renderer (PWA) + renderer (desktop PairMobileDialog) + preload + main (IPC handler)
  • Cross-layer impact: yes — preload exposes getDeviceIdentity, main registers IPC handler, desktop renderer generates QR with scope ID, PWA renderer consumes it
  • Invariants touched from docs/architecture-invariants.md: QR payload format changed (v1 d field removed, s scope ID added, g entries gain m/p/c fields)
  • Why those invariants remain protected: QR is a one-shot pairing payload, not a persisted protocol. PWA qr-decode.ts validates new format. Old QR codes without s field still work (PWA falls back to own device ID).

Linked issues

close #97
close #5

Validation

  • pnpm lint
  • pnpm test
  • pnpm check:ui-contract
  • pnpm typecheck
  • Manual smoke test

Commands, screenshots, or notes:

pnpm check — all gates pass (lint, architecture, ui-contract, renderer-copy, i18n, dead-code, format, typecheck, test)
92 desktop tests + 59 PWA tests passing

Screenshots or recordings

N/A — mobile-only UI changes, requires device testing.

Token changes: --bg-primary to #000000, --bg-secondary to #171717, shadows to none, new --input-bar-bg and --user-bubble-bg tokens. All via CSS variables, no hardcoded values. touch-action overrides on bottom sheet children to restore tappability inside framer-motion drag containers.

Release note

  • User-facing change. Release note is included below.
PWA mobile companion redesigned with native iOS chat app look: OLED dark theme, swipe gestures, settings panel, 8-language support, and proper device identity handling during QR pairing.

Checklist

  • The PR title uses at least one approved prefix: [Feat], [Fix], [UI], [Docs], [Refactor], [Build], or [Chore]
  • The summary explains both what changed and why
  • Validation reflects the commands actually run for this PR
  • Architecture impact is described and references any touched invariants
  • Cross-layer changes are explicitly justified
  • The release note block is accurate

samzong added 2 commits March 27, 2026 01:14
…ntegration

Complete implementation of @clawwork/pwa — an offline-first Progressive Web App
mobile companion for ClawWork desktop.

Architecture:
- Service Worker precaches entire app shell (Workbox generateSW)
- Zero runtime HTTP requests; all data flows through WebSocket
- IndexedDB persistence via idb (5 object stores: identity, gateways,
  tasks, messages, preferences)
- Port-based DI matching core's PlatformPorts interface

Infrastructure:
- BrowserGatewayClient: full WS protocol with Ed25519 device auth,
  structured debug logging, request tracking, exponential backoff reconnect
- Port adapters: PersistencePort, GatewayTransportPort, SettingsPort,
  NotificationsPort — all wired through lazy Proxy pattern
- Core store instantiation with ChatComposer bridge for circular deps
- compactSession/resetSession bypass port adapter (matches desktop pattern)

Security:
- MarkdownContent: restricted allowedElements, input limited to checkbox,
  explicit javascript:/data: href guard, skipHtml enabled
- QR payload validation with typed schema and auth mode checks
- Device identity via Web Crypto Ed25519 (non-extractable keys)

Quality:
- ARIA labels on all interactive elements, focus traps on drawer/dialog,
  touch targets >= 44px, aria-live regions scoped to streaming content
- All user-facing strings via i18next t() keys
- Structured debug events (error/warn in prod, debug in dev only)
- syncSessions resilient to per-client failures (continues, not aborts)
- getDb() uses promise singleton to prevent concurrent initialization race
- ChatInput restores text on send failure
- QrScanner: mediaDevices guard, metadata race fix, error backoff

Desktop changes:
- PairMobileDialog: QR code generation with freshly minted Ed25519 identity
- GeneralSection: pair mobile device button
- theme.css: --surface-qr-bg semantic token
- i18n: pairing keys added to all 8 locales

Config:
- Cloudflare Pages: immutable asset caching, must-revalidate index.html
- Vite: vendor/markdown/motion chunk splitting, conditional basicSsl
- Core: PersistedTask extended with 6 optional fields (model, tokens, etc.)
- knip, e2e playwright, check-ui-contract updated for pwa workspace
…identity fix

- OLED dark theme, pill input bar, user message bubbles, clean assistant layout
- Swipe gestures: edge-swipe to open drawer, drag-to-dismiss bottom sheets
- Settings sheet with theme toggle and 8-language i18n support
- Authorization waiting screen with reconnect button after QR pairing
- Fix device identity: separate auth identity per device, share scope ID for session filtering
- Fix QR payload: encode auth mode properly (token/password/pairingCode)
- Fix PWA icons: replace placeholder with desktop claw logo
- Fix touch-action on bottom sheets so buttons are tappable
- Desktop: fix PairMobileDialog UI contract violations, wire getDeviceIdentity IPC
@github-actions
Copy link
Copy Markdown
Contributor

Hi @samzong,
Thanks for your pull request!
If the PR is ready, use the /auto-cc command to assign Reviewer to Review.
We will review it shortly.

Details

Instructions for interacting with me using comments are available here.
If you have questions or suggestions related to my behavior, please file an issue against the gh-ci-bot repository.

This was referenced Mar 26, 2026
@samzong samzong merged commit 2092a59 into main Mar 26, 2026
7 checks passed
@samzong samzong deleted the feat/pwa-native-ui branch March 29, 2026 14:11
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.

Mobile version of ClawWork Mobile: ClawWork Mobile Client

1 participant