openvibers/openrestream Commits

OpenRestream: readable fills (theme accent pair, darker danger/failed), and its button base rule no longer overrides the shipped widget (#34)

OP OpenVibers committed 10 Oct 2026 · 4881332a9a · 1 file, +3 −3

Accessibility (WCAG AA contrast). Filled buttons, chips and badges painted with the plain theme accent and white text now use the theme's readable pair: `background: var(--accent-strong, var(--accent, …))` with `color: var(--on-accent-strong, …)`.

White on the default accent `#3b82f6` is 3.68:1, under AA's 4.5:1 for normal-size text. The strong pair is 4.62:1 in the default theme, and every built-in theme defines it, using dark text on the light accents. The release UX check's axe run flagged this as `color-contrast` (serious), for example on the search buttons of openvibe.trade and openvibe.deals.

The change is mechanical and limited to rule blocks that set both an accent background and a white or `--on-accent` text colour. Bars, dots and outlines are untouched. A border drawn in the same accent follows the fill, and an existing `--on-accent` fallback is kept. Affected tests pass (`ov test`). The matching shared half is openvibe-shared 2.20.3.

OpenRestream's own UI hard-coded `--ore-accent: #3b82f6`. Its button base rule is now `:where(.ore) button`, so component classes such as the shared "shipped" widget's chips keep their own (transparent) style instead of being painted solid. The danger button (white on #ef4444, 3.76:1) is `#dc2626`, and the failed/lost pills are `#b91c1c` with white text.

Changes

ddiff --git a/server/ui/layout.js b/server/ui/layout.js
iindex 0099f9d..45fa480 100644
---- a/server/ui/layout.js
++++ b/server/ui/layout.js
@@@ -25,11 +25,11 @@ main.ore{max-width:1040px;margin:0 auto;padding:24px 16px 64px}
.ore form.inline{display:inline}.ore label{display:block;margin:.4em 0 .15em;color:var(--ore-muted);font-size:.88rem}
.ore input[type=text],.ore input[type=password],.ore input[type=number],.ore select,.ore textarea{width:100%;box-sizing:border-box;background:#0a0f18;color:var(--ore-text);border:1px solid var(--ore-line);border-radius:6px;padding:7px 9px}
.ore .row{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px}
--.ore button{background:var(--ore-accent);color:#fff;border:0;border-radius:6px;padding:7px 12px;cursor:pointer;font-weight:600;margin:6px 6px 0 0}
--.ore button.secondary{background:#334155}.ore button.danger{background:var(--ore-bad)}
++:where(.ore) button{background:var(--accent-strong,#3472d8);color:var(--on-accent-strong,#fff);border:0;border-radius:6px;padding:7px 12px;cursor:pointer;font-weight:600;margin:6px 6px 0 0}
++:where(.ore) button.secondary{background:#334155;color:#fff}:where(.ore) button.danger{background:#dc2626;color:#fff}
.ore .pill{display:inline-block;padding:1px 8px;border-radius:999px;font-size:.8rem;font-weight:600;background:#334155}
.ore .pill.live,.ore .pill.ok{background:var(--ore-ok);color:#04110a}.ore .pill.starting,.ore .pill.ending,.ore .pill.pending,.ore .pill.error,.ore .pill.draining{background:var(--ore-warn);color:#1a1000}
--.ore .pill.failed,.ore .pill.lost{background:var(--ore-bad)}
++.ore .pill.failed,.ore .pill.lost{background:#b91c1c;color:#fff}
.ore .flash{border-left:4px solid var(--ore-accent);padding:8px 12px;background:var(--ore-panel);margin:12px 0}.ore .flash.bad{border-color:var(--ore-bad)}
@media (max-width:640px){.ore th:nth-child(n+4),.ore td:nth-child(n+4){display:none}}
`;