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
+37 -16
View File
@@ -1,13 +1,23 @@
import { redirect } from "next/navigation";
import { z } from "zod";
import { LeftRail } from "@/components/shell/LeftRail";
import { ApiAuthError } from "@/lib/api/http";
import { StatusBar } from "@/components/shell/StatusBar";
import { TopBar } from "@/components/shell/TopBar";
import { ApiAuthError, apiFetch } from "@/lib/api/http";
import { fetchClaws, fetchCredits, fetchMe } from "@/lib/api/team";
import { fetchCompanies, fetchOrgs, fetchTeams, type GroupSummary } from "@/lib/api/structure";
import {
fetchCompanies,
fetchOrgs,
fetchStats,
fetchTeams,
type GroupSummary,
type StructureStats,
} from "@/lib/api/structure";
import type { Agent, Credits, User } from "@/lib/api/schemas";
// Every workspace page shares the persistent rail (§4). This layout reads
// only path-level data — search params stay client-side (see panel-params).
// Every workspace page shares the persistent shell (top bar + structure rail +
// context column + status bar). The layout server-fetches the chrome data once.
export default async function WorkspaceLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
@@ -17,16 +27,24 @@ export default async function WorkspaceLayout({
let orgs: GroupSummary[];
let companies: GroupSummary[];
let teams: GroupSummary[];
let stats: StructureStats | null;
let doors: number;
try {
// Structure lists are non-critical chrome — never let one fail the shell.
// Non-critical chrome — never let one failed fetch break the shell.
const opt = <T,>(p: Promise<T>, fallback: T) => p.catch(() => fallback);
const groups = <T,>(p: Promise<T[]>) => p.catch(() => [] as T[]);
[user, roster, credits, orgs, companies, teams] = await Promise.all([
[user, roster, credits, orgs, companies, teams, stats, doors] = await Promise.all([
fetchMe(),
fetchClaws(),
fetchCredits(),
groups(fetchOrgs()),
groups(fetchCompanies()),
groups(fetchTeams()),
opt(fetchStats(), null),
opt(
apiFetch(z.array(z.unknown()), "/api/approvals").then((a) => a.length),
0,
),
]);
} catch (error) {
if (error instanceof ApiAuthError) {
@@ -35,16 +53,19 @@ export default async function WorkspaceLayout({
throw error;
}
return (
<div className="flex min-h-dvh">
<LeftRail
user={user}
roster={roster}
orgs={orgs}
companies={companies}
teams={teams}
creditsBalance={credits.available}
/>
<main className="min-w-0 flex-1">{children}</main>
<div className="flex h-dvh flex-col">
<TopBar user={user} stats={stats} />
<div className="flex min-h-0 flex-1">
<LeftRail
roster={roster}
orgs={orgs}
companies={companies}
teams={teams}
creditsBalance={credits.available}
/>
<main className="min-w-0 flex-1 overflow-y-auto">{children}</main>
</div>
<StatusBar stats={stats} doors={doors} />
</div>
);
}