From db48d1d26190429b562f2da344980a5c90154c9c Mon Sep 17 00:00:00 2001
From: Hongming Wang
Date: Sun, 3 May 2026 02:04:20 -0700
Subject: [PATCH] fix(canvas): restore text-white on saturated buttons + close
zinc gaps
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Independent code review of #2555 caught two contrast regressions left
by the bulk perl pass:
1. text-white → text-ink mass-substitution silently broke destructive
and primary buttons. text-ink resolves to #15181c (warm-paper
near-black) in light mode — dark text on bg-red-600 / bg-amber-600
/ bg-emerald-600 / bg-blue-600 / bg-accent / bg-accent-strong /
bg-good / bg-bad fails WCAG contrast and looks broken. Per-line
pass flips text-ink → text-white only when a saturated bg utility
is present; tinted-state pills (bg-red-950/50 etc.) keep their
intentionally-retained text-* literals.
2. Original mapping table was missing bg-zinc-600 (most-used
hover-state literal for cancel buttons — caused them to JUMP from
warm cream resting state to dark zinc on hover in light mode) and
text-zinc-700/800/900 (separator dots and decorative dim text
invisible on warm-paper light bg). Extended mapping fills these
gaps with bg-surface-card / text-ink-soft.
Also: drop stale tailwind.config.ts reference from components.json
(file deleted by the v3→v4 migration); switch baseColor zinc →
neutral and enable cssVariables since v4 uses CSS-driven tokens.
Future shadcn-cli invocations would have failed or written malformed
components without this.
27 sites in 27 files affected by #1, ~20 sites in 20 files by #2.
1214/1214 unit tests still pass; build still clean.
Findings courtesy of multi-model review per code-review-and-quality
skill — different blind spots catch different bugs.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
canvas/components.json | 5 ++---
canvas/src/app/orgs/page.tsx | 8 ++++----
canvas/src/app/page.tsx | 4 ++--
canvas/src/components/ApprovalBanner.tsx | 4 ++--
canvas/src/components/AuditTrailPanel.tsx | 2 +-
canvas/src/components/BatchActionBar.tsx | 2 +-
canvas/src/components/ConfirmDialog.tsx | 6 +++---
.../src/components/ConversationTraceModal.tsx | 2 +-
canvas/src/components/CookieConsent.tsx | 2 +-
.../src/components/CreateWorkspaceDialog.tsx | 4 ++--
.../components/DeleteCascadeConfirmDialog.tsx | 2 +-
canvas/src/components/EmptyState.tsx | 4 ++--
canvas/src/components/ErrorBoundary.tsx | 2 +-
canvas/src/components/ExternalConnectModal.tsx | 2 +-
canvas/src/components/MemoryInspectorPanel.tsx | 6 +++---
canvas/src/components/MissingKeysModal.tsx | 8 ++++----
canvas/src/components/OnboardingWizard.tsx | 2 +-
.../src/components/OrgImportPreflightModal.tsx | 6 +++---
canvas/src/components/PricingTable.tsx | 2 +-
canvas/src/components/ProvisioningTimeout.tsx | 4 ++--
canvas/src/components/TemplatePalette.tsx | 2 +-
canvas/src/components/TermsGate.tsx | 2 +-
canvas/src/components/Toolbar.tsx | 2 +-
canvas/src/components/WorkspaceNode.tsx | 4 ++--
.../src/components/canvas/OrgCancelButton.tsx | 2 +-
canvas/src/components/tabs/ActivityTab.tsx | 4 ++--
canvas/src/components/tabs/BudgetSection.tsx | 2 +-
canvas/src/components/tabs/ChannelsTab.tsx | 4 ++--
canvas/src/components/tabs/ChatTab.tsx | 2 +-
canvas/src/components/tabs/ConfigTab.tsx | 10 +++++-----
canvas/src/components/tabs/DetailsTab.tsx | 12 ++++++------
canvas/src/components/tabs/EventsTab.tsx | 2 +-
canvas/src/components/tabs/FilesTab.tsx | 8 ++++----
canvas/src/components/tabs/MemoryTab.tsx | 18 +++++++++---------
canvas/src/components/tabs/ScheduleTab.tsx | 4 ++--
canvas/src/components/tabs/TracesTab.tsx | 2 +-
.../components/tabs/chat/AttachmentViews.tsx | 2 +-
.../components/tabs/config/secrets-section.tsx | 12 ++++++------
38 files changed, 85 insertions(+), 86 deletions(-)
diff --git a/canvas/components.json b/canvas/components.json
index 8f8b0f3f..0b0911e0 100644
--- a/canvas/components.json
+++ b/canvas/components.json
@@ -4,10 +4,9 @@
"rsc": true,
"tsx": true,
"tailwind": {
- "config": "tailwind.config.ts",
"css": "src/app/globals.css",
- "baseColor": "zinc",
- "cssVariables": false
+ "baseColor": "neutral",
+ "cssVariables": true
},
"aliases": {
"components": "@/components",
diff --git a/canvas/src/app/orgs/page.tsx b/canvas/src/app/orgs/page.tsx
index 48bb7128..3c5576ef 100644
--- a/canvas/src/app/orgs/page.tsx
+++ b/canvas/src/app/orgs/page.tsx
@@ -283,7 +283,7 @@ function OrgCTA({ org }: { org: Org }) {
return (
Open
@@ -293,7 +293,7 @@ function OrgCTA({ org }: { org: Org }) {
return (
Complete payment
@@ -303,7 +303,7 @@ function OrgCTA({ org }: { org: Org }) {
return (
Contact support
@@ -395,7 +395,7 @@ function CreateOrgForm({ onCreated }: { onCreated: (slug: string) => void }) {
diff --git a/canvas/src/app/page.tsx b/canvas/src/app/page.tsx
index e3759b71..137cd623 100644
--- a/canvas/src/app/page.tsx
+++ b/canvas/src/app/page.tsx
@@ -87,7 +87,7 @@ export default function Home() {
setHydrationError(null);
window.location.reload();
}}
- className="px-4 py-2 bg-accent-strong hover:bg-accent text-ink rounded-md text-sm"
+ className="px-4 py-2 bg-accent-strong hover:bg-accent text-white rounded-md text-sm"
>
Retry
@@ -129,7 +129,7 @@ brew services start redis`}
-
⊟
+
⊟
No audit events yet
Delegation, decision, gate, and human-in-the-loop events will appear here.
diff --git a/canvas/src/components/BatchActionBar.tsx b/canvas/src/components/BatchActionBar.tsx
index d4c4a540..004b3205 100644
--- a/canvas/src/components/BatchActionBar.tsx
+++ b/canvas/src/components/BatchActionBar.tsx
@@ -83,7 +83,7 @@ export function BatchActionBar() {
className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[200] flex items-center gap-3 px-4 py-2.5 rounded-2xl bg-surface-sunken/95 border border-line/70 shadow-2xl shadow-black/50 backdrop-blur-md"
>
{/* Selection count badge */}
-
+
{count} selected
diff --git a/canvas/src/components/ConfirmDialog.tsx b/canvas/src/components/ConfirmDialog.tsx
index 773f2709..93961db4 100644
--- a/canvas/src/components/ConfirmDialog.tsx
+++ b/canvas/src/components/ConfirmDialog.tsx
@@ -93,10 +93,10 @@ export function ConfirmDialog({
const confirmColors =
confirmVariant === "danger"
- ? "bg-red-600 hover:bg-red-500 text-ink"
+ ? "bg-red-600 hover:bg-red-500 text-white"
: confirmVariant === "warning"
- ? "bg-amber-600 hover:bg-amber-500 text-ink"
- : "bg-accent-strong hover:bg-accent text-ink";
+ ? "bg-amber-600 hover:bg-amber-500 text-white"
+ : "bg-accent-strong hover:bg-accent text-white";
// Render via Portal so the fixed-position dialog escapes any containing block
// (e.g. parents with transform, filter, will-change that break position:fixed).
diff --git a/canvas/src/components/ConversationTraceModal.tsx b/canvas/src/components/ConversationTraceModal.tsx
index 378beda0..60d6e3ff 100644
--- a/canvas/src/components/ConversationTraceModal.tsx
+++ b/canvas/src/components/ConversationTraceModal.tsx
@@ -161,7 +161,7 @@ export function ConversationTraceModal({ open, workspaceId: _workspaceId, onClos
? "bg-cyan-500"
: isReceive
? "bg-accent"
- : "bg-zinc-600"
+ : "bg-surface-card"
}`}
/>
diff --git a/canvas/src/components/CookieConsent.tsx b/canvas/src/components/CookieConsent.tsx
index 8d6f7c74..6b607b04 100644
--- a/canvas/src/components/CookieConsent.tsx
+++ b/canvas/src/components/CookieConsent.tsx
@@ -137,7 +137,7 @@ export function CookieConsent() {
diff --git a/canvas/src/components/CreateWorkspaceDialog.tsx b/canvas/src/components/CreateWorkspaceDialog.tsx
index f4702127..b47e2564 100644
--- a/canvas/src/components/CreateWorkspaceDialog.tsx
+++ b/canvas/src/components/CreateWorkspaceDialog.tsx
@@ -310,7 +310,7 @@ export function CreateWorkspaceButton() {
return (
-