openvibers/openvibe.shared Commits

Shared 2.20.3: filled controls use --accent-strong / --on-accent-strong (WCAG AA contrast in every theme) (#47)

OP OpenVibers committed 10 Oct 2026 · 88efa22804 · 8 files, +18 −9

Filled controls now use the theme's readable token pair (`--accent-strong` with `--on-accent-strong`) instead of `--accent` with white text. White on the default accent `#3b82f6` is 3.68:1, under WCAG 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 (forest, arctic, monokai…).

Changed: the primary button in `ui.js`, the toast's primary action, the account switcher's add button (its hover fallback was a stray `#a07840`), the footer's avatar initial (white on `#60a5fa` was about 2.5:1) and the navbar launcher's pressed segment.

The release UX check's axe run flagged this pairing as `color-contrast` (serious) on product sites. Those sites' own button rules are fixed in their repos; this is the shared half. `navbar.js` is 29.94 KB brotli, inside its 30 KB budget; the perf budget tests pass.

Version 2.20.3, CHANGELOG entry added.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 112c4bc..94aac37 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,15 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semve
breaking change to any exported module, browser global or served file name is a new major.
A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
++## 2.20.3 — 2026-10-10
++
++- Filled controls use the theme's readable pair, `--accent-strong` with `--on-accent-strong`, instead of `--accent` with
++ white. White on the default accent (#3b82f6) is 3.68:1, under WCAG AA's 4.5:1 for text this size; the strong pair is
++ 4.62:1 in the default theme, and every theme defines it (dark text on the light accents). This covers the primary
++ `ui.js` button, the toast's primary action, the account switcher's add button, the footer's avatar initial (white on
++ #60a5fa was 2.5:1) and the navbar launcher's pressed segment. The release UX check's axe run flagged the same pairing
++ on product sites.
++
## 2.20.2 — 2026-10-09
- On a phone (≤ 420 px) the compact navbar keeps a joined brand whole: openre.stream shows "OpenRestream", not "stream"
ddiff --git a/account-switcher.js b/account-switcher.js
iindex 6e6ec62..bba5e11 100644
---- a/account-switcher.js
++++ b/account-switcher.js
@@@ -411,9 +411,9 @@
transition: all .15s;
}
.openvibe-switcher-actions .btn-add {
-- background: var(--accent, #3b82f6); color: #fff;
++ background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff));
}
-- .openvibe-switcher-actions .btn-add:hover { background: var(--accent-dark, #a07840); }
++ .openvibe-switcher-actions .btn-add:hover { background: var(--accent-dark, #1d4ed8); }
.openvibe-switcher-actions .btn-signout {
background: rgba(231,76,60,0.1); color: var(--live-red, #e74c3c);
}
ddiff --git a/footer.js b/footer.js
iindex 0f4114a..1a6ad6f 100644
---- a/footer.js
++++ b/footer.js
@@@ -344,7 +344,7 @@
.ovf-account-who{display:inline-flex;align-items:center;gap:8px;font-size:.84rem;color:var(--text-secondary,#b6bdd2)}
.ovf-account-who strong{color:var(--text-primary,#f1f4fb)}
.ovf-avatar{width:24px;height:24px;border-radius:50%;overflow:hidden;display:grid;place-items:center;
-- background:var(--accent,#60a5fa);color:#fff;font-size:.7rem;font-weight:800;flex:none}
++ background:var(--accent-strong,var(--accent,#3472d8));color:var(--on-accent-strong,var(--on-accent,#fff));font-size:.7rem;font-weight:800;flex:none}
.ovf-avatar img{width:100%;height:100%;object-fit:cover}
.ovf-account-links{display:flex;flex-wrap:wrap;gap:6px}
.ovf-account-links a{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:999px;font-size:.78rem;font-weight:600;
ddiff --git a/navbar.js b/navbar.js
iindex 1c3303a..573b240 100644
---- a/navbar.js
++++ b/navbar.js
@@@ -122,7 +122,7 @@
.ovnav-launcher .ovl-dl { font-weight: 700; letter-spacing: .6px; text-transform: uppercase; font-size: 11px; margin-right: 2px; }
.ovnav-launcher .ovl-seg { display: inline-flex; border: 1px solid var(--border, rgba(255,255,255,.12)); border-radius: 9px; overflow: hidden; }
.ovnav-launcher .ovl-seg button { all: unset; cursor: pointer; padding: 5px 9px; font-size: 12px; font-weight: 650; color: var(--text-secondary, #a8b3c4); }
-- .ovnav-launcher .ovl-seg button[aria-pressed="true"] { background: var(--accent, #3b82f6); color: var(--on-accent, #fff); }
++ .ovnav-launcher .ovl-seg button[aria-pressed="true"] { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.ovnav-launcher .ovl-seg button:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: -2px; }
.ovnav-launcher .ovl-display a { margin-left: auto; color: var(--accent-light, var(--accent, #60a5fa)); font-weight: 600; }
.ovnav-launcher .ovl-addr a { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; }
ddiff --git a/notification-ui.js b/notification-ui.js
iindex 7741c33..a5305bc 100644
---- a/notification-ui.js
++++ b/notification-ui.js
@@@ -78,7 +78,7 @@
.openvibe-toast.priority-critical { border-left: 3px solid var(--live-red, #e74c3c); background: rgba(231,76,60,0.06); }
.openvibe-toast-actions { display: flex; gap: 6px; margin-top: 8px; }
.openvibe-toast-actions button { padding: 5px 12px; border-radius: 5px; border: 1px solid var(--border, #333340); background: var(--bg-hover, #2f2f3d); color: var(--text-primary, #e0e0e0); font-size: 11px; font-weight: 600; cursor: pointer; }
-- .openvibe-toast-actions button.primary { background: var(--accent, #3b82f6); color: #fff; border-color: var(--accent, #3b82f6); }
++ .openvibe-toast-actions button.primary { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); border-color: var(--accent-strong, var(--accent, #3472d8)); }
.openvibe-bell { position: relative; cursor: pointer; padding: 6px; display: inline-flex; align-items: center; justify-content: center; }
.openvibe-bell svg { width: 22px; height: 22px; fill: var(--text-secondary, #b0b0b8); transition: fill .2s; }
ddiff --git a/package-lock.json b/package-lock.json
iindex b789cb9..c485ae2 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-shared",
-- "version": "2.20.2",
++ "version": "2.20.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-shared",
-- "version": "2.20.2",
++ "version": "2.20.3",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0"
ddiff --git a/package.json b/package.json
iindex fd9905a..3736572 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-shared",
-- "version": "2.20.2",
++ "version": "2.20.3",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"bin": {
ddiff --git a/ui.js b/ui.js
iindex 343e687..ec9a5e8 100644
---- a/ui.js
++++ b/ui.js
@@@ -41,7 +41,7 @@
.ovui-btns{display:flex;justify-content:flex-end;gap:8px;margin-top:18px}
.ovui-btn{appearance:none;border:1px solid var(--border,rgba(255,255,255,.14));background:transparent;color:inherit;font:600 14px/1 system-ui,sans-serif;padding:10px 16px;border-radius:10px;cursor:pointer}
.ovui-btn:hover{background:rgba(127,127,127,.12)}
--.ovui-btn.is-primary{background:var(--accent,#3b82f6);border-color:transparent;color:var(--on-accent,#fff)}
++.ovui-btn.is-primary{background:var(--accent-strong,var(--accent,#3472d8));border-color:transparent;color:var(--on-accent-strong,var(--on-accent,#fff))}
.ovui-btn.is-danger{background:var(--danger,#ef4444);border-color:transparent;color:#fff}
.ovui-btn:focus-visible,.ovui-x:focus-visible,.ovui-act:focus-visible{outline:2px solid var(--accent,#3b82f6);outline-offset:2px}
.ovui-notices{display:flex;flex-direction:column;gap:8px;max-width:1080px;margin:14px auto 0;padding:0 16px;box-sizing:border-box;width:100%}