Adopt design comps: dark system, new landing/auth, dashboard shell + canvas

Re-skins the whole app to the dark design comps and wires the new surfaces to
the backend (the /api proxy + auth + schemas are unchanged).

Design system:
- globals.css: remapped @theme tokens to the comp palette (#08080a base, coral
  #ff6f61, status cyan/green/amber/purple/teal); token names preserved
- MeshMark: triangle + 3-node brand glyph; cm-flow/cm-blink/cm-halo keyframes
- marketing flipped light → dark

Backend (migration 0012):
- agents.model_binding (persisted on team deploy) + GET /api/claws/{id}/runtime-config
- routine_runs table + scheduler journaling + GET /api/routines/runs
- GET /api/claws/{id}/compartments (anatomy aggregate)
- GET /api/structure/stats (workspace counts)

Frontend:
- Landing: full dark marketing page (hero constellation, deploy ladder,
  12-topology taxonomy, recursive execution, compare/Pareto, safety, self-host)
- Auth: dark split-panel AuthShell + comp LoginForm + Clerk SignIn themed dark
- Dashboard shell: TopBar (breadcrumb + live stats + deploy + user) + StatusBar
  (runner/sandbox/doors); rail slimmed to 60px + 252px context column
- ConstellationCanvas (radial recursive) replaces the graph view in StructureCanvas;
  selecting a claw opens ComputerPanel (apps/now-running/dock); RoutinesPanel
- Claw anatomy view (/claws/[id]/anatomy) from compartments + runtime-config

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-19 04:12:16 -07:00
co-authored by Claude Opus 4.8
parent 3eca4ed70c
commit 540c74f42e
41 changed files with 2253 additions and 406 deletions
@@ -0,0 +1,129 @@
"use client";
// The claw "anatomy" view (design comp, CLAW tier): a central core surrounded by
// compartment cards — Skills / Personality / Memory / Tools·Doors / Capabilities
// / Safety·§15 — aggregated from the backend. Each compartment is color-tinted.
import Link from "next/link";
import { useEffect, useState } from "react";
import { ArrowLeft } from "lucide-react";
interface Compartment {
key: string;
label: string;
items: string[];
count: number | null;
}
interface RuntimeConfig {
model: string | null;
sandbox_enabled: boolean;
network_allowed: boolean;
}
const TINT: Record<string, string> = {
skills: "#ff6f61",
personality: "#c98af0",
memory: "#5fd08a",
tools: "#5ec8d8",
capabilities: "#e8b465",
safety: "#6fd0c0",
};
export function ClawAnatomy({ clawId }: { clawId: string }) {
const [compartments, setCompartments] = useState<Compartment[]>([]);
const [cfg, setCfg] = useState<RuntimeConfig | null>(null);
const [name, setName] = useState("Claw");
const [loaded, setLoaded] = useState(false);
useEffect(() => {
let live = true;
void (async () => {
const [c, rc, settings] = await Promise.all([
fetch(`/api/claws/${clawId}/compartments`).then((x) => (x.ok ? x.json() : [])).catch(() => []),
fetch(`/api/claws/${clawId}/runtime-config`).then((x) => (x.ok ? x.json() : null)).catch(() => null),
fetch(`/api/claws/settings/full?clawId=${clawId}`).then((x) => (x.ok ? x.json() : null)).catch(() => null),
]);
if (!live) return;
setCompartments(c as Compartment[]);
setCfg(rc as RuntimeConfig | null);
const n = (settings as { agent?: { name?: string } } | null)?.agent?.name;
if (n) setName(n);
setLoaded(true);
})();
return () => {
live = false;
};
}, [clawId]);
return (
<div className="mx-auto flex w-full max-w-4xl flex-col gap-6 p-6">
<div className="flex items-center gap-3">
<Link
href={`/claws/${clawId}`}
className="flex items-center gap-1.5 font-mono text-[11px] text-muted-foreground hover:text-foreground"
>
<ArrowLeft size={13} /> back to chat
</Link>
</div>
{/* Core */}
<div className="flex items-center gap-4">
<div
className="relative flex size-[72px] items-center justify-center rounded-full text-2xl font-bold"
style={{ background: "linear-gradient(135deg,#ff9a6a,#ff6f4a)", color: "#2a0d05" }}
>
<span className="cm-halo absolute inset-0 rounded-full" style={{ background: "rgba(255,111,97,.3)" }} />
<span className="relative">{name.charAt(0).toUpperCase()}</span>
</div>
<div>
<h1 className="text-xl font-semibold tracking-tight">{name}</h1>
<p className="font-mono text-[11px] text-muted-foreground">
ANATOMY · what {name} is made of
{cfg?.model ? <span className="ml-2 capitalize text-running">● {cfg.model}</span> : null}
</p>
</div>
</div>
{/* Compartments */}
{!loaded ? (
<p className="text-sm text-muted-foreground">Loading…</p>
) : (
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
{compartments.map((c) => {
const tint = TINT[c.key] ?? "#ff6f61";
return (
<div
key={c.key}
className="rounded-2xl border bg-[#0c0c0f] p-4"
style={{ borderColor: `${tint}40` }}
>
<div className="mb-2.5 flex items-center justify-between">
<span className="font-mono text-[10px] tracking-[0.12em]" style={{ color: tint }}>
{c.label.toUpperCase()}
</span>
{c.count != null ? (
<span className="font-mono text-[10px] text-muted-foreground">{c.count}</span>
) : null}
</div>
{c.items.length === 0 ? (
<p className="text-xs text-subtle-foreground">—</p>
) : (
<div className="flex flex-col gap-1.5">
{c.items.slice(0, 5).map((it, i) => (
<div key={i} className="truncate text-[13px] text-[#cfcfd5]">
{it}
</div>
))}
{c.items.length > 5 ? (
<div className="text-xs text-subtle-foreground">+{c.items.length - 5} more</div>
) : null}
</div>
)}
</div>
);
})}
</div>
)}
</div>
);
}