diff --git a/apps/web/src/app.css b/apps/web/src/app.css index bc3df6a70..0a4073165 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -143,7 +143,7 @@ select:disabled, --ui-border: var(--border); --ui-accent: var(--primary); --ui-danger: var(--destructive); - --shell-sidebar-width: 17.5rem; + --shell-sidebar-width: 256px; --shell-sidebar-width-tight: 15rem; --shell-canvas-width: min(36rem, 42vw); /* Mock --accent / --faint: same idea across themes, but each still @@ -521,10 +521,20 @@ select:disabled, overflow: hidden; text-overflow: ellipsis; color: var(--muted-foreground); - font-size: 0.95rem; + font-size: 13.5px; font-weight: 640; } +.stage-crumbs { + font-size: 13.5px; +} + +.stage-crumb-link { + display: inline-flex; + align-items: center; + gap: 4px; +} + .stage-crumb-link:hover { color: var(--foreground); } diff --git a/apps/web/src/lib/icons/index.tsx b/apps/web/src/lib/icons/index.tsx index c7e7b95ae..195406f7f 100644 --- a/apps/web/src/lib/icons/index.tsx +++ b/apps/web/src/lib/icons/index.tsx @@ -81,6 +81,7 @@ export { UserPlus, Users, Workflow as FlowArrow, + Wrench, X, Zap as Lightning, } from "lucide-react"; diff --git a/apps/web/src/shell/page-crumbs.tsx b/apps/web/src/shell/page-crumbs.tsx index 07e4ec98f..83242cad0 100644 --- a/apps/web/src/shell/page-crumbs.tsx +++ b/apps/web/src/shell/page-crumbs.tsx @@ -7,7 +7,7 @@ import { Fragment, useSyncExternalStore } from "react"; import { listWorkbenches } from "@/chat/workbench-tenants"; import { useBench } from "../bench-context"; -import { ArrowLeft } from "../lib/icons"; +import { ArrowLeft, Hash } from "../lib/icons"; import { Link } from "../navigation"; import { tenantKeys } from "../query-client"; import { getPath, subscribeToPath } from "../router-store"; @@ -24,7 +24,14 @@ export function benchLink(path: string, benchId: string | null): string { return `${url.pathname}${url.search}${url.hash}`; } -export type PageCrumb = { readonly label: string; readonly href?: string }; +export type PageCrumb = { + readonly label: string; + readonly href?: string; + /** A workbench crumb carries the `#` mark. */ + readonly hash?: true; +}; + +const ROOT_CRUMB: PageCrumb = { label: "Workbench" }; /** The workbench tenant id named by `?from=`, or null. Full-page views scope * their data to it instead of the last-opened workbench. */ @@ -58,19 +65,15 @@ export function usePageCrumbs(crumbs: readonly PageCrumb[]): { } { const from = useFromWorkbench(); const fromId = useFromBench(); - // A bare one-level page reads "Workbench / "; `?from=` swaps the - // root for the bench itself. - if (fromId === null) { - return { - crumbs: crumbs.length === 1 ? [{ label: "Workbench" }, ...crumbs] : crumbs, - back: null, - }; + // The root crumb is always "Workbench"; `?from=` adds the bench itself. + if (fromId === null || from === null || from.name === null) { + return { crumbs: [ROOT_CRUMB, ...crumbs], back: null }; } - if (from === null || from.name === null) return { crumbs, back: null }; const href = workbenchPath(from.id); return { crumbs: [ - { label: from.name, href }, + ROOT_CRUMB, + { label: from.name, href, hash: true }, ...crumbs.map((crumb) => crumb.href === undefined ? crumb : { ...crumb, href: benchLink(crumb.href, from.id) }, ), @@ -105,6 +108,7 @@ export function PageCrumbs({ crumbs: pageCrumbs }: { readonly crumbs: readonly P {crumb.label} ) : ( + {crumb.hash === true ?