diff --git a/frontend/src/app/components/Layout/AppShell.tsx b/frontend/src/app/components/Layout/AppShell.tsx
index 753cba04..64b13179 100644
--- a/frontend/src/app/components/Layout/AppShell.tsx
+++ b/frontend/src/app/components/Layout/AppShell.tsx
@@ -444,7 +444,9 @@ const AppShell: React.FC = () => {
{/* Sidebar retired: dashboards switch via the macOS-Spaces top strip; a slim band below the
spaces hot zone keeps the frameless window draggable (the sidebar's drag strip is gone). */}
{isDashboardViewActive && !v3FlowActive && }
-
+ {/* Tagged so tiling can inset below it: this strip is a window-DRAG region, so anything tiled
+ underneath it loses those pixels to dragging the OS window instead of taking clicks. */}
+
{/* Top bar dropped (Arc/Zen): a zero-height anchor left only to float the agent-activity island at top-center; the island renders nothing when idle. */}
vp.left + vp.width * 0.75 ? vp.right - r.left + GAP : 0;
}
+// How far down the top chrome reaches into the viewport. Same shape as edgeInset: absent or
+// non-overlapping chrome yields 0, never a bogus inset.
+function topInset(vp: DOMRect): number {
+ let deepest = 0;
+ document.querySelectorAll('[data-top-chrome]').forEach((el) => {
+ const r = el.getBoundingClientRect();
+ if (!(r.height > 0) || r.bottom <= vp.top) return;
+ if (r.top > vp.top + vp.height * 0.25) return;
+ deepest = Math.max(deepest, r.bottom - vp.top);
+ });
+ return deepest;
+}
+
function measureWorkspace(): Workspace {
const el = document.querySelector('[data-canvas-viewport]');
const r = el?.getBoundingClientRect();
- if (!r || !(r.width > 0 && r.height > 0)) return { x0: 0, x1: 0, w: window.innerWidth, h: window.innerHeight };
+ if (!r || !(r.width > 0 && r.height > 0)) return { x0: 0, x1: 0, y0: 0, w: window.innerWidth, h: window.innerHeight };
// macOS model: a tiled window sits BESIDE the Dock and beside the minimized rail, never under either.
return {
x0: edgeInset('[data-desktop-dock]', r, 'left'),
x1: edgeInset('[data-minimized-rail]', r, 'right'),
+ y0: topInset(r),
w: r.width,
h: r.height,
};
@@ -77,16 +95,17 @@ function measureWorkspace(): Workspace {
export function zoneRect(zone: string): ZoneRect | null {
const ws = workspace ?? (workspace = measureWorkspace());
const usableW = ws.w - ws.x0 - ws.x1;
+ const usableH = ws.h - ws.y0;
if (zone === 'fullscreen') {
- return { x: ws.x0 + GAP, y: GAP, w: usableW - GAP * 2, h: ws.h - GAP * 2 };
+ return { x: ws.x0 + GAP, y: ws.y0 + GAP, w: usableW - GAP * 2, h: usableH - GAP * 2 };
}
const z = TILE_ZONES[zone];
if (!z) return null;
return {
x: ws.x0 + z.x * usableW + GAP,
- y: z.y * ws.h + GAP,
+ y: ws.y0 + z.y * usableH + GAP,
w: z.w * usableW - GAP * 2,
- h: z.h * ws.h - GAP * 2,
+ h: z.h * usableH - GAP * 2,
};
}