Chat header: two-zone toolbar (centered action cluster + right-side device zone)
Was a single right-aligned row where the title's flex-1 bunched the action icons and the device controls together on the right. Now matches WorkClaw's two-zone pattern: - Identity stays left (capped width so it never reaches center). - Action cluster (Sessions / New / Computer) is its own group, absolutely centered in the header (measured at ~808, the chat-header center). - Device-size toggles + Close are a separate, absolutely-positioned top-right overlay (z-50, above the panel), shown only while the panel is open. Toggles are md+ only; Close stays (now also reachable above the mobile full-screen panel). Measured far-right at 1296–1420. Button classes, icons, aria-labels and handlers are unchanged — only the grouping/positioning wrappers differ. The panel card starts below the header (pt-88), so both zones stay visible/clickable when the panel is open. 86 unit + 31 functional E2E green. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
40e7e66eea
commit
906ab50bb8
@@ -8,9 +8,12 @@ import { Avatar } from "@/components/ui/Avatar";
|
|||||||
import { DeviceSizeToggle } from "@/components/computer/DeviceSizeToggle";
|
import { DeviceSizeToggle } from "@/components/computer/DeviceSizeToggle";
|
||||||
import { panelParsers } from "@/lib/url/panel-params";
|
import { panelParsers } from "@/lib/url/panel-params";
|
||||||
|
|
||||||
/** Chat header (measured): 80px, transparent, identity left; sessions /
|
/** Chat header (measured): a two-zone toolbar. The identity sits left; the
|
||||||
* new-session as 36px round icon buttons; the 42px coral-glow Computer
|
* action cluster (Sessions / New / Computer) is centered as its own group;
|
||||||
* launcher on the right. Accessible names unchanged from §5b. */
|
* and the device-size toggles + Close are a separate, absolutely-positioned
|
||||||
|
* top-right overlay (z-50, above the Computer panel) shown while the panel
|
||||||
|
* is open. Button styling, icons, aria-labels and handlers are unchanged —
|
||||||
|
* only the grouping/positioning differs. */
|
||||||
export function ChatHeader({
|
export function ChatHeader({
|
||||||
agent,
|
agent,
|
||||||
onNewSession,
|
onNewSession,
|
||||||
@@ -23,7 +26,8 @@ export function ChatHeader({
|
|||||||
});
|
});
|
||||||
const panelOpen = app !== null;
|
const panelOpen = app !== null;
|
||||||
return (
|
return (
|
||||||
<header className="flex h-20 items-center gap-3 pr-6 pl-5">
|
<header className="relative flex h-20 items-center gap-3 px-5">
|
||||||
|
{/* Identity (left). Capped so it never reaches the centered cluster. */}
|
||||||
<Avatar
|
<Avatar
|
||||||
name={agent.name}
|
name={agent.name}
|
||||||
accent={agent.accent}
|
accent={agent.accent}
|
||||||
@@ -31,12 +35,15 @@ export function ChatHeader({
|
|||||||
shape="squircle"
|
shape="squircle"
|
||||||
online={agent.status === "online"}
|
online={agent.status === "online"}
|
||||||
/>
|
/>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 max-w-[34%]">
|
||||||
<p className="truncate text-lg font-semibold text-neutral-200">
|
<p className="truncate text-lg font-semibold text-neutral-200">
|
||||||
{agent.name}
|
{agent.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="truncate text-sm text-[#7d7d7d]">{agent.job_title}</p>
|
<p className="truncate text-sm text-[#7d7d7d]">{agent.job_title}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Action cluster — centered, standalone group. */}
|
||||||
|
<div className="absolute top-1/2 left-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center gap-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Sessions"
|
aria-label="Sessions"
|
||||||
@@ -66,15 +73,21 @@ export function ChatHeader({
|
|||||||
>
|
>
|
||||||
<Monitor aria-hidden size={20} />
|
<Monitor aria-hidden size={20} />
|
||||||
</button>
|
</button>
|
||||||
{/* When the Computer is open, its size toggles + close live here in
|
</div>
|
||||||
the global header (measured), beside a thin divider. */}
|
|
||||||
|
{/* Device-size controls + Close — a separate right-aligned overlay,
|
||||||
|
pinned top-right above the panel (z-50). The toggles only show at
|
||||||
|
md+; Close stays so it's reachable above the mobile full-screen
|
||||||
|
panel. */}
|
||||||
{panelOpen && (
|
{panelOpen && (
|
||||||
<>
|
<div className="absolute top-1/2 right-5 z-50 flex -translate-y-1/2 items-center gap-1">
|
||||||
<span aria-hidden className="mx-1 h-5 w-px bg-border" />
|
<span aria-hidden className="mx-1 hidden h-5 w-px bg-border md:block" />
|
||||||
|
<div className="hidden md:flex">
|
||||||
<DeviceSizeToggle
|
<DeviceSizeToggle
|
||||||
value={device}
|
value={device}
|
||||||
onChange={(size) => setParams({ device: size })}
|
onChange={(size) => setParams({ device: size })}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Close computer"
|
aria-label="Close computer"
|
||||||
@@ -83,7 +96,7 @@ export function ChatHeader({
|
|||||||
>
|
>
|
||||||
<X aria-hidden size={18} />
|
<X aria-hidden size={18} />
|
||||||
</button>
|
</button>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user