openvibers/openvibe.shared Commits

4.39.1: room.css stands on its own (the kit's tokens and numbers strip), so a front page without kit.css draws its cards and stats (#179)

OP OpenVibers committed 15 days ago · 31670fded7 · 7 files, +61 −6

Media's home loads room.css without kit.css. It had no --ovk-* tokens, so cards lost their corners and colours, picture-less cards had no background, and the kit.stats strip was a bare list. room.css now carries identical copies: the tokens as :where(:root), so kit.css and site values win, and the strip. A test keeps both copies identical.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex d12b462..64aecbf 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -6,6 +6,14 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
## Unreleased
++## 4.39.1 — 2026-10-29
++
++- **room.css stands on its own.** A front page that loads room.css without kit.css (Media's, to skip kit.css's 25 KB)
++ had no `--ovk-*` tokens: cards lost their corners and colours, a card without a picture had no background, and its
++ `kit.stats` strip was a bare list. room.css now carries the same tokens (as `:where(:root)`, so kit.css's and a
++ site's own values always win) and the numbers strip. The copies are identical, so loading both files changes nothing, and
++ test/room-kit.test.js keeps them that way. room.css: +2.8 KB raw.
++
## 4.39.0 — 2026-10-29
What the front-page passes of 10-29 (Media, Quest, Actor, Rent, Services, Community) each had to add locally:
ddiff --git a/README.md b/README.md
iindex 1b90f70..0a98d62 100644
---- a/README.md
++++ b/README.md
@@@ -2,7 +2,7 @@
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
--**Status:** alpha, v4.39.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
++**Status:** alpha, v4.39.1 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
consumer installs a tagged release and none keeps a vendored copy
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
the tag it pins.
ddiff --git a/STATUS.json b/STATUS.json
iindex e143a67..eea5062 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -4,7 +4,7 @@
"code": true,
"wave": "W2",
"package": "openvibe-shared",
-- "version": "4.39.0",
++ "version": "4.39.1",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"deployed": false,
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
ddiff --git a/package-lock.json b/package-lock.json
iindex f95f99d..cdb2ada 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-shared",
-- "version": "4.39.0",
++ "version": "4.39.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-shared",
-- "version": "4.39.0",
++ "version": "4.39.1",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0",
ddiff --git a/package.json b/package.json
iindex 6861076..5750714 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-shared",
-- "version": "4.39.0",
++ "version": "4.39.1",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"bin": {
ddiff --git a/room.css b/room.css
iindex 6473cbb..a922e86 100644
---- a/room.css
++++ b/room.css
@@@ -1,6 +1,48 @@
/* openvibe-shared/room.css — the room kit's look (4.29.1; before, in kit.css): a room's accent (rooms.js), kit.card and
* kit.rail. A page that shows cards or rails, or wears a room's accent (sc.room() does all three), loads it after
-- * kit.css; pages that use only the kit's controls do not pay for it. Uses kit.css's tokens (--ovk-*). */
++ * kit.css, or alone on a front page that draws only cards, rails and a numbers strip (it carries the tokens and the
++ * strip since 4.39.1); pages that use only the kit's controls do not pay for it. */
++
++/* ── The kit's tokens and its numbers strip, the same as kit.css's (4.39.1): a front page that loads room.css without
++ * kit.css (cards, rails and a kit.stats strip, nothing else) still has them. Identical copies, so loading both files
++ * changes nothing (the tokens are :where(:root), so kit.css's and a site's own values always win);
++ * test/room-kit.test.js keeps them identical. ── */
++:where(:root) {
++ --ovk-bg: var(--bg-primary, #0b0f17);
++ --ovk-panel: var(--bg-card, var(--bg-secondary, #121826));
++ --ovk-panel-2: var(--bg-hover, var(--bg-tertiary, #1a2233));
++ --ovk-input: var(--bg-input, var(--bg-tertiary, #0f1522));
++ --ovk-line: var(--border, rgba(255, 255, 255, .1));
++ --ovk-text: var(--text-primary, #e8ecf3);
++ --ovk-muted: var(--text-muted, var(--text-secondary, #93a0b4));
++ --ovk-accent: var(--accent, #3b82f6);
++ --ovk-fill: var(--accent-strong, var(--accent, #3b82f6));
++ --ovk-on-fill: var(--on-accent-strong, var(--on-accent, #fff));
++ --ovk-ok: var(--success, #22c55e);
++ --ovk-warn: var(--warning, #f59e0b);
++ --ovk-bad: var(--danger, var(--error, #ef4444));
++ --ovk-live: var(--live-red, #ef4444);
++ --ovk-radius: 14px;
++ --ovk-radius-sm: 10px;
++ --ovk-tap: 44px;
++ --ovk-top: var(--ovnav-real-h, 52px); /* the navbar's height: sticky things stop under it */
++ --ovk-bottom: var(--ovnav-appbar-h, 0px); /* the app bar's height on phones (navbar.js sets it) */
++ --ovk-font: var(--ov-font, 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif);
++}
++.ovk-stats { display: flex; gap: 8px; margin: 12px -16px; padding: 0 16px; overflow-x: auto; scrollbar-width: none; }
++.ovk-stats::-webkit-scrollbar { display: none; }
++.ovk-stats > div { display: flex; flex-direction: column-reverse; flex: 0 0 auto; min-width: 104px; box-sizing: border-box; padding: 8px 14px; border: 1px solid var(--ovk-line); border-radius: 12px; background: var(--ovk-panel); }
++.ovk-stats dt { margin: 0; color: var(--ovk-muted); font-size: .76rem; line-height: 1.25; }
++.ovk-stats dt a { color: inherit; text-decoration: none; }
++.ovk-stat--link { position: relative; transition: border-color .15s; }
++.ovk-stat--link dt a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
++.ovk-stat--link:hover { border-color: var(--ovk-accent); }
++.ovk-stat--link dt a:focus-visible { outline: none; }
++.ovk-stat--link:focus-within { outline: 2px solid var(--ovk-accent); outline-offset: -2px; }
++.ovk-stats dd { margin: 0; color: var(--ovk-text); font-size: 1.2rem; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.2; }
++@media (min-width: 600px) {
++ .ovk-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); margin-left: 0; margin-right: 0; padding: 0; overflow: visible; }
++}
/* ── Rooms (rooms.js): the room's accent in the theme's mode. rooms.style(id) sets --room-dark/--room-light on .ov-room;
* without them the theme's accent stays. --room-accent: icons, outlines, motifs; --room-strong: text on the page;
ddiff --git a/test/room-kit.test.js b/test/room-kit.test.js
iindex 2de36e4..e0a650e 100644
---- a/test/room-kit.test.js
++++ b/test/room-kit.test.js
@@@ -88,6 +88,11 @@ const sc = require('../showcase');
const kitCss = fs.readFileSync(path.join(__dirname, '..', 'kit.css'), 'utf8');
assert.match(kitCss, /\.ovk-tabs a, \.ovk-list-head a \{ min-height: 44px; \}/, 'tab pills and list links are 44 px to the touch');
assert.match(kitCss, /\.ovk-stats dt a \{ color: inherit; text-decoration: none; \}/, 'a stats label that is a link is not underlined');
++ // 4.39.1: room.css stands alone (Media's front page loads it without kit.css): the same tokens and numbers strip.
++ const tok = (css) => { const at = css.search(/^(:root|:where\(:root\)) \{/m); return at < 0 ? '' : css.slice(css.indexOf('{', at), css.indexOf('}', at) + 1); };
++ assert.ok(tok(kitCss).length > 500 && tok(room) === tok(kitCss) && /^:where\(:root\) \{/m.test(room), 'room.css carries kit.css\'s tokens, identical, at zero specificity');
++ const strip = (css) => css.split('\n').filter((l) => /^\.ovk-stats?[\s:>-]|^\.ovk-stat--link|^ {4}\.ovk-stats \{ display: grid;/.test(l)).join('\n');
++ assert.ok(strip(kitCss).length > 400 && strip(room) === strip(kitCss), 'and the same numbers strip');
}
// ── sc.room: the front door's order, the accent, nothing invented ──