fix(a11y): WCAG AA contrast retune for the Otter Orange palette (#567)

Fixes #557. Vivid fill, ink label: brand #E07832 stays on fills while primary-foreground flips to #1A1814 (5.83:1); new theme-aware ink tokens carry orange, destructive, and success text roles; opacity-modified text purged; landing, demo, and the docs fund button retuned. Guarded by a CSS-parsing unit contrast test, rebuilt axe baselines with zero contrast entries, a new landing axe smoke, and fully regenerated darwin visual baselines.
This commit is contained in:
SnapOtter
2026-07-18 12:56:48 +08:00
committed by GitHub
parent 6241f8719f
commit 51022628dc
566 changed files with 856 additions and 707 deletions
+4 -4
View File
@@ -238,7 +238,7 @@ test.describe("A) Multi-input tools", () => {
// Since merge-audio requires 2+ inputs, each individual file fails, yielding
// "All files failed processing". This confirms the batch-instead-of-merge bug.
const errorText = await page
.locator("[role='alert'], .text-red-500")
.locator("[role='alert'], .text-destructive-ink, .text-red-500")
.first()
.innerText()
.catch(() => "no error visible");
@@ -319,7 +319,7 @@ test.describe("A) Multi-input tools", () => {
// Same bug as merge-audio: processAllFiles sends each file individually,
// merge-csvs needs 2+ files, so each individual file fails.
const errorText = await page
.locator("[role='alert'], .text-red-500")
.locator("[role='alert'], .text-destructive-ink, .text-red-500")
.first()
.innerText()
.catch(() => "no error visible");
@@ -561,7 +561,7 @@ test.describe("A) Multi-input tools", () => {
).toBe(inputFiles.length);
} else {
const errorText = await page
.locator("[role='alert'], .text-red-500")
.locator("[role='alert'], .text-destructive-ink, .text-red-500")
.first()
.innerText()
.catch(() => "no error visible");
@@ -771,7 +771,7 @@ test.describe("C) Edge cases", () => {
let gotDownload = false;
while (Date.now() < deadline) {
const errorRegion = page
.locator("[role='alert'], [aria-live='assertive'], .text-red-500")
.locator("[role='alert'], [aria-live='assertive'], .text-destructive-ink, .text-red-500")
.filter({ hasText: /error|failed|too many|maximum|limit|exceeded|invalid/i })
.first();
if (await errorRegion.isVisible().catch(() => false)) {
+3 -1
View File
@@ -398,7 +398,9 @@ test.describe("1: Modality-crossing output previews", () => {
}
}
// Check for error
const errorMsg = page.locator(".text-destructive, .text-red-500").first();
const errorMsg = page
.locator(".text-destructive, .text-destructive-ink, .text-red-500")
.first();
if (await errorMsg.isVisible().catch(() => false)) {
errorFound = true;
break;
+1 -1
View File
@@ -127,7 +127,7 @@ test.describe("Pipeline Builder UI", () => {
if (!hasPreview) {
// Also check for error
const errorEl = page.locator(".text-red-500").first();
const errorEl = page.locator(".text-destructive-ink, .text-red-500").first();
const errorText = await errorEl.textContent().catch(() => null);
if (errorText) {
console.log(`Pipeline UI error displayed: ${errorText}`);
+2 -2
View File
@@ -1490,7 +1490,7 @@ test.describe("FILE: csv-excel", () => {
const issues = instrument(page);
await setupTool(page, "csv-excel", CSV);
// Process but check for inline errors too (the csv-excel tool surfaces
// errors in a <p class="text-red-500"> that waitForResult doesn't catch).
// errors in a <p class="text-destructive-ink"> that waitForResult doesn't catch).
const submit = page.getByTestId("csv-excel-submit");
await submit.first().click();
// Wait up to 60s for either download button or an inline error
@@ -1498,7 +1498,7 @@ test.describe("FILE: csv-excel", () => {
let gotResult = false;
let inlineError = "";
while (Date.now() < deadline) {
const errEl = page.locator(".text-red-500").first();
const errEl = page.locator(".text-destructive-ink, .text-red-500").first();
if (await errEl.isVisible().catch(() => false)) {
inlineError = await errEl.innerText().catch(() => "unknown error");
gotResult = true;