{/* Always-present daemon status mirror for the smoke suite: no visible
diff --git a/frontend/src/renderer/components/TitlebarNav.tsx b/frontend/src/renderer/components/TitlebarNav.tsx
index ac364962f6..594958137a 100644
--- a/frontend/src/renderer/components/TitlebarNav.tsx
+++ b/frontend/src/renderer/components/TitlebarNav.tsx
@@ -1,14 +1,17 @@
import { useCanGoBack, useRouter } from "@tanstack/react-router";
import { ArrowLeft, ArrowRight, PanelLeft } from "lucide-react";
import { useEffect, useState } from "react";
-import { isMacPlatform } from "../lib/platform";
+import { isLinuxPlatform, isMacPlatform } from "../lib/platform";
import { useUiStore } from "../stores/ui-store";
const isMac = isMacPlatform();
+const isLinux = isLinuxPlatform();
const noDragStyle = isMac ? ({ WebkitAppRegion: "no-drag" } as React.CSSProperties) : undefined;
-// macOS-only sidebar chrome cluster (sidebar toggle + history arrows). It stays
-// fixed while the sidebar expands, collapses, or appears as a hover preview.
+// Sidebar chrome cluster (sidebar toggle + history arrows). It stays fixed while
+// the sidebar expands, collapses, or appears as a hover preview. macOS pins it
+// beside the traffic lights; Linux has no traffic lights, so it sits at the
+// sidebar's top-left. (Windows keeps these controls in its own titlebar.)
// The installed router has no useCanGoForward, and deriving one as
// `__TSR_index < history.length - 1` (the upstream hook's approach) is wrong
// here: window.history.length also counts entries the router never created —
@@ -46,12 +49,19 @@ export function TitlebarNav({
const canGoBack = useCanGoBack();
const canGoForward = useCanGoForward();
- if (!isMac) return null;
+ if (!isMac && !isLinux) return null;
- // Stay pinned beside the traffic lights. Nudge down slightly so the
- // toggle/arrows share a centerline with the native dots (y: 12).
- const leftClass = isFullScreen ? "left-titlebar-cluster-left-fullscreen" : "left-titlebar-cluster-left";
- const topClass = isFullScreen ? "top-0" : "top-0.5";
+ // macOS: pinned beside the traffic lights, nudged down so the toggle/arrows
+ // share a centerline with the native dots (y: 12). Linux: no traffic lights,
+ // so it sits at the sidebar's top-left within the reserved titlebar band.
+ const leftClass = !isMac
+ ? "left-1.5"
+ : isFullScreen
+ ? "left-titlebar-cluster-left-fullscreen"
+ : "left-titlebar-cluster-left";
+ // Linux: match the framed board titlebar's y (mac inset 2px + surface border
+ // 1px) so the cluster shares its centerline with the project title.
+ const topClass = !isMac ? "top-0.75" : isFullScreen ? "top-0" : "top-0.5";
return (
{
expect(usesBoardActionsInPanel()).toBe(false);
});
- it("uses the framed app topbar on Linux", () => {
+ it("hides the shell topbar on Linux and keeps board actions in the panel", () => {
spoofPlatform("Linux x86_64");
expect(isLinuxPlatform()).toBe(true);
expect(isWindowsPlatform()).toBe(false);
expect(usesFramedAppTopbar()).toBe(true);
- expect(hidesShellTopbar()).toBe(false);
- expect(usesBoardActionsInPanel()).toBe(false);
+ expect(hidesShellTopbar()).toBe(true);
+ expect(usesBoardActionsInPanel()).toBe(true);
});
});
diff --git a/frontend/src/renderer/lib/platform.ts b/frontend/src/renderer/lib/platform.ts
index 381749cebc..77eb9ca563 100644
--- a/frontend/src/renderer/lib/platform.ts
+++ b/frontend/src/renderer/lib/platform.ts
@@ -31,11 +31,14 @@ export function usesFramedAppTopbar(): boolean {
}
/**
- * macOS: shell does not mount ShellTopbar (full-height inset panel + drag
- * strip). SessionView mounts the same topbar in-panel for session actions.
+ * macOS + Linux: shell does not mount ShellTopbar (full-height inset panel).
+ * The sidebar toggle + history arrows live in the fixed TitlebarNav cluster and
+ * board/session actions mount in-panel, so both platforms share the framed
+ * chrome. (macOS additionally paints a traffic-light drag strip.) Windows keeps
+ * the ShellTopbar under its custom titlebar.
*/
export function hidesShellTopbar(): boolean {
- return isMacPlatform();
+ return isMacPlatform() || isLinuxPlatform();
}
/**
diff --git a/frontend/src/renderer/routes/_shell.tsx b/frontend/src/renderer/routes/_shell.tsx
index 765df24726..aea7d29229 100644
--- a/frontend/src/renderer/routes/_shell.tsx
+++ b/frontend/src/renderer/routes/_shell.tsx
@@ -133,9 +133,6 @@ function ShellLayout() {
: routeParams.sessionId
? workspaces.find((workspace) => workspace.sessions.some((session) => session.id === routeParams.sessionId))?.id
: undefined;
- const isSessionRoute =
- Boolean(matchRoute({ to: "/projects/$projectId/sessions/$sessionId", fuzzy: true })) ||
- Boolean(matchRoute({ to: "/sessions/$sessionId", fuzzy: true }));
// First-launch root board only (no projects in scope).
const isWelcomeBoard = Boolean(matchRoute({ to: "/" })) && workspaces.length === 0;
const isSettingsRoute =
@@ -547,15 +544,14 @@ function ShellLayout() {
} as CSSProperties
}
>
- {/* Hang the fixed sidebar below shell chrome on Win/Linux. macOS
- keeps a full-height sidebar beneath the fixed titlebar controls. */}
+ {/* macOS + Linux reserve a titlebar band for the fixed TitlebarNav
+ cluster above a full-height sidebar; Windows hangs the sidebar
+ below its custom titlebar. */}