mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 09:29:38 +02:00
fix: comprehensive a11y and contrast QA pass across workbench
Automated QA loop (6 parallel browser agents, 2 rounds) found and fixed 15 accessibility, contrast, and responsive issues across all 8 pages: - WCAG contrast: light-mode warning (#854d0e), error (#b91c1c), toggle off-state (surface-400), connection badge (fg-muted) - ARIA: mode selector group+pressed, tab pattern ids+labelledby, nav and aside labels, dialog focus-return, alert roles on banners - Responsive: library header flex-wrap, search/button aria-labels - Focus: NavLink visible ring, dialog close button ring Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
77a5fa5044
commit
d097b790ff
24 changed files with 1360 additions and 17 deletions
|
|
@ -251,11 +251,12 @@ export default function ChatPage() {
|
|||
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{/* Mode selector */}
|
||||
<div className="flex rounded-lg border border-border bg-surface-100 p-0.5">
|
||||
<div role="group" aria-label="Chat mode" className="flex rounded-lg border border-border bg-surface-100 p-0.5">
|
||||
{MODES.map((mode) => (
|
||||
<button
|
||||
key={mode.value}
|
||||
onClick={() => setChatMode(mode.value)}
|
||||
aria-pressed={chatMode === mode.value}
|
||||
className={cn(
|
||||
"rounded-md px-3 py-1 text-xs font-medium transition-colors",
|
||||
chatMode === mode.value
|
||||
|
|
|
|||
|
|
@ -324,6 +324,7 @@ function FlowRow({
|
|||
}}
|
||||
className="rounded p-1.5 text-fg-subtle hover:bg-error/10 hover:text-error"
|
||||
title="Stop flow"
|
||||
aria-label={`Stop flow ${flow.id}`}
|
||||
>
|
||||
<Square className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
|
|
@ -451,7 +452,7 @@ export default function FlowsPage() {
|
|||
)}
|
||||
|
||||
{error && (
|
||||
<p className="mb-4 rounded-lg bg-error/10 px-4 py-2 text-sm text-error">
|
||||
<p role="alert" className="mb-4 rounded-lg bg-error/10 px-4 py-2 text-sm text-error">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -500,6 +500,7 @@ export default function GraphPage() {
|
|||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
placeholder="Search nodes..."
|
||||
aria-label="Search nodes"
|
||||
className="w-48 rounded-lg border border-border bg-surface-100 py-1.5 pl-8 pr-3 text-xs text-fg placeholder:text-fg-subtle focus:border-brand-500 focus:outline-none focus:ring-1 focus:ring-brand-500"
|
||||
/>
|
||||
{searchTerm && (
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ export default function KnowledgeCoresPage() {
|
|||
disabled={actionInProgress === id}
|
||||
className="flex items-center gap-1.5 rounded px-2.5 py-1.5 text-xs font-medium text-brand-400 hover:bg-brand-600/10 disabled:opacity-40"
|
||||
title="Load core"
|
||||
aria-label={`Load core ${id}`}
|
||||
>
|
||||
{actionInProgress === id ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
|
|
@ -227,6 +228,7 @@ export default function KnowledgeCoresPage() {
|
|||
disabled={actionInProgress === id}
|
||||
className="flex items-center gap-1.5 rounded px-2.5 py-1.5 text-xs font-medium text-error hover:bg-error/10 disabled:opacity-40"
|
||||
title="Delete core"
|
||||
aria-label={`Delete core ${id}`}
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
Delete
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ function UploadDialog({
|
|||
e.stopPropagation();
|
||||
setFile(null);
|
||||
}}
|
||||
aria-label="Remove selected file"
|
||||
className="ml-1 text-fg-subtle hover:text-fg"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
|
|
@ -345,7 +346,7 @@ export default function LibraryPage() {
|
|||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
{/* Header */}
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="mb-6 flex flex-wrap items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<LibraryBig className="h-6 w-6 text-brand-400" />
|
||||
<h1 className="text-2xl font-bold text-fg">Library</h1>
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ export default function PromptsPage() {
|
|||
{/* Tabs */}
|
||||
<div role="tablist" aria-label="Prompt sections" className="mb-4 flex gap-1 rounded-lg bg-surface-100 p-1">
|
||||
<button
|
||||
id="tab-templates"
|
||||
role="tab"
|
||||
aria-selected={activeTab === "templates"}
|
||||
aria-controls="panel-templates"
|
||||
onClick={() => setActiveTab("templates")}
|
||||
className={cn(
|
||||
"flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors",
|
||||
|
|
@ -86,9 +86,9 @@ export default function PromptsPage() {
|
|||
Templates
|
||||
</button>
|
||||
<button
|
||||
id="tab-system"
|
||||
role="tab"
|
||||
aria-selected={activeTab === "system"}
|
||||
aria-controls="panel-system"
|
||||
onClick={() => setActiveTab("system")}
|
||||
className={cn(
|
||||
"flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors",
|
||||
|
|
@ -111,7 +111,7 @@ export default function PromptsPage() {
|
|||
|
||||
{/* Templates tab */}
|
||||
{activeTab === "templates" && (
|
||||
<div id="panel-templates" role="tabpanel" className="flex flex-1 flex-col gap-4 overflow-hidden">
|
||||
<div id="panel-templates" role="tabpanel" aria-labelledby="tab-templates" className="flex flex-1 flex-col gap-4 overflow-hidden">
|
||||
{loading && prompts.length === 0 && (
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<Loader2 className="mr-2 h-5 w-5 animate-spin text-fg-subtle" />
|
||||
|
|
@ -201,7 +201,7 @@ export default function PromptsPage() {
|
|||
|
||||
{/* System Prompt tab */}
|
||||
{activeTab === "system" && (
|
||||
<div id="panel-system" role="tabpanel" className="flex flex-1 flex-col overflow-hidden rounded-lg border border-border">
|
||||
<div id="panel-system" role="tabpanel" aria-labelledby="tab-system" className="flex flex-1 flex-col overflow-hidden rounded-lg border border-border">
|
||||
<div className="border-b border-border bg-surface-100 px-4 py-3">
|
||||
<h2 className="text-xs font-medium uppercase tracking-wider text-fg-muted">
|
||||
System Prompt
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ export default function SettingsPage() {
|
|||
onClick={toggleTheme}
|
||||
className={cn(
|
||||
"relative inline-flex h-6 w-11 items-center rounded-full transition-colors",
|
||||
isDark ? "bg-brand-600" : "bg-surface-300",
|
||||
isDark ? "bg-brand-600" : "bg-surface-400",
|
||||
)}
|
||||
>
|
||||
<span
|
||||
|
|
@ -372,7 +372,7 @@ export default function SettingsPage() {
|
|||
onClick={() => updateFeatureSwitches({ [key]: !enabled })}
|
||||
className={cn(
|
||||
"relative inline-flex h-6 w-11 items-center rounded-full transition-colors",
|
||||
enabled ? "bg-brand-600" : "bg-surface-300",
|
||||
enabled ? "bg-brand-600" : "bg-surface-400",
|
||||
)}
|
||||
>
|
||||
<span className={cn(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue