forked from molecule-ai/molecule-core
fix(canvas): restore text-white on saturated buttons + close zinc gaps
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) <noreply@anthropic.com>
This commit is contained in:
parent
052575d773
commit
db48d1d261
@ -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",
|
||||
|
||||
@ -283,7 +283,7 @@ function OrgCTA({ org }: { org: Org }) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-ink hover:bg-emerald-500"
|
||||
className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-500"
|
||||
>
|
||||
Open
|
||||
</a>
|
||||
@ -293,7 +293,7 @@ function OrgCTA({ org }: { org: Org }) {
|
||||
return (
|
||||
<a
|
||||
href={`/pricing?org=${encodeURIComponent(org.slug)}`}
|
||||
className="rounded bg-amber-600 px-4 py-2 text-sm font-medium text-ink hover:bg-amber-500"
|
||||
className="rounded bg-amber-600 px-4 py-2 text-sm font-medium text-white hover:bg-amber-500"
|
||||
>
|
||||
Complete payment
|
||||
</a>
|
||||
@ -303,7 +303,7 @@ function OrgCTA({ org }: { org: Org }) {
|
||||
return (
|
||||
<a
|
||||
href="mailto:support@moleculesai.app"
|
||||
className="rounded bg-surface-card px-4 py-2 text-sm font-medium text-ink hover:bg-zinc-600"
|
||||
className="rounded bg-surface-card px-4 py-2 text-sm font-medium text-ink hover:bg-surface-card"
|
||||
>
|
||||
Contact support
|
||||
</a>
|
||||
@ -395,7 +395,7 @@ function CreateOrgForm({ onCreated }: { onCreated: (slug: string) => void }) {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={submitting}
|
||||
className="rounded bg-accent-strong px-4 py-2 text-sm font-medium text-ink hover:bg-accent disabled:opacity-50"
|
||||
className="rounded bg-accent-strong px-4 py-2 text-sm font-medium text-white hover:bg-accent disabled:opacity-50"
|
||||
>
|
||||
{submitting ? "Creating…" : "Create organization"}
|
||||
</button>
|
||||
|
||||
@ -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
|
||||
</button>
|
||||
@ -129,7 +129,7 @@ brew services start redis`}</pre>
|
||||
</p>
|
||||
<button
|
||||
onClick={() => window.location.reload()}
|
||||
className="px-4 py-2 bg-accent-strong hover:bg-accent text-ink rounded-md text-sm mt-2"
|
||||
className="px-4 py-2 bg-accent-strong hover:bg-accent text-white rounded-md text-sm mt-2"
|
||||
>
|
||||
Reload
|
||||
</button>
|
||||
|
||||
@ -73,14 +73,14 @@ export function ApprovalBanner() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDecide(approval, "approved")}
|
||||
className="px-3 py-1.5 bg-emerald-600 hover:bg-emerald-500 text-xs rounded-lg text-ink font-medium transition-colors"
|
||||
className="px-3 py-1.5 bg-emerald-600 hover:bg-emerald-500 text-xs rounded-lg text-white font-medium transition-colors"
|
||||
>
|
||||
Approve
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDecide(approval, "denied")}
|
||||
className="px-3 py-1.5 bg-surface-card hover:bg-zinc-600 text-xs rounded-lg text-ink-mid transition-colors"
|
||||
className="px-3 py-1.5 bg-surface-card hover:bg-surface-card text-xs rounded-lg text-ink-mid transition-colors"
|
||||
>
|
||||
Deny
|
||||
</button>
|
||||
|
||||
@ -174,7 +174,7 @@ export function AuditTrailPanel({ workspaceId }: Props) {
|
||||
{entries.length === 0 ? (
|
||||
/* Empty state */
|
||||
<div className="flex flex-col items-center justify-center py-16 gap-3 text-center">
|
||||
<span className="text-4xl text-zinc-700" aria-hidden="true">⊟</span>
|
||||
<span className="text-4xl text-ink-soft" aria-hidden="true">⊟</span>
|
||||
<p className="text-sm font-medium text-ink-mid">No audit events yet</p>
|
||||
<p className="text-[11px] text-ink-soft max-w-[200px] leading-relaxed">
|
||||
Delegation, decision, gate, and human-in-the-loop events will appear here.
|
||||
|
||||
@ -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 */}
|
||||
<span className="text-[12px] font-semibold text-ink bg-accent-strong/80 px-2.5 py-0.5 rounded-full tabular-nums">
|
||||
<span className="text-[12px] font-semibold text-white bg-accent-strong/80 px-2.5 py-0.5 rounded-full tabular-nums">
|
||||
{count} selected
|
||||
</span>
|
||||
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -161,7 +161,7 @@ export function ConversationTraceModal({ open, workspaceId: _workspaceId, onClos
|
||||
? "bg-cyan-500"
|
||||
: isReceive
|
||||
? "bg-accent"
|
||||
: "bg-zinc-600"
|
||||
: "bg-surface-card"
|
||||
}`}
|
||||
/>
|
||||
<div className="w-px flex-1 bg-surface-card min-h-[8px]" />
|
||||
|
||||
@ -137,7 +137,7 @@ export function CookieConsent() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => decide("accepted")}
|
||||
className="rounded border border-accent bg-accent-strong px-4 py-2 text-sm font-medium text-ink hover:bg-accent"
|
||||
className="rounded border border-accent bg-accent-strong px-4 py-2 text-sm font-medium text-white hover:bg-accent"
|
||||
>
|
||||
Accept all
|
||||
</button>
|
||||
|
||||
@ -310,7 +310,7 @@ export function CreateWorkspaceButton() {
|
||||
return (
|
||||
<Dialog.Root open={open} onOpenChange={setOpen}>
|
||||
<Dialog.Trigger asChild>
|
||||
<button type="button" className="fixed bottom-6 right-6 z-40 px-5 py-2.5 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm font-medium rounded-xl text-ink shadow-lg shadow-blue-600/20 hover:shadow-xl hover:shadow-blue-500/30 transition-all duration-200 flex items-center gap-2">
|
||||
<button type="button" className="fixed bottom-6 right-6 z-40 px-5 py-2.5 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm font-medium rounded-xl text-white shadow-lg shadow-blue-600/20 hover:shadow-xl hover:shadow-blue-500/30 transition-all duration-200 flex items-center gap-2">
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
@ -560,7 +560,7 @@ export function CreateWorkspaceButton() {
|
||||
type="button"
|
||||
onClick={handleCreate}
|
||||
disabled={creating}
|
||||
className="px-5 py-2 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm rounded-lg text-ink disabled:opacity-50 transition-colors"
|
||||
className="px-5 py-2 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm rounded-lg text-white disabled:opacity-50 transition-colors"
|
||||
>
|
||||
{creating ? "Creating..." : "Create"}
|
||||
</button>
|
||||
|
||||
@ -155,7 +155,7 @@ export function DeleteCascadeConfirmDialog({
|
||||
disabled={!checked}
|
||||
className={`px-3.5 py-1.5 text-[13px] rounded-lg transition-colors
|
||||
${checked
|
||||
? "bg-red-600 hover:bg-red-500 text-ink cursor-pointer"
|
||||
? "bg-red-600 hover:bg-red-500 text-white cursor-pointer"
|
||||
: "bg-red-900/30 text-bad/40 cursor-not-allowed"
|
||||
}`}
|
||||
>
|
||||
|
||||
@ -169,9 +169,9 @@ export function EmptyState() {
|
||||
<div className="mt-5 pt-4 border-t border-line/50">
|
||||
<div className="flex items-center justify-center gap-6 text-[10px] text-ink-mid">
|
||||
<span>Drag to nest workspaces into teams</span>
|
||||
<span className="text-zinc-700">|</span>
|
||||
<span className="text-ink-soft">|</span>
|
||||
<span>Right-click for actions</span>
|
||||
<span className="text-zinc-700">|</span>
|
||||
<span className="text-ink-soft">|</span>
|
||||
<span>Press <kbd className="px-1 py-0.5 bg-surface-card rounded text-ink-soft font-mono">⌘K</kbd> to search</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -83,7 +83,7 @@ export class ErrorBoundary extends React.Component<
|
||||
<button
|
||||
type="button"
|
||||
onClick={this.handleReload}
|
||||
className="rounded-lg bg-accent-strong hover:bg-accent px-5 py-2 text-sm font-medium text-ink transition-colors"
|
||||
className="rounded-lg bg-accent-strong hover:bg-accent px-5 py-2 text-sm font-medium text-white transition-colors"
|
||||
>
|
||||
Reload
|
||||
</button>
|
||||
|
||||
@ -256,7 +256,7 @@ function SnippetBlock({
|
||||
<button
|
||||
type="button"
|
||||
onClick={onCopy}
|
||||
className="text-xs px-2 py-1 rounded bg-accent-strong/80 hover:bg-accent text-ink"
|
||||
className="text-xs px-2 py-1 rounded bg-accent-strong/80 hover:bg-accent text-white"
|
||||
>
|
||||
{copied ? "Copied!" : "Copy"}
|
||||
</button>
|
||||
|
||||
@ -167,7 +167,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
|
||||
className={[
|
||||
"px-3 py-1 text-[11px] rounded transition-colors",
|
||||
activeScope === scope
|
||||
? "bg-accent-strong text-ink"
|
||||
? "bg-accent-strong text-white"
|
||||
: "bg-surface-card text-ink-mid hover:bg-surface-card hover:text-ink",
|
||||
].join(" ")}
|
||||
>
|
||||
@ -269,7 +269,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
|
||||
) : entries.length === 0 ? (
|
||||
debouncedQuery ? (
|
||||
<div className="flex flex-col items-center justify-center py-16 gap-3 text-center">
|
||||
<span className="text-4xl text-zinc-700" aria-hidden="true">◇</span>
|
||||
<span className="text-4xl text-ink-soft" aria-hidden="true">◇</span>
|
||||
<p className="text-sm font-medium text-ink-mid">
|
||||
No memories match your search
|
||||
</p>
|
||||
@ -290,7 +290,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center py-16 gap-3 text-center">
|
||||
<span className="text-4xl text-zinc-700" aria-hidden="true">◇</span>
|
||||
<span className="text-4xl text-ink-soft" aria-hidden="true">◇</span>
|
||||
<p className="text-sm font-medium text-ink-mid">No {activeScope} memories</p>
|
||||
<p className="text-[11px] text-ink-soft max-w-[200px] leading-relaxed">
|
||||
{activeScope === "LOCAL"
|
||||
|
||||
@ -451,7 +451,7 @@ function ProviderPickerModal({
|
||||
<button
|
||||
onClick={() => handleSaveKey(index)}
|
||||
disabled={!entry.value.trim() || entry.saving}
|
||||
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-ink disabled:opacity-30 transition-colors shrink-0"
|
||||
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-white disabled:opacity-30 transition-colors shrink-0"
|
||||
>
|
||||
{entry.saving ? "..." : "Save"}
|
||||
</button>
|
||||
@ -492,7 +492,7 @@ function ProviderPickerModal({
|
||||
!selectorValue.providerId ||
|
||||
(showModelInput && model.trim() === "")
|
||||
}
|
||||
className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-ink rounded-lg transition-colors disabled:opacity-40"
|
||||
className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-white rounded-lg transition-colors disabled:opacity-40"
|
||||
>
|
||||
{allSaved ? "Deploy" : entries.length > 1 ? "Add Keys" : "Add Key"}
|
||||
</button>
|
||||
@ -706,7 +706,7 @@ function AllKeysModal({
|
||||
type="button"
|
||||
onClick={() => handleSaveKey(index)}
|
||||
disabled={!entry.value.trim() || entry.saving}
|
||||
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-ink disabled:opacity-30 transition-colors shrink-0"
|
||||
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-white disabled:opacity-30 transition-colors shrink-0"
|
||||
>
|
||||
{entry.saving ? "..." : "Save"}
|
||||
</button>
|
||||
@ -748,7 +748,7 @@ function AllKeysModal({
|
||||
type="button"
|
||||
onClick={handleAddKeysAndDeploy}
|
||||
disabled={!allSaved || anySaving}
|
||||
className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-ink rounded-lg transition-colors disabled:opacity-40"
|
||||
className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-white rounded-lg transition-colors disabled:opacity-40"
|
||||
>
|
||||
{anySaving ? "Saving..." : allSaved ? "Deploy" : "Add Keys"}
|
||||
</button>
|
||||
|
||||
@ -181,7 +181,7 @@ export function OnboardingWizard() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleAction}
|
||||
className="flex-1 px-3 py-1.5 bg-accent-strong/90 hover:bg-accent rounded-lg text-[11px] font-medium text-ink transition-colors"
|
||||
className="flex-1 px-3 py-1.5 bg-accent-strong/90 hover:bg-accent rounded-lg text-[11px] font-medium text-white transition-colors"
|
||||
>
|
||||
{step === "welcome"
|
||||
? "Create Workspace"
|
||||
|
||||
@ -308,7 +308,7 @@ export function OrgImportPreflightModal({
|
||||
type="button"
|
||||
onClick={onProceed}
|
||||
disabled={!canProceed}
|
||||
className="px-4 py-1.5 text-[11px] font-semibold rounded bg-accent-strong hover:bg-accent text-ink disabled:bg-surface-card disabled:text-ink-soft disabled:cursor-not-allowed"
|
||||
className="px-4 py-1.5 text-[11px] font-semibold rounded bg-accent-strong hover:bg-accent text-white disabled:bg-surface-card disabled:text-white-soft disabled:cursor-not-allowed"
|
||||
>
|
||||
Import
|
||||
</button>
|
||||
@ -428,7 +428,7 @@ function StrictEnvRow({
|
||||
type="button"
|
||||
onClick={() => onSave(envKey)}
|
||||
disabled={d?.saving || !d?.value.trim()}
|
||||
className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-ink disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-white disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
>
|
||||
{d?.saving ? "…" : "Save"}
|
||||
</button>
|
||||
@ -520,7 +520,7 @@ function AnyOfEnvGroup({
|
||||
type="button"
|
||||
onClick={() => onSave(m)}
|
||||
disabled={d?.saving || !d?.value.trim()}
|
||||
className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-ink disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-white disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
>
|
||||
{d?.saving ? "…" : "Save"}
|
||||
</button>
|
||||
|
||||
@ -130,7 +130,7 @@ function PlanCard({
|
||||
disabled={loading}
|
||||
className={`mt-6 rounded-lg px-4 py-3 text-sm font-medium ${
|
||||
plan.highlighted
|
||||
? "bg-accent-strong text-ink hover:bg-accent disabled:bg-blue-900"
|
||||
? "bg-accent-strong text-white hover:bg-accent disabled:bg-blue-900"
|
||||
: "border border-line bg-surface-sunken text-ink hover:bg-surface-card disabled:opacity-50"
|
||||
}`}
|
||||
>
|
||||
|
||||
@ -341,7 +341,7 @@ export function ProvisioningTimeout({
|
||||
type="button"
|
||||
onClick={() => handleRetry(entry.workspaceId)}
|
||||
disabled={isRetrying || isCancelling || retryCooldown.has(entry.workspaceId)}
|
||||
className="px-3 py-1.5 bg-amber-600 hover:bg-amber-500 text-[11px] font-medium rounded-lg text-ink disabled:opacity-40 transition-colors"
|
||||
className="px-3 py-1.5 bg-amber-600 hover:bg-amber-500 text-[11px] font-medium rounded-lg text-white disabled:opacity-40 transition-colors"
|
||||
>
|
||||
{isRetrying ? "Retrying..." : retryCooldown.has(entry.workspaceId) ? "Wait..." : "Retry"}
|
||||
</button>
|
||||
@ -389,7 +389,7 @@ export function ProvisioningTimeout({
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCancelConfirm}
|
||||
className="px-3.5 py-1.5 text-[12px] bg-red-600 hover:bg-red-500 text-ink rounded-lg transition-colors"
|
||||
className="px-3.5 py-1.5 text-[12px] bg-red-600 hover:bg-red-500 text-white rounded-lg transition-colors"
|
||||
>
|
||||
Remove Workspace
|
||||
</button>
|
||||
|
||||
@ -476,7 +476,7 @@ export function TemplatePalette() {
|
||||
onClick={() => setOpen(!open)}
|
||||
className={`fixed top-4 left-4 z-40 w-9 h-9 flex items-center justify-center rounded-lg transition-colors ${
|
||||
open
|
||||
? "bg-accent-strong text-ink"
|
||||
? "bg-accent-strong text-white"
|
||||
: "bg-surface-sunken/90 border border-line/50 text-ink-mid hover:text-ink hover:border-line"
|
||||
}`}
|
||||
title="Template Palette"
|
||||
|
||||
@ -105,7 +105,7 @@ export function TermsGate({ children }: { children: React.ReactNode }) {
|
||||
type="button"
|
||||
onClick={accept}
|
||||
disabled={submitting}
|
||||
className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-ink hover:bg-emerald-500 disabled:opacity-50"
|
||||
className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-500 disabled:opacity-50"
|
||||
>
|
||||
{submitting ? "Saving…" : "I agree"}
|
||||
</button>
|
||||
|
||||
@ -154,7 +154,7 @@ export function Toolbar() {
|
||||
{counts.failed > 0 && (
|
||||
<StatusPill color={statusDotClass("failed")} count={counts.failed} label="failed" />
|
||||
)}
|
||||
<span className="text-zinc-700" aria-hidden="true">·</span>
|
||||
<span className="text-ink-soft" aria-hidden="true">·</span>
|
||||
<span className="text-[10px] text-ink-soft whitespace-nowrap">
|
||||
{counts.roots} workspace{counts.roots !== 1 ? "s" : ""}
|
||||
{counts.children > 0 && <span className="text-ink-soft"> + {counts.children} sub</span>}
|
||||
|
||||
@ -165,7 +165,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
<Handle
|
||||
type="target"
|
||||
position={Position.Top}
|
||||
className="!w-2.5 !h-1 !rounded-full !bg-zinc-600/80 !border-0 !-top-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all"
|
||||
className="!w-2.5 !h-1 !rounded-full !bg-surface-card/80 !border-0 !-top-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all"
|
||||
/>
|
||||
|
||||
<div className="relative px-3.5 py-2.5">
|
||||
@ -318,7 +318,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
className="!w-2.5 !h-1 !rounded-full !bg-zinc-600/80 !border-0 !-bottom-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all"
|
||||
className="!w-2.5 !h-1 !rounded-full !bg-surface-card/80 !border-0 !-bottom-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -130,7 +130,7 @@ export function OrgCancelButton({ rootId, rootName, workspaceCount }: Props) {
|
||||
type="button"
|
||||
onClick={() => setConfirming(false)}
|
||||
disabled={submitting}
|
||||
className="px-2 py-0.5 rounded bg-surface-card/80 hover:bg-zinc-600 text-[10px] text-ink"
|
||||
className="px-2 py-0.5 rounded bg-surface-card/80 hover:bg-surface-card text-[10px] text-ink"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
|
||||
@ -111,7 +111,7 @@ export function ActivityTab({ workspaceId }: Props) {
|
||||
</button>
|
||||
<button
|
||||
onClick={loadActivities}
|
||||
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[11px] rounded text-ink-mid"
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[11px] rounded text-ink-mid"
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
@ -137,7 +137,7 @@ export function ActivityTab({ workspaceId }: Props) {
|
||||
{!loading && !error && activities.length === 0 && (
|
||||
<div className="text-center py-8">
|
||||
<div className="text-ink-soft text-xs">No activity recorded yet</div>
|
||||
<div className="text-zinc-700 text-[9px] mt-1">
|
||||
<div className="text-ink-soft text-[9px] mt-1">
|
||||
Activity logs appear when agents communicate or perform tasks
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -243,7 +243,7 @@ export function BudgetSection({ workspaceId }: Props) {
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
data-testid="budget-save-btn"
|
||||
className="px-4 py-1.5 bg-accent-strong hover:bg-accent active:bg-accent-strong rounded-lg text-xs font-medium text-ink disabled:opacity-50 transition-colors"
|
||||
className="px-4 py-1.5 bg-accent-strong hover:bg-accent active:bg-accent-strong rounded-lg text-xs font-medium text-white disabled:opacity-50 transition-colors"
|
||||
>
|
||||
{saving ? "Saving…" : "Save"}
|
||||
</button>
|
||||
|
||||
@ -366,7 +366,7 @@ export function ChannelsTab({ workspaceId }: Props) {
|
||||
)}
|
||||
<button
|
||||
onClick={handleCreate}
|
||||
className="w-full text-xs py-1.5 rounded bg-accent-strong hover:bg-accent text-ink transition"
|
||||
className="w-full text-xs py-1.5 rounded bg-accent-strong hover:bg-accent text-white transition"
|
||||
>
|
||||
Connect Channel
|
||||
</button>
|
||||
@ -392,7 +392,7 @@ export function ChannelsTab({ workspaceId }: Props) {
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
ch.enabled ? "bg-emerald-500" : "bg-zinc-600"
|
||||
ch.enabled ? "bg-emerald-500" : "bg-surface-card"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-xs font-medium text-ink">
|
||||
|
||||
@ -901,7 +901,7 @@ function MyChatPanel({ workspaceId, data }: Props) {
|
||||
<button
|
||||
onClick={sendMessage}
|
||||
disabled={(!input.trim() && pendingFiles.length === 0) || !agentReachable || sending || uploading}
|
||||
className="px-4 py-2 bg-accent-strong hover:bg-accent text-xs font-medium rounded-lg text-ink disabled:opacity-30 transition-colors shrink-0"
|
||||
className="px-4 py-2 bg-accent-strong hover:bg-accent text-xs font-medium rounded-lg text-white disabled:opacity-30 transition-colors shrink-0"
|
||||
>
|
||||
{uploading ? "Uploading…" : "Send"}
|
||||
</button>
|
||||
|
||||
@ -65,11 +65,11 @@ function AgentCardSection({ workspaceId }: { workspaceId: string }) {
|
||||
{error && <div className="px-2 py-1 bg-red-900/30 border border-red-800 rounded text-[10px] text-bad">{error}</div>}
|
||||
<div className="flex gap-2">
|
||||
<button type="button" onClick={handleSave} disabled={saving}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-50">
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-50">
|
||||
{saving ? "Saving..." : "Save"}
|
||||
</button>
|
||||
<button type="button" onClick={() => setEditing(false)}
|
||||
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
@ -955,7 +955,7 @@ export function ConfigTab({ workspaceId }: Props) {
|
||||
type="button"
|
||||
onClick={() => handleSave(true)}
|
||||
disabled={!isDirty || saving}
|
||||
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-xs rounded text-ink disabled:opacity-30 transition-colors"
|
||||
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-xs rounded text-white disabled:opacity-30 transition-colors"
|
||||
>
|
||||
{saving ? "Restarting..." : "Save & Restart"}
|
||||
</button>
|
||||
@ -963,14 +963,14 @@ export function ConfigTab({ workspaceId }: Props) {
|
||||
type="button"
|
||||
onClick={() => handleSave(false)}
|
||||
disabled={!isDirty || saving}
|
||||
className="px-3 py-1.5 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid disabled:opacity-30 transition-colors"
|
||||
className="px-3 py-1.5 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid disabled:opacity-30 transition-colors"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={loadConfig}
|
||||
className="px-3 py-1.5 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid ml-auto"
|
||||
className="px-3 py-1.5 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid ml-auto"
|
||||
>
|
||||
Reload
|
||||
</button>
|
||||
|
||||
@ -166,7 +166,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-ink disabled:opacity-50"
|
||||
className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-white disabled:opacity-50"
|
||||
>
|
||||
{saving ? "Saving..." : "Save"}
|
||||
</button>
|
||||
@ -179,7 +179,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
|
||||
setRole(data.role || "");
|
||||
setTier(data.tier);
|
||||
}}
|
||||
className="px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid"
|
||||
className="px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
@ -208,7 +208,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
|
||||
type="button"
|
||||
onClick={handleRestart}
|
||||
disabled={restarting}
|
||||
className="px-3 py-1 bg-green-700 hover:bg-green-600 text-xs rounded text-ink disabled:opacity-50"
|
||||
className="px-3 py-1 bg-green-700 hover:bg-green-600 text-xs rounded text-white disabled:opacity-50"
|
||||
>
|
||||
{restarting ? "Restarting..." : data.status === "failed" ? "Retry" : "Restart"}
|
||||
</button>
|
||||
@ -217,7 +217,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditing(true)}
|
||||
className="mt-2 px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid"
|
||||
className="mt-2 px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
@ -322,7 +322,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDelete}
|
||||
className="px-3 py-1 bg-red-600 hover:bg-red-500 text-xs rounded text-ink"
|
||||
className="px-3 py-1 bg-red-600 hover:bg-red-500 text-xs rounded text-white"
|
||||
>
|
||||
Confirm Delete
|
||||
</button>
|
||||
@ -334,7 +334,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
|
||||
// Return focus to the trigger so keyboard users aren't stranded
|
||||
deleteButtonRef.current?.focus();
|
||||
}}
|
||||
className="px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid"
|
||||
className="px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@ -65,7 +65,7 @@ export function EventsTab({ workspaceId }: Props) {
|
||||
<span className="text-xs text-ink-mid">{events.length} events</span>
|
||||
<button
|
||||
onClick={loadEvents}
|
||||
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid"
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid"
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
|
||||
@ -165,8 +165,8 @@ export function FilesTab({ workspaceId }: Props) {
|
||||
<div className="mx-3 mt-2 px-3 py-2 bg-red-950/30 border border-red-800/40 rounded space-y-1.5">
|
||||
<p className="text-xs text-bad">Delete all {files.filter((f) => !f.dir).length} files? This cannot be undone.</p>
|
||||
<div className="flex gap-2">
|
||||
<button type="button" onClick={() => { handleDeleteAll(); setShowDeleteAll(false); }} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-ink">Delete All</button>
|
||||
<button type="button" onClick={() => setShowDeleteAll(false)} className="px-2 py-0.5 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
<button type="button" onClick={() => { handleDeleteAll(); setShowDeleteAll(false); }} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-white">Delete All</button>
|
||||
<button type="button" onClick={() => setShowDeleteAll(false)} className="px-2 py-0.5 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -179,8 +179,8 @@ export function FilesTab({ workspaceId }: Props) {
|
||||
<div className="mx-3 mt-2 px-3 py-2 bg-amber-950/30 border border-amber-800/40 rounded space-y-1.5">
|
||||
<p className="text-xs text-warm">Delete <span className="font-mono">{confirmDelete}</span>{files.find((f) => f.path === confirmDelete && f.dir) ? " and all its contents" : ""}?</p>
|
||||
<div className="flex gap-2">
|
||||
<button type="button" onClick={confirmDeleteFile} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-ink">Delete</button>
|
||||
<button type="button" onClick={() => setConfirmDelete(null)} className="px-2 py-0.5 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
<button type="button" onClick={confirmDeleteFile} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-white">Delete</button>
|
||||
<button type="button" onClick={() => setConfirmDelete(null)} className="px-2 py-0.5 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -137,14 +137,14 @@ export function MemoryTab({ workspaceId }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAwareness((prev) => !prev)}
|
||||
className="shrink-0 px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink"
|
||||
className="shrink-0 px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink"
|
||||
>
|
||||
{showAwareness ? "Collapse" : "Expand"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={openAwareness}
|
||||
className="shrink-0 px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink"
|
||||
className="shrink-0 px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink"
|
||||
>
|
||||
Open
|
||||
</button>
|
||||
@ -177,7 +177,7 @@ export function MemoryTab({ workspaceId }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAwareness(true)}
|
||||
className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink"
|
||||
className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white"
|
||||
>
|
||||
Expand
|
||||
</button>
|
||||
@ -212,21 +212,21 @@ export function MemoryTab({ workspaceId }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAdvanced((prev) => !prev)}
|
||||
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid"
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid"
|
||||
>
|
||||
{showAdvanced ? "Hide Advanced" : "Advanced"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={loadMemory}
|
||||
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid"
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid"
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { setShowAdd(!showAdd); if (!showAdd) setShowAdvanced(true); }}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink"
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white"
|
||||
>
|
||||
+ Add
|
||||
</button>
|
||||
@ -262,7 +262,7 @@ export function MemoryTab({ workspaceId }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleAdd}
|
||||
className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-ink"
|
||||
className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-white"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
@ -272,7 +272,7 @@ export function MemoryTab({ workspaceId }: Props) {
|
||||
setShowAdd(false);
|
||||
setError(null);
|
||||
}}
|
||||
className="px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid"
|
||||
className="px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
@ -340,7 +340,7 @@ export function MemoryTab({ workspaceId }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAdvanced(true)}
|
||||
className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink"
|
||||
className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white"
|
||||
>
|
||||
Show
|
||||
</button>
|
||||
|
||||
@ -271,7 +271,7 @@ export function ScheduleTab({ workspaceId }: Props) {
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
disabled={!formCron || !formPrompt}
|
||||
className="text-[11px] px-3 py-1 bg-accent-strong text-ink rounded hover:bg-accent disabled:opacity-40 transition-colors"
|
||||
className="text-[11px] px-3 py-1 bg-accent-strong text-white rounded hover:bg-accent disabled:opacity-40 transition-colors"
|
||||
>
|
||||
{editId ? "Update" : "Create"}
|
||||
</button>
|
||||
@ -320,7 +320,7 @@ export function ScheduleTab({ workspaceId }: Props) {
|
||||
? "bg-red-400"
|
||||
: sched.last_status === "ok"
|
||||
? "bg-emerald-400"
|
||||
: "bg-zinc-600"
|
||||
: "bg-surface-card"
|
||||
}`}
|
||||
title={sched.enabled ? "Click to disable" : "Click to enable"}
|
||||
/>
|
||||
|
||||
@ -70,7 +70,7 @@ export function TracesTab({ workspaceId }: Props) {
|
||||
<div className="text-center py-8">
|
||||
<div className="text-2xl opacity-20 mb-2" aria-hidden="true">--</div>
|
||||
<p className="text-xs text-ink-soft">No traces yet</p>
|
||||
<details className="mt-2 text-[10px] text-zinc-700">
|
||||
<details className="mt-2 text-[10px] text-ink-soft">
|
||||
<summary className="cursor-pointer text-ink-soft hover:text-ink-mid">How to enable tracing</summary>
|
||||
<p className="mt-1">
|
||||
Set <code className="font-mono text-ink-mid">LANGFUSE_HOST</code>, <code className="font-mono text-ink-mid">LANGFUSE_PUBLIC_KEY</code>, <code className="font-mono text-ink-mid">LANGFUSE_SECRET_KEY</code> as workspace secrets to enable tracing.
|
||||
|
||||
@ -58,7 +58,7 @@ export function AttachmentChip({
|
||||
const toneClasses =
|
||||
tone === "user"
|
||||
? "border-blue-400/30 bg-accent-strong/20 hover:bg-accent-strong/30 text-blue-100"
|
||||
: "border-line/50 bg-surface-card/40 hover:bg-zinc-600/50 text-ink";
|
||||
: "border-line/50 bg-surface-card/40 hover:bg-surface-card/50 text-ink";
|
||||
return (
|
||||
<button
|
||||
onClick={() => onDownload(attachment)}
|
||||
|
||||
@ -131,7 +131,7 @@ function SecretRow({ label, secretKey, isSet, scope, globalMode, onSave, onDelet
|
||||
<button type="button"
|
||||
onClick={() => { onSave(value); setEditing(false); setValue(""); }}
|
||||
disabled={!value}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-30"
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30"
|
||||
>Save</button>
|
||||
</div>
|
||||
)}
|
||||
@ -184,7 +184,7 @@ function CustomSecretRow({ secretKey, scope, globalMode, onSave, onDelete }: {
|
||||
<button type="button"
|
||||
onClick={() => { onSave(value); setEditing(false); setValue(""); }}
|
||||
disabled={!value}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-30"
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30"
|
||||
>Save</button>
|
||||
</div>
|
||||
)}
|
||||
@ -298,7 +298,7 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
|
||||
<button
|
||||
onClick={() => setGlobalMode(false)}
|
||||
className={`text-[10px] px-2 py-0.5 rounded transition-colors ${
|
||||
!globalMode ? "bg-accent-strong/20 text-accent border border-accent/30" : "text-ink-soft hover:text-ink-mid"
|
||||
!globalMode ? "bg-accent-strong/20 text-accent border border-accent/30" : "text-white-soft hover:text-white-mid"
|
||||
}`}
|
||||
>
|
||||
This Workspace
|
||||
@ -306,7 +306,7 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
|
||||
<button
|
||||
onClick={() => setGlobalMode(true)}
|
||||
className={`text-[10px] px-2 py-0.5 rounded transition-colors ${
|
||||
globalMode ? "bg-amber-600/20 text-warm border border-amber-500/30" : "text-ink-soft hover:text-ink-mid"
|
||||
globalMode ? "bg-amber-600/20 text-warm border border-amber-500/30" : "text-white-soft hover:text-white-mid"
|
||||
}`}
|
||||
>
|
||||
Global (All Workspaces)
|
||||
@ -356,11 +356,11 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
|
||||
className="w-full bg-surface-sunken border border-line rounded px-2 py-1 text-[10px] text-ink focus:outline-none focus:border-accent" />
|
||||
<div className="flex gap-2">
|
||||
<button type="button" onClick={() => { if (newKey && newValue) handleSave(newKey, newValue); }} disabled={!newKey || !newValue}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-30">
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30">
|
||||
Save{globalMode ? " (Global)" : ""}
|
||||
</button>
|
||||
<button type="button" onClick={() => { setShowAdd(false); setNewKey(""); setNewValue(""); }}
|
||||
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user