diff --git a/ui/src/index.css b/ui/src/index.css index 1d0f4968..9ce6f265 100644 --- a/ui/src/index.css +++ b/ui/src/index.css @@ -66,6 +66,12 @@ --color-near-black: var(--near-black); --color-hover-gray: var(--hover-gray); --color-silver: var(--silver); + /* [nexus] chart palette exception — see MIGRATION-PLAN.md §6 and agent-role-colors.ts */ + --color-chart-role-1: var(--chart-role-1); + --color-chart-role-2: var(--chart-role-2); + --color-chart-role-3: var(--chart-role-3); + --color-chart-role-4: var(--chart-role-4); + --color-chart-role-5: var(--chart-role-5); --radius-sm: 4px; --radius-md: 4px; --radius-lg: 8px; @@ -128,6 +134,12 @@ --silver: #6b6b6b; --charcoal-border: rgba(20, 20, 20, 0.12); --charcoal-divider: rgba(20, 20, 20, 0.08); + /* [nexus] chart palette exception — 5 muted hues for agent-role differentiation */ + --chart-role-1: #4f5100; /* olive (volt family) — generalist/primary */ + --chart-role-2: #0f766e; /* teal — ops/secondary */ + --chart-role-3: #6d28d9; /* violet — creative/tertiary */ + --chart-role-4: #b45309; /* amber — data/quaternary */ + --chart-role-5: #6b6b6b; /* gray — support/quinary */ } /* -- Dark mode --------------------------------------------------------- */ @@ -182,6 +194,12 @@ --silver: #a0a0a0; --charcoal-border: rgba(65, 65, 65, 0.8); --charcoal-divider: #343434; + /* [nexus] chart palette exception — 5 muted hues for agent-role differentiation */ + --chart-role-1: #faff69; /* volt — generalist/primary */ + --chart-role-2: #6ee7b7; /* muted teal-green — ops/secondary */ + --chart-role-3: #c4b5fd; /* muted lavender — creative/tertiary */ + --chart-role-4: #fcd34d; /* muted amber — data/quaternary */ + --chart-role-5: #a0a0a0; /* silver — support/quinary */ } /* -- highlight.js syntax theme overrides (chat code blocks) ------------- */ diff --git a/ui/src/lib/agent-role-colors.ts b/ui/src/lib/agent-role-colors.ts index af9b68b2..fa7ecac3 100644 --- a/ui/src/lib/agent-role-colors.ts +++ b/ui/src/lib/agent-role-colors.ts @@ -1,17 +1,68 @@ import type { AgentRole } from "@paperclipai/shared"; +/** + * Agent role → color class mapping. + * + * [nexus] Migrated to design system tokens — see MIGRATION-PLAN.md §6. + * + * DESIGN.md §2 restricts the palette to "black, neon, green, gray". This file + * is the one sanctioned exception: a controlled 5-hue "chart palette" so + * agent-mesh views can differentiate roles at a glance. + * + * The 5 hues are defined as CSS variables in `ui/src/index.css` + * (`--chart-role-1` .. `--chart-role-5`) and exposed as Tailwind utilities via + * `@theme inline` (`text-chart-role-1` .. `text-chart-role-5`). Each hue is + * verified to pass WCAG AA for normal text on both the dark canvas (#000) and + * light canvas (#fafafa). + * + * We have 11 agent roles but only 5 slots — we cycle with modular arithmetic. + * Collisions past 5 roles are accepted (role identity is also carried by + * labels, icons, and names — color is a secondary signal). + */ + +// Ordered list of role → slot assignments. The order is intentional: +// - generalist/pm get the brand anchor (volt in dark / olive in light) +// - leadership (ceo/cto/cmo/cfo) spread across the other 4 slots +// - engineering/design/qa/devops/research reuse the cycle +// This is mechanical mod-5 over the AGENT_ROLES array order, but declared +// explicitly so future role additions get a deterministic slot. +const ROLE_SLOT: Record = { + // Slot 1 — volt / olive (brand anchor, generalist) + general: 1, + pm: 1, + // Slot 2 — teal (ops) + devops: 2, + cto: 2, + // Slot 3 — violet (creative) + designer: 3, + cmo: 3, + // Slot 4 — amber (data / leadership) + ceo: 4, + cfo: 4, + researcher: 4, + // Slot 5 — gray (support) + engineer: 5, + qa: 5, +}; + +function slotClass(slot: 1 | 2 | 3 | 4 | 5): string { + // `text-chart-role-N` is a valid Tailwind utility because `--color-chart-role-N` + // is declared in the `@theme inline` block in index.css. + return `text-chart-role-${slot}`; +} + export const agentRoleColors: Record = { - pm: "text-blue-600 dark:text-blue-400", - engineer: "text-violet-600 dark:text-violet-400", - ceo: "text-amber-600 dark:text-amber-400", - general: "text-slate-600 dark:text-slate-400", - designer: "text-pink-600 dark:text-pink-400", - qa: "text-orange-600 dark:text-orange-400", - researcher: "text-teal-600 dark:text-teal-400", - devops: "text-emerald-600 dark:text-emerald-400", - cto: "text-indigo-600 dark:text-indigo-400", - cmo: "text-rose-600 dark:text-rose-400", - cfo: "text-cyan-600 dark:text-cyan-400", + pm: slotClass(ROLE_SLOT.pm), + engineer: slotClass(ROLE_SLOT.engineer), + ceo: slotClass(ROLE_SLOT.ceo), + general: slotClass(ROLE_SLOT.general), + designer: slotClass(ROLE_SLOT.designer), + qa: slotClass(ROLE_SLOT.qa), + researcher: slotClass(ROLE_SLOT.researcher), + devops: slotClass(ROLE_SLOT.devops), + cto: slotClass(ROLE_SLOT.cto), + cmo: slotClass(ROLE_SLOT.cmo), + cfo: slotClass(ROLE_SLOT.cfo), }; export const agentRoleColorDefault = "text-muted-foreground"; diff --git a/ui/src/lib/status-colors.ts b/ui/src/lib/status-colors.ts index beee561a..8f6bf317 100644 --- a/ui/src/lib/status-colors.ts +++ b/ui/src/lib/status-colors.ts @@ -3,106 +3,124 @@ * * Every component that renders a status indicator (StatusIcon, StatusBadge, * agent status dots, etc.) should import from here so colors stay consistent. + * + * [nexus] Migrated to design system tokens — see MIGRATION-PLAN.md §3, §6. + * All entries use semantic tokens (bg-destructive, bg-warning, bg-success, + * bg-primary, bg-muted) instead of raw palette utilities. Dark-mode variants + * are handled automatically by the token system in index.css. */ // --------------------------------------------------------------------------- // Issue status colors +// [nexus] Migrated to design system tokens — see MIGRATION-PLAN.md // --------------------------------------------------------------------------- /** StatusIcon circle: text + border classes */ export const issueStatusIcon: Record = { - backlog: "text-muted-foreground border-muted-foreground", - todo: "text-blue-600 border-blue-600 dark:text-blue-400 dark:border-blue-400", - in_progress: "text-yellow-600 border-yellow-600 dark:text-yellow-400 dark:border-yellow-400", - in_review: "text-violet-600 border-violet-600 dark:text-violet-400 dark:border-violet-400", - done: "text-green-600 border-green-600 dark:text-green-400 dark:border-green-400", - cancelled: "text-neutral-500 border-neutral-500", - blocked: "text-red-600 border-red-600 dark:text-red-400 dark:border-red-400", + // backlog / not-started → muted (softer than plain idle) + backlog: "text-muted-foreground border-border", + // todo → muted foreground (neutral "not yet started") + todo: "text-muted-foreground border-border", + // in_progress / active / running → primary accent + in_progress: "text-primary border-primary/60", + // in_review → warning (awaiting action) + in_review: "text-warning border-warning/60", + // done / completed / success + done: "text-success border-success/60", + // cancelled / archived → muted, dim + cancelled: "text-muted-foreground/70 border-border", + // blocked → softer destructive (distinct from hard "error") + blocked: "text-destructive border-destructive/50", }; -export const issueStatusIconDefault = "text-muted-foreground border-muted-foreground"; +export const issueStatusIconDefault = "text-muted-foreground border-border"; /** Text-only color for issue statuses (dropdowns, labels) */ export const issueStatusText: Record = { backlog: "text-muted-foreground", - todo: "text-blue-600 dark:text-blue-400", - in_progress: "text-yellow-600 dark:text-yellow-400", - in_review: "text-violet-600 dark:text-violet-400", - done: "text-green-600 dark:text-green-400", - cancelled: "text-neutral-500", - blocked: "text-red-600 dark:text-red-400", + todo: "text-muted-foreground", + in_progress: "text-primary", + in_review: "text-warning", + done: "text-success", + cancelled: "text-muted-foreground/70", + blocked: "text-destructive", }; export const issueStatusTextDefault = "text-muted-foreground"; // --------------------------------------------------------------------------- // Badge colors — used by StatusBadge for all entity types +// [nexus] Migrated to design system tokens — see MIGRATION-PLAN.md // --------------------------------------------------------------------------- export const statusBadge: Record = { // Agent statuses - active: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", - running: "bg-cyan-100 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300", - paused: "bg-orange-100 text-orange-700 dark:bg-orange-900/50 dark:text-orange-300", - idle: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-300", - archived: "bg-muted text-muted-foreground", + active: "bg-success/15 text-success border border-success/30", + running: "bg-primary/15 text-primary border border-primary/30", + paused: "bg-warning/15 text-warning border border-warning/30", + idle: "bg-muted text-muted-foreground border border-border", + archived: "bg-muted/40 text-muted-foreground/70 border border-border", // Goal statuses - planned: "bg-muted text-muted-foreground", - achieved: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", - completed: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", + planned: "bg-muted/60 text-muted-foreground border border-border", + achieved: "bg-success/15 text-success border border-success/30", + completed: "bg-success/15 text-success border border-success/30", // Run statuses - failed: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", - timed_out: "bg-orange-100 text-orange-700 dark:bg-orange-900/50 dark:text-orange-300", - succeeded: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", - error: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", - terminated: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", - pending: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-300", + failed: "bg-destructive/15 text-destructive border border-destructive/30", + // [nexus] timed_out mapped to warning (closer semantic than "error") — note in report + timed_out: "bg-warning/15 text-warning border border-warning/30", + succeeded: "bg-success/15 text-success border border-success/30", + error: "bg-destructive/15 text-destructive border border-destructive/30", + terminated: "bg-destructive/15 text-destructive border border-destructive/30", + pending: "bg-warning/15 text-warning border border-warning/30", // Approval statuses - pending_approval: "bg-amber-100 text-amber-700 dark:bg-amber-900/50 dark:text-amber-300", - revision_requested: "bg-amber-100 text-amber-700 dark:bg-amber-900/50 dark:text-amber-300", - approved: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", - rejected: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", + pending_approval: "bg-warning/15 text-warning border border-warning/30", + revision_requested: "bg-warning/15 text-warning border border-warning/30", + approved: "bg-success/15 text-success border border-success/30", + rejected: "bg-destructive/15 text-destructive border border-destructive/30", // Issue statuses — consistent hues with issueStatusIcon above - backlog: "bg-muted text-muted-foreground", - todo: "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300", - in_progress: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-300", - in_review: "bg-violet-100 text-violet-700 dark:bg-violet-900/50 dark:text-violet-300", - blocked: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300", - done: "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300", - cancelled: "bg-muted text-muted-foreground", + backlog: "bg-muted/60 text-muted-foreground border border-border", + todo: "bg-muted/60 text-muted-foreground border border-border", + in_progress: "bg-primary/15 text-primary border border-primary/30", + in_review: "bg-warning/15 text-warning border border-warning/30", + blocked: "bg-destructive/10 text-destructive border border-destructive/25", + done: "bg-success/15 text-success border border-success/30", + cancelled: "bg-muted/40 text-muted-foreground/70 border border-border", }; -export const statusBadgeDefault = "bg-muted text-muted-foreground"; +export const statusBadgeDefault = "bg-muted text-muted-foreground border border-border"; // --------------------------------------------------------------------------- // Agent status dot — solid background for small indicator dots +// [nexus] Migrated to design system tokens — see MIGRATION-PLAN.md // --------------------------------------------------------------------------- export const agentStatusDot: Record = { - running: "bg-cyan-400 animate-pulse", - active: "bg-green-400", - paused: "bg-yellow-400", - idle: "bg-yellow-400", - pending_approval: "bg-amber-400", - error: "bg-red-400", - archived: "bg-neutral-400", + running: "bg-primary animate-pulse", + active: "bg-success", + paused: "bg-warning", + idle: "bg-muted-foreground", + pending_approval: "bg-warning", + error: "bg-destructive", + archived: "bg-muted-foreground/50", }; -export const agentStatusDotDefault = "bg-neutral-400"; +export const agentStatusDotDefault = "bg-muted-foreground"; // --------------------------------------------------------------------------- // Priority colors +// [nexus] Migrated to design system tokens — see MIGRATION-PLAN.md +// urgent/critical → destructive, high → warning, medium → primary, low → muted // --------------------------------------------------------------------------- export const priorityColor: Record = { - critical: "text-red-600 dark:text-red-400", - high: "text-orange-600 dark:text-orange-400", - medium: "text-yellow-600 dark:text-yellow-400", - low: "text-blue-600 dark:text-blue-400", + critical: "text-destructive", + high: "text-warning", + medium: "text-primary", + low: "text-muted-foreground", }; -export const priorityColorDefault = "text-yellow-600 dark:text-yellow-400"; +export const priorityColorDefault = "text-muted-foreground";