fix(canvas): raise minimum text size in Legend and WorkspaceNode to meet WCAG readability
UX Audit Run 6 critical finding: Legend panel and workspace node cards used 8px and 9px text (6–7pt), which is physically unreadable and fails WCAG minimum guidelines. - Legend.tsx: raise all text-[8px]/[9px]/[10px] → text-[11px] across every sub-component (StatusItem labels, TierItem badge+label, CommItem icon+label, section headers) - WorkspaceNode.tsx: raise text-[8px]/[9px] → text-[10px] for all readable labels in the main card (status text, skill badges, task/error banners, tier badge, sub count, Team Members header) and TeamMemberChip primary name/role text Compact 7px elements inside TeamMemberChip (tier/sub badges, status micropills) retained to preserve dense canvas layout — only human-readable labels were upgraded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
458ccec29e
commit
bc4c704d12
@ -3,11 +3,11 @@
|
||||
export function Legend() {
|
||||
return (
|
||||
<div className="fixed bottom-6 left-4 z-30 bg-zinc-900/95 border border-zinc-700/50 rounded-xl px-4 py-3 shadow-xl shadow-black/30 backdrop-blur-sm max-w-[280px]">
|
||||
<div className="text-[10px] font-semibold text-zinc-400 uppercase tracking-wider mb-2">Legend</div>
|
||||
<div className="text-[11px] font-semibold text-zinc-400 uppercase tracking-wider mb-2">Legend</div>
|
||||
|
||||
{/* Status */}
|
||||
<div className="mb-2">
|
||||
<div className="text-[9px] text-zinc-500 font-medium mb-1">Status</div>
|
||||
<div className="text-[11px] text-zinc-500 font-medium mb-1">Status</div>
|
||||
<div className="flex flex-wrap gap-x-3 gap-y-1">
|
||||
<StatusItem color="bg-emerald-400" label="Online" />
|
||||
<StatusItem color="bg-sky-400 animate-pulse" label="Starting" />
|
||||
@ -20,7 +20,7 @@ export function Legend() {
|
||||
|
||||
{/* Tiers */}
|
||||
<div className="mb-2">
|
||||
<div className="text-[9px] text-zinc-500 font-medium mb-1">Tier</div>
|
||||
<div className="text-[11px] text-zinc-500 font-medium mb-1">Tier</div>
|
||||
<div className="flex flex-wrap gap-x-3 gap-y-1">
|
||||
<TierItem tier={1} label="Sandboxed" color="text-sky-300 bg-sky-950/40 border-sky-700/30" />
|
||||
<TierItem tier={2} label="Standard" color="text-violet-300 bg-violet-950/40 border-violet-700/30" />
|
||||
@ -30,7 +30,7 @@ export function Legend() {
|
||||
|
||||
{/* Communication */}
|
||||
<div>
|
||||
<div className="text-[9px] text-zinc-500 font-medium mb-1">Communication</div>
|
||||
<div className="text-[11px] text-zinc-500 font-medium mb-1">Communication</div>
|
||||
<div className="flex flex-wrap gap-x-3 gap-y-1">
|
||||
<CommItem icon="↗" color="text-cyan-400" label="A2A Out" />
|
||||
<CommItem icon="↙" color="text-blue-400" label="A2A In" />
|
||||
@ -46,7 +46,7 @@ function StatusItem({ color, label }: { color: string; label: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<div className={`w-1.5 h-1.5 rounded-full ${color}`} />
|
||||
<span className="text-[8px] text-zinc-400">{label}</span>
|
||||
<span className="text-[11px] text-zinc-400">{label}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -54,8 +54,8 @@ function StatusItem({ color, label }: { color: string; label: string }) {
|
||||
function TierItem({ tier, label, color }: { tier: number; label: string; color: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<span className={`text-[8px] font-mono px-1 py-0.5 rounded border ${color}`}>T{tier}</span>
|
||||
<span className="text-[8px] text-zinc-400">{label}</span>
|
||||
<span className={`text-[11px] font-mono px-1 py-0.5 rounded border ${color}`}>T{tier}</span>
|
||||
<span className="text-[11px] text-zinc-400">{label}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -63,8 +63,8 @@ function TierItem({ tier, label, color }: { tier: number; label: string; color:
|
||||
function CommItem({ icon, color, label }: { icon: string; color: string; label: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<span className={`text-[9px] ${color}`}>{icon}</span>
|
||||
<span className="text-[8px] text-zinc-400">{label}</span>
|
||||
<span className={`text-[11px] ${color}`}>{icon}</span>
|
||||
<span className="text-[11px] text-zinc-400">{label}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -126,11 +126,11 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 shrink-0">
|
||||
{hasChildren && (
|
||||
<span className="text-[8px] font-mono text-violet-300 bg-violet-900/40 border border-violet-700/30 px-1.5 py-0.5 rounded-md">
|
||||
<span className="text-[10px] font-mono text-violet-300 bg-violet-900/40 border border-violet-700/30 px-1.5 py-0.5 rounded-md">
|
||||
{descendantCount} sub
|
||||
</span>
|
||||
)}
|
||||
<span className={`text-[9px] font-mono px-1.5 py-0.5 rounded-md ${tierCfg.color}`}>
|
||||
<span className={`text-[10px] font-mono px-1.5 py-0.5 rounded-md ${tierCfg.color}`}>
|
||||
{tierCfg.label}
|
||||
</span>
|
||||
</div>
|
||||
@ -179,7 +179,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
{skills.slice(0, 4).map((skill) => (
|
||||
<span
|
||||
key={skill}
|
||||
className={`text-[8px] px-1.5 py-0.5 rounded-md border ${
|
||||
className={`text-[10px] px-1.5 py-0.5 rounded-md border ${
|
||||
isOnline
|
||||
? "text-emerald-300/80 bg-emerald-950/30 border-emerald-800/30"
|
||||
: "text-zinc-400 bg-zinc-800/60 border-zinc-700/40"
|
||||
@ -189,7 +189,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
</span>
|
||||
))}
|
||||
{skills.length > 4 && (
|
||||
<span className="text-[8px] text-zinc-500 self-center">
|
||||
<span className="text-[10px] text-zinc-500 self-center">
|
||||
+{skills.length - 4}
|
||||
</span>
|
||||
)}
|
||||
@ -206,7 +206,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
<Tooltip text={String(data.currentTask)}>
|
||||
<div className="flex items-center gap-1.5 mt-1 bg-amber-950/20 px-2 py-1 rounded-md border border-amber-800/20 cursor-default">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-amber-400 animate-pulse shrink-0" />
|
||||
<span className="text-[8px] text-amber-300/80 truncate">{data.currentTask}</span>
|
||||
<span className="text-[10px] text-amber-300/80 truncate">{data.currentTask}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -220,15 +220,15 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
}}
|
||||
className="flex items-center gap-1.5 mt-1 w-full bg-sky-950/30 px-2 py-1 rounded-md border border-sky-800/30 hover:bg-sky-900/40 transition-colors text-left"
|
||||
>
|
||||
<span className="text-[8px]">↻</span>
|
||||
<span className="text-[8px] text-sky-300/80">Restart to apply changes</span>
|
||||
<span className="text-[10px]">↻</span>
|
||||
<span className="text-[10px] text-sky-300/80">Restart to apply changes</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Bottom row: status / active tasks */}
|
||||
<div className="flex items-center justify-between mt-0.5">
|
||||
{data.status !== "online" ? (
|
||||
<div className={`text-[8px] uppercase tracking-widest font-medium ${
|
||||
<div className={`text-[10px] uppercase tracking-widest font-medium ${
|
||||
data.status === "failed" ? "text-red-400" :
|
||||
data.status === "degraded" ? "text-amber-400" :
|
||||
data.status === "provisioning" ? "text-sky-400" :
|
||||
@ -241,7 +241,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
{data.activeTasks > 0 && (
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-1 h-1 rounded-full bg-amber-400 animate-pulse" />
|
||||
<span className="text-[8px] text-amber-300/80 tabular-nums">
|
||||
<span className="text-[10px] text-amber-300/80 tabular-nums">
|
||||
{data.activeTasks} task{data.activeTasks > 1 ? "s" : ""}
|
||||
</span>
|
||||
</div>
|
||||
@ -251,7 +251,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
|
||||
{/* Degraded error preview */}
|
||||
{data.status === "degraded" && data.lastSampleError && (
|
||||
<div
|
||||
className="text-[8px] text-amber-300/60 truncate mt-1 bg-amber-950/20 px-1.5 py-0.5 rounded border border-amber-800/20"
|
||||
className="text-[10px] text-amber-300/60 truncate mt-1 bg-amber-950/20 px-1.5 py-0.5 rounded border border-amber-800/20"
|
||||
title={data.lastSampleError}
|
||||
>
|
||||
{data.lastSampleError}
|
||||
@ -294,7 +294,7 @@ function EmbeddedTeam({ members, depth, onSelect, onExtract }: {
|
||||
const useGrid = depth === 0 && members.length >= 2;
|
||||
return (
|
||||
<div className="mt-2 pt-2 border-t border-zinc-700/30">
|
||||
<div className="text-[8px] text-zinc-500 uppercase tracking-widest mb-1.5">Team Members</div>
|
||||
<div className="text-[10px] text-zinc-500 uppercase tracking-widest mb-1.5">Team Members</div>
|
||||
<div className={useGrid
|
||||
? "grid grid-cols-2 gap-1.5 lg:grid-cols-3"
|
||||
: "space-y-1.5"
|
||||
@ -358,7 +358,7 @@ function TeamMemberChip({
|
||||
<div className="flex items-center justify-between gap-1 mb-0.5">
|
||||
<div className="flex items-center gap-1.5 min-w-0">
|
||||
<div className={`w-1.5 h-1.5 rounded-full shrink-0 ${statusCfg.dot}`} />
|
||||
<span className="text-[9px] font-semibold text-zinc-200 truncate leading-tight">
|
||||
<span className="text-[10px] font-semibold text-zinc-200 truncate leading-tight">
|
||||
{data.name}
|
||||
</span>
|
||||
</div>
|
||||
@ -386,7 +386,7 @@ function TeamMemberChip({
|
||||
|
||||
{/* Role */}
|
||||
{data.role && (
|
||||
<div className="text-[8px] text-zinc-500 mb-1 leading-tight truncate">{data.role}</div>
|
||||
<div className="text-[10px] text-zinc-500 mb-1 leading-tight truncate">{data.role}</div>
|
||||
)}
|
||||
|
||||
{/* Skills */}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user