R1+R2: shell and chat restyled to the reference system

Shell (main-chat-shell-spec): rail rebuilt around a 48px squircle claw
avatar stack with a 2px coral active ring + name beneath + online dot,
dashed 'New claw' tile, lucide-icon nav pills with the live credits
balance shown inline (coral when negative, aria-hidden so the nav link
name stays 'Credits'); 80px transparent chat header with 36px round
sessions/new-session icon buttons and the 42px coral-glow Computer
launcher; 768px centered content rail. RosterList computes the active
claw from the pathname so AgentRosterItem stays presentational.

Chat (chat-message-components): asymmetric layout — user pill #1A1A1A
radius 24/24/4 with inset white ring + dual shadow, capped 75%, vs the
bubble-less assistant message (50px squircle avatar, 15px gap, plain
14px/1.7 text); messageSlideIn entrance; 126px welcome avatar with the
24px/600/-0.6px heading (claw name in coral) and lucide-led suggestion
chips; floating 24px-radius neutral-800 composer card with the cream
Send pill; StepTrace rows restyled to the system.

Brand marks (Chrome, Slack) vendored to public/services from the bundle.
83 unit tests, full 29-journey functional E2E green.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-10 19:41:31 -05:00
co-authored by Claude Fable 5
parent 3ec1d3b829
commit 6e061515b8
17 changed files with 361 additions and 128 deletions
@@ -3,23 +3,51 @@ import Link from "next/link";
import type { Agent } from "@/lib/api/schemas";
import { Avatar } from "@/components/ui/Avatar";
/** One agent row in the left rail (§4): avatar, name, online dot. Links to
* the claw's chat (latest session resumes, or a fresh one opens). */
export function AgentRosterItem({ agent }: { agent: Agent }) {
/** One claw in the rail stack (measured): 48px squircle avatar with a 2px
* coral ring when its chat is open, name beneath, online dot. */
export function AgentRosterItem({
agent,
active = false,
}: {
agent: Agent;
active?: boolean;
}) {
return (
<Link
href={`/claws/${agent.id}`}
className="flex items-center gap-2 rounded-(--radius) px-2 py-1.5 text-sm text-foreground hover:bg-surface-warm"
aria-current={active ? "page" : undefined}
className="group flex w-full flex-col items-center gap-1 py-1.5"
>
<Avatar name={agent.name} accent={agent.accent} size="sm" />
<span className="truncate">{agent.name}</span>
{agent.status === "online" && (
<span
role="status"
aria-label={`${agent.name} is online`}
className="ml-auto size-1.5 shrink-0 rounded-full bg-green-500"
/>
)}
<span
className={`rounded-[19px] p-0.5 transition-colors duration-normal ease-app ${
active ? "ring-2 ring-coral" : ""
}`}
>
<span className="relative inline-flex">
<Avatar
name={agent.name}
accent={agent.accent}
size="rail"
shape="squircle"
/>
{agent.status === "online" && (
<span
role="status"
aria-label={`${agent.name} is online`}
className="absolute -right-0.5 -bottom-0.5 size-2.5 rounded-full border-2 border-background bg-green-500"
/>
)}
</span>
</span>
<span
className={`max-w-full truncate text-xs transition-colors duration-normal ease-app ${
active
? "text-foreground"
: "text-muted-foreground group-hover:text-foreground"
}`}
>
{agent.name}
</span>
</Link>
);
}