feat(11-02): replace 1113 old CSS variable references with Paperclip design tokens

- Replace all bg-[color:var(--old)] with bg-background/bg-card/bg-muted/bg-primary etc.
- Replace all text-[color:var(--old)] with text-foreground/text-muted-foreground/text-primary etc.
- Replace all border-[color:var(--line)] with border-border
- Replace all inline var(--old) with var(--new) equivalents
- Replace all rounded-[6px]/rounded-[8px] with rounded-lg
- Replace .surface class with bg-card border border-border shadow-sm
- Replace .focus-ring class with focus-visible Tailwind utilities
- Replace .mono class with font-mono
- Replace data-theme attribute with class-based dark mode
- 99 files updated, ~1265 lines changed, zero old references remaining
This commit is contained in:
ZacharyZhang-NY committed 2026-03-27 22:12:00 -04:00
1 parent 2ed5dd3388
commit 06ea4c6aec
99 files changed
+1265 -1265

No files matched your search

@@ -77,7 +77,7 @@ export function AgentCreator({
options={executionReadyConnectors.map((connector) => ({ value: connector.id, label: connector.label }))}
/>
{executionReadyConnectors.length === 0 ? (
<p className="text-[12px] text-[color:var(--warn)]">
<p className="text-[12px] text-yellow-600 dark:text-yellow-400">
No execution-ready connector is available. Fix connector health before requesting hires.
</p>
) : null}
@@ -127,7 +127,7 @@ export function AgentCreator({
onChange={setCapabilities}
placeholder="What this agent does"
/>
<p className="text-[12px] text-[color:var(--muted)]">
<p className="text-[12px] text-muted-foreground">
New agents enter the hiring pipeline first. Approval activates the agent and keeps onboarding, budgets, and org history linked to the same record.
</p>
<ActionButton
@@ -173,7 +173,7 @@ export function AgentCreator({
icon={Robot}
disabled={!selectedConnector}
/>
{requestError ? <p className="text-[12px] text-[color:var(--danger)]">{requestError}</p> : null}
{requestError ? <p className="text-[12px] text-destructive">{requestError}</p> : null}
</div>
);
}
@@ -128,7 +128,7 @@ export function AgentEditor({
]}
/>
{pendingApproval ? (
<p className="text-[12px] text-[color:var(--muted)]">
<p className="text-[12px] text-muted-foreground">
Pending hires must be approved or rejected from Hiring or Approvals. Status changes are intentionally locked here.
</p>
) : null}
@@ -140,7 +140,7 @@ export function AgentEditor({
options={connectorOptions}
/>
{selectedConnectorIssue ? (
<p className="text-[12px] text-[color:var(--warn)]">
<p className="text-[12px] text-yellow-600 dark:text-yellow-400">
{selectedConnectorIssue}
</p>
) : null}
@@ -193,8 +193,8 @@ export function AgentEditor({
<HeartbeatSection agent={agent} companyId={companyId} pendingApproval={pendingApproval} persistedConnectorIssue={persistedConnectorIssue} onSaved={onSaved} />
{/* Skills section (D-04 dual access) */}
<div className="mt-6 border-t border-[color:var(--line)] pt-4">
<h3 className="text-[13px] font-semibold uppercase tracking-[0.08em] text-[color:var(--accent-text)] mb-3">Skills</h3>
<div className="mt-6 border-t border-border pt-4">
<h3 className="text-[13px] font-semibold uppercase tracking-[0.08em] text-primary mb-3">Skills</h3>
<SkillAgentToggles mode="agent" companyId={companyId} agentId={agent.id} skills={skills} />
</div>
@@ -271,11 +271,11 @@ export function AgentEditor({
)}
</div>
{pendingApproval ? (
<p className="text-[12px] text-[color:var(--muted)]">
<p className="text-[12px] text-muted-foreground">
Pending hires are read-only here. Use Hiring or Approvals to approve or reject the request before editing the agent profile.
</p>
) : null}
{saveError ? <p className="text-[12px] text-[color:var(--danger)]">{saveError}</p> : null}
{saveError ? <p className="text-[12px] text-destructive">{saveError}</p> : null}
</div>
);
}
@@ -38,7 +38,7 @@ export function AgentRoster({
return (
<div
ref={parentRef}
className="h-full overflow-auto border-y border-[color:var(--line)]"
className="h-full overflow-auto border-y border-border"
role="listbox"
aria-label="Agent roster"
onKeyDown={handleKeyDown}
@@ -73,29 +73,29 @@ export function AgentRoster({
width: "100%",
transform: `translateY(${virtualRow.start}px)`,
}}
className={`focus-ring outline-none ${virtualRow.index === focusedIndex ? "ring-1 ring-[color:var(--accent)] ring-inset" : ""}`}
className={`focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 outline-none ${virtualRow.index === focusedIndex ? "ring-1 ring-[color:var(--primary)] ring-inset" : ""}`}
>
<button
type="button"
onClick={() => onSelect(agent.id)}
tabIndex={-1}
className={`block w-full border-b border-[color:var(--line)] px-4 py-3 text-left last:border-b-0 cursor-pointer transition-colors duration-150 ${isSelected ? "bg-[color:var(--accent-soft)] border-l-[3px] border-l-[color:var(--accent)]" : "hover:bg-[color:var(--panel-soft)]"}`}
className={`block w-full border-b border-border px-4 py-3 text-left last:border-b-0 cursor-pointer transition-colors duration-150 ${isSelected ? "bg-accent border-l-[3px] border-l-[color:var(--primary)]" : "hover:bg-muted"}`}
>
<div className="mb-2 flex items-center justify-between">
<div className="flex items-center gap-2">
{isSelected && (
<CheckCircle size={16} weight="fill" className="text-[color:var(--accent)]" />
<CheckCircle size={16} weight="fill" className="text-primary" />
)}
<div>
<div className={`truncate text-[14px] font-semibold text-[color:var(--text)]`}>{agent.name}</div>
<div className="truncate text-[11px] text-[color:var(--muted)]">
<div className={`truncate text-[14px] font-semibold text-foreground`}>{agent.name}</div>
<div className="truncate text-[11px] text-muted-foreground">
{agent.role} · {agent.title || "No title"}
</div>
</div>
</div>
<StatusPill status={agent.status} />
</div>
<div className="flex items-center justify-between text-[11px] text-[color:var(--muted)]">
<div className="flex items-center justify-between text-[11px] text-muted-foreground">
<span>Connector: {connector?.label ?? agent.connectorId}</span>
{workspace && <span>Workspace: {workspace.name}</span>}
</div>
@@ -30,19 +30,19 @@ export function GoalList({
<ListRow
key={goal.id}
onClick={() => onSelect(goal.id)}
className={`cursor-pointer transition-colors duration-100 ${isSelected ? "bg-[color:var(--accent-soft)]" : "hover:bg-[color:var(--panel-soft)]"}`}
className={`cursor-pointer transition-colors duration-100 ${isSelected ? "bg-accent" : "hover:bg-muted"}`}
>
<div className="mb-2 flex items-center justify-between gap-3">
<div className="flex min-w-0 items-center gap-2">
{isSelected && (
<CheckCircle size={16} weight="fill" className="shrink-0 text-[color:var(--accent)]" />
<CheckCircle size={16} weight="fill" className="shrink-0 text-primary" />
)}
<div className="truncate text-[14px] font-semibold text-[color:var(--text)]">{goal.title}</div>
<div className="truncate text-[14px] font-semibold text-foreground">{goal.title}</div>
</div>
<StatusPill status={goal.status} />
</div>
<div className="line-clamp-2 text-[13px] text-[color:var(--muted)]">{goal.description}</div>
<div className="mt-1 flex gap-4 text-[11px] text-[color:var(--muted)]">
<div className="line-clamp-2 text-[13px] text-muted-foreground">{goal.description}</div>
<div className="mt-1 flex gap-4 text-[11px] text-muted-foreground">
{parentGoal && <span>Parent: {parentGoal.title}</span>}
{ownerAgent && <span>Owner: {ownerAgent.name}</span>}
</div>
@@ -73,10 +73,10 @@ export function OrgChart({ agents, onSelectAgent }: { agents: AgentRecord[]; onS
const zoomOut = () => { const nz = Math.max(zoom * 0.8, 0.2); const c = containerRef.current; if (c) { const cx = c.clientWidth / 2; const cy = c.clientHeight / 2; const s = nz / zoom; setPan({ x: cx - s * (cx - pan.x), y: cy - s * (cy - pan.y) }); } setZoom(nz); };
return (
<div ref={containerRef} className="relative min-h-[400px] h-[clamp(400px,60vh,720px)] w-full overflow-hidden rounded-[8px] border border-[color:var(--line)] bg-[color:var(--bg)]" style={{ cursor: dragging ? "grabbing" : "grab" }} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} onMouseLeave={handleMouseUp} onWheel={handleWheel}>
<div ref={containerRef} className="relative min-h-[400px] h-[clamp(400px,60vh,720px)] w-full overflow-hidden rounded-lg border border-border bg-background" style={{ cursor: dragging ? "grabbing" : "grab" }} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} onMouseLeave={handleMouseUp} onWheel={handleWheel}>
<div className="absolute right-3 top-3 z-10 flex flex-col gap-1">
{[{ label: "+", ariaLabel: "Zoom in", action: zoomIn }, { label: "\u2212", ariaLabel: "Zoom out", action: zoomOut }, { label: "Fit", ariaLabel: "Fit chart to screen", action: fitToScreen }].map((btn) => (
<button key={btn.ariaLabel} className="flex h-7 w-7 items-center justify-center rounded-[6px] border border-[color:var(--line)] bg-[color:var(--panel)] text-[12px] text-[color:var(--text)] transition hover:bg-[color:var(--panel-soft)]" onClick={btn.action} aria-label={btn.ariaLabel}>{btn.label}</button>
<button key={btn.ariaLabel} className="flex h-7 w-7 items-center justify-center rounded-lg border border-border bg-card text-[12px] text-foreground transition hover:bg-muted" onClick={btn.action} aria-label={btn.ariaLabel}>{btn.label}</button>
))}
</div>
<svg className="pointer-events-none absolute inset-0" style={{ width: "100%", height: "100%" }}>
@@ -85,7 +85,7 @@ export function OrgChart({ agents, onSelectAgent }: { agents: AgentRecord[]; onS
const x1 = parent.x + CARD_W / 2, y1 = parent.y + CARD_H, x2 = child.x + CARD_W / 2, y2 = child.y;
const midY = (y1 + y2) / 2;
const isChildRunning = child.agent.status === "running";
return <path key={`${parent.agent.id}-${child.agent.id}`} d={`M ${x1} ${y1} C ${x1} ${midY}, ${x2} ${midY}, ${x2} ${y2}`} fill="none" stroke={isChildRunning ? "var(--success)" : "var(--line-strong)"} strokeWidth={isChildRunning ? 2 : 1.5} strokeDasharray={isChildRunning ? "6 3" : "none"} opacity={isChildRunning ? 0.8 : 0.5} />;
return <path key={`${parent.agent.id}-${child.agent.id}`} d={`M ${x1} ${y1} C ${x1} ${midY}, ${x2} ${midY}, ${x2} ${y2}`} fill="none" stroke={isChildRunning ? "var(--primary)" : "var(--border)"} strokeWidth={isChildRunning ? 2 : 1.5} strokeDasharray={isChildRunning ? "6 3" : "none"} opacity={isChildRunning ? 0.8 : 0.5} />;
})}
</g>
</svg>
@@ -100,27 +100,27 @@ export function OrgChart({ agents, onSelectAgent }: { agents: AgentRecord[]; onS
const isPending = node.agent.status === "pending_approval";
const isCEO = node.children.length > 0 && !node.agent.reportsTo;
return (
<div key={node.agent.id} data-org-card className={`absolute cursor-pointer select-none rounded-[8px] border bg-[color:var(--panel)] shadow-sm transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5 ${isRunning ? "border-[color:var(--success)] shadow-[0_0_12px_rgba(74,222,128,0.15)]" : isError ? "border-[color:var(--danger)] border-opacity-50" : isPending ? "border-[color:var(--warn)] border-dashed" : "border-[color:var(--line)] hover:border-[color:var(--line-strong)]"}`} style={{ left: node.x, top: node.y, width: CARD_W, minHeight: CARD_H }} onClick={() => onSelectAgent?.(node.agent.id)}>
<div className={`rounded-t-[7px] ${isCEO ? "h-[4px] bg-[color:var(--accent)]" : node.children.length > 0 ? "h-[3px] bg-[color:var(--warn)]" : "h-[2px] bg-[color:var(--muted)] opacity-30"}`} />
<div key={node.agent.id} data-org-card className={`absolute cursor-pointer select-none rounded-lg border bg-card shadow-sm transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5 ${isRunning ? "border-[color:var(--primary)] shadow-[0_0_12px_rgba(74,222,128,0.15)]" : isError ? "border-[color:var(--destructive)] border-opacity-50" : isPending ? "border-[color:var(--destructive)] border-dashed" : "border-border hover:border-border"}`} style={{ left: node.x, top: node.y, width: CARD_W, minHeight: CARD_H }} onClick={() => onSelectAgent?.(node.agent.id)}>
<div className={`rounded-t-[7px] ${isCEO ? "h-[4px] bg-primary" : node.children.length > 0 ? "h-[3px] bg-yellow-600 dark:bg-yellow-400" : "h-[2px] bg-[color:var(--muted-foreground)] opacity-30"}`} />
<div className="flex items-center gap-3 px-4 py-3">
<div className="relative shrink-0">
<div className={`flex h-11 w-11 items-center justify-center rounded-full text-[13px] font-bold ${isActive ? "bg-[color:var(--success-soft)] text-[color:var(--success)]" : isError ? "bg-[color:var(--danger-soft)] text-[color:var(--danger)]" : "bg-[color:var(--panel-soft)] text-[color:var(--muted-strong)]"}`}>{initials}</div>
<div className={`flex h-11 w-11 items-center justify-center rounded-full text-[13px] font-bold ${isActive ? "bg-green-100 dark:bg-green-900/50 text-green-600 dark:text-green-400" : isError ? "bg-red-100 dark:bg-red-900/50 text-destructive" : "bg-muted text-muted-foreground"}`}>{initials}</div>
{isRunning ? (
<span className="absolute -bottom-0.5 -right-0.5 flex h-3.5 w-3.5" aria-hidden="true">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full opacity-40" style={{ backgroundColor: dotColor, willChange: "transform" }} />
<span className="relative inline-flex h-2.5 w-2.5 rounded-full border-2 border-[color:var(--panel)]" style={{ backgroundColor: dotColor }} />
<span className="relative inline-flex h-2.5 w-2.5 rounded-full border-2 border-[color:var(--card)]" style={{ backgroundColor: dotColor }} />
</span>
) : (
<span className="absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-[color:var(--panel)]" style={{ backgroundColor: dotColor }} aria-hidden="true" />
<span className="absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-[color:var(--card)]" style={{ backgroundColor: dotColor }} aria-hidden="true" />
)}
<span className="sr-only">{`Status: ${node.agent.status}`}</span>
</div>
<div className="flex min-w-0 flex-1 flex-col items-start">
<span className="truncate text-[14px] font-semibold leading-tight text-[color:var(--text)]">{node.agent.name}</span>
<span className="mt-0.5 text-[11px] leading-tight text-[color:var(--muted)]">{node.agent.title || node.agent.role}</span>
<span className="truncate text-[14px] font-semibold leading-tight text-foreground">{node.agent.name}</span>
<span className="mt-0.5 text-[11px] leading-tight text-muted-foreground">{node.agent.title || node.agent.role}</span>
<div className="mt-1.5 flex items-center gap-2">
<span className="rounded bg-[color:var(--panel-soft)] px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]">{connectorLabel}</span>
{node.agent.heartbeatEnabled ? <Heartbeat size={10} className="text-[color:var(--success)]" /> : null}
<span className="rounded bg-muted px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">{connectorLabel}</span>
{node.agent.heartbeatEnabled ? <Heartbeat size={10} className="text-green-600 dark:text-green-400" /> : null}
</div>
</div>
</div>
@@ -31,19 +31,19 @@ export function ProjectList({
<ListRow
key={project.id}
onClick={() => onSelect(project.id)}
className={`cursor-pointer transition-colors duration-100 ${isSelected ? "bg-[color:var(--accent-soft)]" : "hover:bg-[color:var(--panel-soft)]"}`}
className={`cursor-pointer transition-colors duration-100 ${isSelected ? "bg-accent" : "hover:bg-muted"}`}
>
<div className="mb-2 flex items-center justify-between">
<div className="flex items-center gap-2">
{isSelected && (
<CheckCircle size={16} weight="fill" className="text-[color:var(--accent)]" />
<CheckCircle size={16} weight="fill" className="text-primary" />
)}
<div className="truncate text-[14px] font-semibold text-[color:var(--text)]">{project.name}</div>
<div className="truncate text-[14px] font-semibold text-foreground">{project.name}</div>
</div>
<StatusPill status={project.status} />
</div>
<div className="mb-2 text-[13px] text-[color:var(--muted)]">{project.description}</div>
<div className="flex flex-wrap gap-4 text-[11px] text-[color:var(--muted)]">
<div className="mb-2 text-[13px] text-muted-foreground">{project.description}</div>
<div className="flex flex-wrap gap-4 text-[11px] text-muted-foreground">
<span>
Goal: {goals.find((g) => g.id === project.goalId)?.title ?? "None"}
</span>
@@ -8,13 +8,13 @@ export function BudgetBar({ spent, budget }: { spent: number; budget: number })
const overBudget = spent > budget && budget > 0;
return (
<div className="flex items-center gap-2">
<div className="h-1.5 w-20 overflow-hidden rounded-full bg-[color:var(--line)]">
<div className="h-1.5 w-20 overflow-hidden rounded-full bg-[color:var(--border)]">
<div
className={`h-full rounded-full transition-all ${overBudget ? "bg-[color:var(--danger)]" : "bg-[color:var(--success)]"}`}
className={`h-full rounded-full transition-all ${overBudget ? "bg-destructive" : "bg-green-600 dark:bg-green-400"}`}
style={{ width: `${pct}%` }}
/>
</div>
<span className={`text-[11px] ${overBudget ? "text-[color:var(--danger)]" : "text-[color:var(--muted)]"}`}>
<span className={`text-[11px] ${overBudget ? "text-destructive" : "text-muted-foreground"}`}>
{formatMoney(spent)} / {formatMoney(budget)}
</span>
</div>
@@ -31,8 +31,8 @@ export function ConfirmDelete({
onCancel: () => void;
}) {
return (
<div className="flex items-center gap-3 rounded-[8px] border border-[color:var(--danger)] bg-[color:var(--danger-soft)] px-4 py-3">
<span className="text-[13px] text-[color:var(--danger)]">Delete {entityLabel}?</span>
<div className="flex items-center gap-3 rounded-lg border border-[color:var(--destructive)] bg-red-100 dark:bg-red-900/50 px-4 py-3">
<span className="text-[13px] text-destructive">Delete {entityLabel}?</span>
<ActionButton label="Yes, delete" tone="danger" onClick={onConfirm} icon={Trash} />
<ActionButton label="Cancel" onClick={onCancel} icon={XCircle} />
</div>
@@ -63,10 +63,10 @@ export function HeartbeatSection({
onSaved: () => Promise<void>;
}) {
return (
<div className="rounded-lg border border-[color:var(--line)] p-3">
<div className="rounded-lg border border-border p-3">
<div className="mb-2 flex items-center gap-2">
<Heartbeat size={16} className="text-[color:var(--accent)]" />
<span className="text-[13px] font-semibold text-[color:var(--text)]">Continuous Execution</span>
<Heartbeat size={16} className="text-primary" />
<span className="text-[13px] font-semibold text-foreground">Continuous Execution</span>
</div>
<div className="mb-2 flex items-center gap-3">
<label className="flex cursor-pointer items-center gap-2">
@@ -80,12 +80,12 @@ export function HeartbeatSection({
await onSaved();
})()
}
className="h-4 w-4 rounded border-[color:var(--line)] accent-[color:var(--accent)]"
className="h-4 w-4 rounded border-border accent-[color:var(--primary)]"
/>
<span className="text-[13px] text-[color:var(--text)]">Enable heartbeat</span>
<span className="text-[13px] text-foreground">Enable heartbeat</span>
</label>
{agent.heartbeatEnabled && (
<span className="text-[11px] text-[color:var(--muted)]">
<span className="text-[11px] text-muted-foreground">
Every {agent.heartbeatIntervalSec}s{agent.lastHeartbeatAt ? ` · Last: ${formatTime(agent.lastHeartbeatAt)}` : ""}
</span>
)}
@@ -118,7 +118,7 @@ export function HeartbeatSection({
}
/>
{persistedConnectorIssue ? (
<p className="mt-2 text-[12px] text-[color:var(--warn)]">
<p className="mt-2 text-[12px] text-yellow-600 dark:text-yellow-400">
{persistedConnectorIssue} Save a ready connector before waking this agent again.
</p>
) : null}
@@ -86,13 +86,13 @@ export function collectEdges(nodes: LayoutNode[]): Array<{ parent: LayoutNode; c
}
export const statusDotColor: Record<string, string> = {
running: "var(--accent)",
active: "var(--success)",
paused: "var(--warn)",
idle: "var(--muted)",
error: "var(--danger)",
terminated: "var(--muted)",
pending_approval: "var(--warn)",
running: "var(--primary)",
active: "var(--primary)",
paused: "var(--destructive)",
idle: "var(--muted-foreground)",
error: "var(--destructive)",
terminated: "var(--muted-foreground)",
pending_approval: "var(--destructive)",
};
export const adapterLabels: Record<string, string> = {