From 0c49b132ee83dfad28d504db53d51eabc8aaa4d4 Mon Sep 17 00:00:00 2001 From: space Date: Sat, 1 Aug 2026 00:43:48 +0200 Subject: [PATCH] feat(ui): make the UI feel native on mobile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reworks the frontend around phone-first interaction patterns and makes the app installable to a home screen. Shell - Bottom tab bar (Home / Requests / Agents / Alerts / Settings) below `md`, with the unread badge moved onto the Alerts tab; the bell stays on desktop. - Account menu opens as a bottom sheet on phones, dropdown on desktop. - Safe-area insets throughout: `viewport-fit=cover` plus `env(safe-area-inset-*)` on the sticky header, tab bar and sheet footers. Sheets - New `Sheet` primitive: drag-to-dismiss bottom sheet on phones, centred dialog from `sm` up. `Modal` now delegates to it, so every dialog inherits the gesture, the scroll lock and the safe-area padding. - Portalled to `` — an ancestor with a transform (the page fade-in) was otherwise becoming the containing block and displacing the fixed overlay. - Scroll lock pins `` and restores position, which iOS needs; plain `overflow: hidden` still rubber-bands there. - `ConfirmSheet` replaces `window.confirm` for destructive actions. Screens - Request detail gets a sticky decision bar above the tab bar; the sidebar decision card is now desktop-only. - Requests state filter becomes a swipeable pill row instead of a select. - Agent cards show two primary actions plus an overflow sheet on phones. - Diffs and code blocks contain their horizontal overscroll so a sideways swipe no longer triggers browser back; diffs gain a line-wrap toggle. - `min-w-0` on grid tracks — items default to `min-width: auto`, so truncated meta lines were widening columns past the viewport at 320px. Touch and input - 44px minimum touch targets, `:active` press feedback, no tap highlight. - 16px inputs on coarse pointers so iOS stops zooming on focus. - autocomplete/inputmode hints so password managers and keyboards behave. - `overscroll-behavior-y: none` disables pull-to-refresh; motion respects `prefers-reduced-motion`. PWA - Manifest, generated app icons (192/512/apple-touch) and standalone display metadata, so the app installs to a home screen without browser chrome. - Backend serves `.webmanifest` as `application/manifest+json`; rjweb's type map has no entry for it. Co-Authored-By: Claude Opus 5 --- Backend/src/index.ts | 7 +- UI/index.html | 22 +- UI/public/apple-touch-icon.png | Bin 0 -> 5969 bytes UI/public/icon-192.png | Bin 0 -> 6539 bytes UI/public/icon-512.png | Bin 0 -> 18166 bytes UI/public/icon.svg | 22 ++ UI/public/manifest.webmanifest | 24 ++ UI/src/components/AgentModals.tsx | 47 ++-- UI/src/components/ChangeRenderer.tsx | 96 +++++--- UI/src/components/CodeBlock.tsx | 21 +- UI/src/components/ConfirmSheet.tsx | 52 ++++ UI/src/components/DecisionModal.tsx | 48 ++-- UI/src/components/Layout.tsx | 325 ++++++++++++++++++------- UI/src/components/Modal.tsx | 48 +--- UI/src/components/NotificationBell.tsx | 15 +- UI/src/components/Sheet.tsx | 188 ++++++++++++++ UI/src/components/icons.tsx | 155 ++++++++++++ UI/src/components/ui.tsx | 79 ++++-- UI/src/hooks/useMediaQuery.ts | 27 ++ UI/src/hooks/useScrollLock.ts | 44 ++++ UI/src/index.css | 248 ++++++++++++++++++- UI/src/main.tsx | 16 +- UI/src/pages/Admin.tsx | 183 ++++++++------ UI/src/pages/Agents.tsx | 176 ++++++++++--- UI/src/pages/Dashboard.tsx | 82 ++++--- UI/src/pages/Legal.tsx | 69 +++--- UI/src/pages/Login.tsx | 14 +- UI/src/pages/Notifications.tsx | 19 +- UI/src/pages/Register.tsx | 8 +- UI/src/pages/RequestDetail.tsx | 288 +++++++++++++--------- UI/src/pages/Requests.tsx | 87 ++++--- UI/src/pages/Settings.tsx | 49 ++-- 32 files changed, 1892 insertions(+), 567 deletions(-) create mode 100644 UI/public/apple-touch-icon.png create mode 100644 UI/public/icon-192.png create mode 100644 UI/public/icon-512.png create mode 100644 UI/public/icon.svg create mode 100644 UI/public/manifest.webmanifest create mode 100644 UI/src/components/ConfirmSheet.tsx create mode 100644 UI/src/components/Sheet.tsx create mode 100644 UI/src/components/icons.tsx create mode 100644 UI/src/hooks/useMediaQuery.ts create mode 100644 UI/src/hooks/useScrollLock.ts diff --git a/Backend/src/index.ts b/Backend/src/index.ts index 56f7379..a9e9767 100644 --- a/Backend/src/index.ts +++ b/Backend/src/index.ts @@ -86,7 +86,12 @@ server.notFound(async (ctr) => { // Serve a matching build file (assets, favicons, etc.) if present. const file = resolveStaticFile(path); - if (file) return ctr.status(200, "OK").printFile(file, { addTypes: true }); + if (file) { + // rjweb's type map has no entry for .webmanifest, and browsers want the + // PWA manifest served as application/manifest+json. + if (file.endsWith(".webmanifest")) ctr.headers.set("Content-Type", "application/manifest+json"); + return ctr.status(200, "OK").printFile(file, { addTypes: !file.endsWith(".webmanifest") }); + } // SPA fallback — hand any other route to the React app. if (hasUiIndex) return ctr.status(200, "OK").printFile(uiIndexPath, { addTypes: true }); diff --git a/UI/index.html b/UI/index.html index 0593d03..cdbca07 100644 --- a/UI/index.html +++ b/UI/index.html @@ -2,9 +2,27 @@ - - + + + + + + + + + + + + + + + PatchPass diff --git a/UI/public/apple-touch-icon.png b/UI/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7f14922e74da83979a0d65d6d40129ee65a27393 GIT binary patch literal 5969 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 literal 0 HcmV?d00001 diff --git a/UI/public/icon-192.png b/UI/public/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a96fc2866512535a448f9b040d28c608341d4b GIT binary patch literal 6539 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 literal 0 HcmV?d00001 diff --git a/UI/public/icon-512.png b/UI/public/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..87aaac679539e69317191a613391588d0513d3dd GIT binary patch literal 18166 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 + + + + + + + + + + + + + + diff --git a/UI/public/manifest.webmanifest b/UI/public/manifest.webmanifest new file mode 100644 index 0000000..640ae06 --- /dev/null +++ b/UI/public/manifest.webmanifest @@ -0,0 +1,24 @@ +{ + "name": "PatchPass", + "short_name": "PatchPass", + "description": "A human approval layer for AI agents. Review changes, approve intent, let agents proceed.", + "start_url": "/", + "scope": "/", + "display": "standalone", + "display_override": ["standalone", "minimal-ui"], + "orientation": "any", + "background_color": "#0a0e17", + "theme_color": "#0a0e17", + "categories": ["developer", "productivity", "utilities"], + "icons": [ + { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, + { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, + { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }, + { "src": "/icon.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any" } + ], + "shortcuts": [ + { "name": "Awaiting review", "url": "/", "description": "Requests waiting for your review" }, + { "name": "All requests", "url": "/requests", "description": "Full change request history" }, + { "name": "Agents", "url": "/agents", "description": "Manage your agents and API keys" } + ] +} diff --git a/UI/src/components/AgentModals.tsx b/UI/src/components/AgentModals.tsx index ad78967..d7acc26 100644 --- a/UI/src/components/AgentModals.tsx +++ b/UI/src/components/AgentModals.tsx @@ -47,9 +47,7 @@ export function AgentFormModal({ icon_url: iconUrl.trim() || null, max_pending_requests: maxPending, }; - const saved = editing - ? await agentsApi.update(agent!.id, payload) - : await agentsApi.create(payload); + const saved = editing ? await agentsApi.update(agent!.id, payload) : await agentsApi.create(payload); toast.success(editing ? "Agent updated" : "Agent created"); onSaved(saved, !editing); onClose(); @@ -68,17 +66,17 @@ export function AgentFormModal({ title={editing ? "Edit agent" : "New agent"} footer={ <> - - } >
- setName(e.target.value)} autoFocus /> + setName(e.target.value)} />