From 334611b375fe0af89555ac2d4c682f685c49137a Mon Sep 17 00:00:00 2001
From: Syed Laraib Ahmed <67756542+Laraib-1629@users.noreply.github.com>
Date: Mon, 11 May 2026 14:04:43 +0530
Subject: [PATCH] feat(web): add PWA manifest and wire mobile accordion on
dashboard (#1476)
* feat(web): add PWA manifest and wire mobile accordion on dashboard
- Add manifest.json with standalone display mode and theme colors
- Link manifest in layout.tsx generateMetadata
- Pass compactMobile, collapsed, onToggle to AttentionZone from Dashboard
so the mobile accordion (already implemented) is now activated
Closes #175
* fix(web): add missing PWA icons and split icon purposes
- Add icon-192.png and icon-512.png to public/ (were 404ing on PWA install)
- Split combined 'any maskable' into separate icon entries per W3C
best practice to avoid safe-zone cropping in non-maskable contexts
- Apply Prettier formatting to Dashboard.tsx (long SVG attribute lines)
* fix(web): resolve merge conflict, fix types, use dynamic icon routes
- Resolve Dashboard.tsx merge conflict with upstream refactored useSessionEvents
- Type handleZoneToggle as (level: AttentionLevel) per reviewer request
- Start all zones collapsed on mobile for better UX (collapsedZones init)
- Add scope to manifest.json per PWA best practice
- Switch manifest icons from static PNGs to dynamic /icon-192 and /icon-512
routes that use the existing renderIconElement system (branded icons)
- Remove static icon-192.png and icon-512.png black square placeholders
* fix(web): wire BottomSheet preview, fix mobile tests, update manifest
- Add onPreview to AttentionZone, opens BottomSheet on mobile tap
- Add previewSession state and bottom sheet handlers to Dashboard
- Default collapsedZones to done+working only, not all zones
- Fix isMergeReady to use server attentionLevels instead of client recompute
- Restore isMerged guard on DoneCard restore button
- Update manifest.ts with scope, orientation, maskable icon entries
- Update manifest.test.ts to expect new fields
- Update Dashboard.mobile.test.tsx for MobileSessionRow compact row structure
- Revert inverted Dashboard.doneBar.test.tsx assertion
* fix(web): add display:flex to kanban-board mobile override
---
packages/web/src/app/globals.css | 3 +-
packages/web/src/app/manifest.test.ts | 4 ++
packages/web/src/app/manifest.ts | 4 ++
packages/web/src/components/Dashboard.tsx | 63 ++++++++++++++++---
.../__tests__/Dashboard.doneBar.test.tsx | 4 +-
.../__tests__/Dashboard.mobile.test.tsx | 29 +++++----
6 files changed, 85 insertions(+), 22 deletions(-)
diff --git a/packages/web/src/app/globals.css b/packages/web/src/app/globals.css
index 38a300e88..8bb4b4016 100644
--- a/packages/web/src/app/globals.css
+++ b/packages/web/src/app/globals.css
@@ -5817,7 +5817,8 @@ html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:active {
/* -- Kanban board: stack columns vertically -- */
.kanban-board {
- grid-template-columns: minmax(0, 1fr);
+ display: flex;
+ flex-direction: column;
height: auto;
min-height: auto;
overflow-x: visible;
diff --git a/packages/web/src/app/manifest.test.ts b/packages/web/src/app/manifest.test.ts
index bd6e7e62f..de9f09808 100644
--- a/packages/web/src/app/manifest.test.ts
+++ b/packages/web/src/app/manifest.test.ts
@@ -12,13 +12,17 @@ describe("app manifest", () => {
name: "ao | Agent Orchestrator",
short_name: "ao",
start_url: "/",
+ scope: "/",
display: "standalone",
+ orientation: "portrait-primary",
background_color: "#121110",
theme_color: "#121110",
icons: [
{ src: "/apple-icon", sizes: "180x180", type: "image/png" },
{ src: "/icon-192", sizes: "192x192", type: "image/png", purpose: "any" },
+ { src: "/icon-192", sizes: "192x192", type: "image/png", purpose: "maskable" },
{ src: "/icon-512", sizes: "512x512", type: "image/png", purpose: "any" },
+ { src: "/icon-512", sizes: "512x512", type: "image/png", purpose: "maskable" },
],
});
});
diff --git a/packages/web/src/app/manifest.ts b/packages/web/src/app/manifest.ts
index 6977692da..2138c2d92 100644
--- a/packages/web/src/app/manifest.ts
+++ b/packages/web/src/app/manifest.ts
@@ -8,13 +8,17 @@ export default function manifest(): MetadataRoute.Manifest {
short_name: "ao",
description: "Dashboard for managing parallel AI coding agents",
start_url: "/",
+ scope: "/",
display: "standalone",
+ orientation: "portrait-primary",
background_color: "#121110",
theme_color: "#121110",
icons: [
{ src: "/apple-icon", sizes: "180x180", type: "image/png" },
{ src: "/icon-192", sizes: "192x192", type: "image/png", purpose: "any" },
+ { src: "/icon-192", sizes: "192x192", type: "image/png", purpose: "maskable" },
{ src: "/icon-512", sizes: "512x512", type: "image/png", purpose: "any" },
+ { src: "/icon-512", sizes: "512x512", type: "image/png", purpose: "maskable" },
],
};
}
diff --git a/packages/web/src/components/Dashboard.tsx b/packages/web/src/components/Dashboard.tsx
index f9dd25245..2e5a3eade 100644
--- a/packages/web/src/components/Dashboard.tsx
+++ b/packages/web/src/components/Dashboard.tsx
@@ -25,6 +25,7 @@ import { ConnectionBar } from "./ConnectionBar";
import { CopyDebugBundleButton } from "./CopyDebugBundleButton";
import { SidebarContext } from "./workspace/SidebarContext";
import { projectDashboardPath, projectSessionPath } from "@/lib/routes";
+import { BottomSheet } from "./BottomSheet";
interface DashboardProps {
initialSessions: DashboardSession[];
@@ -121,7 +122,7 @@ function DoneCard({
) : null}
{formatRelativeTimeCompact(session.lastActivityAt)}
- {canRestore ? (
+ {canRestore && !isMerged ? (