Collapsed toolbar: Slack chip + separator + raised-chip action group

Match WorkClaw's collapsed action cluster. Left-to-right now reads
Slack → Sessions → New → │ separator │ → Computer (coral):
- New Slack quick-launch chip (brand /services/slack.svg) as the first
  action, opening the Computer → Slack app via setParams({app:'slack'})
  (same handler as the panel home tile; connect-gated there).
- Slack/Sessions/New wrapped in their own md+ sub-group and given the
  raised-chip treatment (bg-neutral-900 + ring-1 ring-inset ring-white/8
  + shadow-bubble), preserving hover/active.
- Thin 24px vertical separator (w-px h-6 bg-white/12) before the coral
  Computer toggle, which stays size-[42px]/shadow-launcher and always
  visible (mobile-reachable; the action group hides <md per WorkClaw).
Handlers/aria-labels/icons of Sessions/New/Computer unchanged. The
header 'Slack' button doesn't collide with the panel-scoped Slack tests.
Verified live: cluster order Slack→Sessions→New→Computer; Slack opens
?app=slack.

86 unit + 31 functional E2E green.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-11 08:40:32 -05:00
co-authored by Claude Fable 5
parent e0a59e3b95
commit 35d0754b8d
+45 -23
View File
@@ -1,5 +1,6 @@
"use client"; "use client";
import Image from "next/image";
import { List, Monitor, SquarePen, X } from "lucide-react"; import { List, Monitor, SquarePen, X } from "lucide-react";
import { useQueryStates } from "nuqs"; import { useQueryStates } from "nuqs";
@@ -8,6 +9,11 @@ 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";
/* WorkClaw's raised-chip treatment for the collapsed action buttons:
dark fill, inset hairline ring, bubble shadow (dark-only app). */
const CHIP =
"inline-flex size-9 items-center justify-center rounded-full bg-neutral-900 shadow-bubble ring-1 ring-white/[0.08] transition-colors duration-(--duration-normal) ease-app ring-inset";
/** Chat header (measured): a two-zone toolbar. The identity sits left; the /** Chat header (measured): a two-zone toolbar. The identity sits left; the
* action cluster (Sessions / New / Computer) is centered as its own group; * action cluster (Sessions / New / Computer) is centered as its own group;
* and the device-size toggles + Close are a separate, absolutely-positioned * and the device-size toggles + Close are a separate, absolutely-positioned
@@ -42,29 +48,45 @@ export function ChatHeader({
<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. */} {/* Action cluster — centered, standalone group (measured): the
<div className="absolute top-1/2 left-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center gap-3"> chipped action group (Slack / Sessions / New), a vertical
<button separator, then the coral Computer toggle. */}
type="button" <div className="absolute top-1/2 left-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center gap-2.5">
aria-label="Sessions" <div className="hidden items-center gap-3 md:flex">
aria-pressed={sessions} <button
onClick={() => setParams({ sessions: !sessions })} type="button"
className={`inline-flex size-9 items-center justify-center rounded-full transition-colors duration-(--duration-normal) ease-app ${ aria-label="Slack"
sessions onClick={() => setParams({ app: "slack" })}
? "bg-surface-warm-muted text-foreground" className={`${CHIP} text-foreground hover:bg-neutral-800`}
: "text-muted-foreground hover:bg-hover-bg hover:text-foreground" >
}`} <Image src="/services/slack.svg" alt="" width={18} height={18} />
> </button>
<List aria-hidden size={18} /> <button
</button> type="button"
<button aria-label="Sessions"
type="button" aria-pressed={sessions}
aria-label="New" onClick={() => setParams({ sessions: !sessions })}
onClick={onNewSession} className={`${CHIP} ${
className="inline-flex size-9 items-center justify-center rounded-full text-muted-foreground transition-colors duration-(--duration-normal) ease-app hover:bg-hover-bg hover:text-foreground" sessions
> ? "text-foreground"
<SquarePen aria-hidden size={18} /> : "text-muted-foreground hover:bg-neutral-800 hover:text-foreground"
</button> }`}
>
<List aria-hidden size={18} />
</button>
<button
type="button"
aria-label="New"
onClick={onNewSession}
className={`${CHIP} text-muted-foreground hover:bg-neutral-800 hover:text-foreground`}
>
<SquarePen aria-hidden size={18} />
</button>
</div>
<span
aria-hidden
className="hidden h-6 w-px shrink-0 bg-white/[0.12] md:block"
/>
<button <button
type="button" type="button"
aria-label="Computer" aria-label="Computer"