openvibers/openvibe.live Commits
Icons stay put: the go-live guide's root is .ovg-root, never the glyph icons' .ovg (#493)
Changes
@@@ -1,6 +1,8 @@/* ── Go Live setup wizard (public/js/golive-wizard.js) ── */--.ovg { position: fixed; inset: 0; z-index: 21000; display: none; }--.ovg.is-open { display: block; }++/* The root is .ovg-root, never .ovg: openvibe-shared's ov-glyphs.js marks every icon it draws with class "ovg", and a++ bare .ovg rule here hid every icon on the page and pinned the rest to the top-left corner (the owner, 2026-11-01). */++.ovg-root { position: fixed; inset: 0; z-index: 21000; display: none; }++.ovg-root.is-open { display: block; }body.ovg-lock { overflow: hidden; }.ovg-scrim { position: absolute; inset: 0; background: rgba(4,5,10,0.72); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); animation: ovgFade .25s ease; }.ovg-card { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(720px, calc(100vw - 24px)); max-height: calc(100vh - 32px); display: flex; flex-direction: column;@@@ -824,7 +824,7 @@ function ovClearStrandedOverlays() {document.querySelectorAll(sel).forEach(el => { try { el.remove(); } catch { /* */ } });}// The scroll lock outliving its modal is the other way a page goes dead.-- try { if (!document.querySelector('.ovg.is-open')) document.body.classList.remove('ovg-lock'); } catch { /* */ }++ try { if (!document.querySelector('.ovg-root.is-open')) document.body.classList.remove('ovg-lock'); } catch { /* */ }}/**@@@ -41,7 +41,7 @@function shell() {let root = $('#ovg');if (root) return root;-- root = document.createElement('div'); root.id = 'ovg'; root.className = 'ovg';++ root = document.createElement('div'); root.id = 'ovg'; root.className = 'ovg-root'; // never 'ovg': the glyph icons' classroot.innerHTML = `<div class="ovg-scrim"></div><div class="ovg-card" role="dialog" aria-modal="true"><button type="button" class="ovg-close" aria-label="Close"><i class="fa-solid fa-xmark"></i></button>nnew file mode 100644@@@ -0,0 +1,33 @@++'use strict';++/**++ * openvibe-shared's ov-glyphs.js (loaded by the shared navbar on every page that uses Font Awesome) draws each icon as++ * <i class="fa-solid fa-… ovg"><svg>…</svg></i>. A rule of Live's own on the bare class .ovg styles every one of those++ * icons too: the go-live guide's root was .ovg { position: fixed; inset: 0; display: none }, so once its stylesheet++ * loaded (a couple of seconds in, for signed-in streamers) every icon vanished and the rest were pinned to the++ * top-left corner (the owner, 2026-11-01: "broken icons… the play button in the top left… cubes"). Live's own classes++ * may start with "ovg-" (the guide's .ovg-quest, .ovg-root …) but never be exactly "ovg".++ */++const assert = require('assert');++const fs = require('fs');++const path = require('path');++++const ROOT = path.join(__dirname, '..', 'public');++const files = [];++(function walk(dir) {++ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {++ const p = path.join(dir, e.name);++ if (e.isDirectory()) { if (e.name !== 'vendor') walk(p); } else if (/\.(css|js|html)$/.test(e.name)) files.push(p);++ }++})(ROOT);++++const BARE_SELECTOR = /(^|[\s,}>~+(])\.ovg(?![\w-])/; // .ovg as a whole class in a selector++const BARE_CLASS = /(class(Name)?\s*=\s*['"]|classList\.(add|toggle|contains)\(\s*['"])ovg(?=['"\s])/; // class="ovg …", className = 'ovg'++const offenders = [];++for (const f of files) {++ const text = fs.readFileSync(f, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '');++ text.split('\n').forEach((line, i) => {++ if (BARE_SELECTOR.test(line) || BARE_CLASS.test(line)) offenders.push(`${path.relative(ROOT, f)}:${i + 1}: ${line.trim().slice(0, 120)}`);++ });++}++assert.deepStrictEqual(offenders, [], `the class "ovg" belongs to the shared glyph icons; use .ovg-root or another ovg-… name:\n${offenders.join('\n')}`);++console.log(` ✓ no rule or element of Live's own uses the glyph icons' class "ovg" (${files.length} files)`);
@@ -1,6 +1,8 @@
@@ -1,6 +1,8 @@
/* ── Go Live setup wizard (public/js/golive-wizard.js) ── */
/* ── Go Live setup wizard (public/js/golive-wizard.js) ── */
-.ovg { position: fixed; inset: 0; z-index: 21000; display: none; }
-.ovg.is-open { display: block; }
+/* The root is .ovg-root, never .ovg: openvibe-shared's ov-glyphs.js marks every icon it draws with class "ovg", and a
+ bare .ovg rule here hid every icon on the page and pinned the rest to the top-left corner (the owner, 2026-11-01). */
+.ovg-root { position: fixed; inset: 0; z-index: 21000; display: none; }
+.ovg-root.is-open { display: block; }
body.ovg-lock { overflow: hidden; }
body.ovg-lock { overflow: hidden; }
.ovg-scrim { position: absolute; inset: 0; background: rgba(4,5,10,0.72); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); animation: ovgFade .25s ease; }
.ovg-scrim { position: absolute; inset: 0; background: rgba(4,5,10,0.72); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); animation: ovgFade .25s ease; }
.ovg-card { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(720px, calc(100vw - 24px)); max-height: calc(100vh - 32px); display: flex; flex-direction: column;
.ovg-card { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(720px, calc(100vw - 24px)); max-height: calc(100vh - 32px); display: flex; flex-direction: column;
@@ -824,7 +824,7 @@ function ovClearStrandedOverlays() {
@@ -824,7 +824,7 @@ function ovClearStrandedOverlays() {
document.querySelectorAll(sel).forEach(el => { try { el.remove(); } catch { /* */ } });
document.querySelectorAll(sel).forEach(el => { try { el.remove(); } catch { /* */ } });
}
}
// The scroll lock outliving its modal is the other way a page goes dead.
// The scroll lock outliving its modal is the other way a page goes dead.
- try { if (!document.querySelector('.ovg.is-open')) document.body.classList.remove('ovg-lock'); } catch { /* */ }
+ try { if (!document.querySelector('.ovg-root.is-open')) document.body.classList.remove('ovg-lock'); } catch { /* */ }
}
}
/**
/**
@@ -41,7 +41,7 @@
@@ -41,7 +41,7 @@
function shell() {
function shell() {
let root = $('#ovg');
let root = $('#ovg');
if (root) return root;
if (root) return root;
- root = document.createElement('div'); root.id = 'ovg'; root.className = 'ovg';
+ root = document.createElement('div'); root.id = 'ovg'; root.className = 'ovg-root'; // never 'ovg': the glyph icons' class
root.innerHTML = `<div class="ovg-scrim"></div>
root.innerHTML = `<div class="ovg-scrim"></div>
<div class="ovg-card" role="dialog" aria-modal="true">
<div class="ovg-card" role="dialog" aria-modal="true">
<button type="button" class="ovg-close" aria-label="Close"><i class="fa-solid fa-xmark"></i></button>
<button type="button" class="ovg-close" aria-label="Close"><i class="fa-solid fa-xmark"></i></button>
new file mode 100644
new file mode 100644
@@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
+'use strict';
+/**
+ * openvibe-shared's ov-glyphs.js (loaded by the shared navbar on every page that uses Font Awesome) draws each icon as
+ * <i class="fa-solid fa-… ovg"><svg>…</svg></i>. A rule of Live's own on the bare class .ovg styles every one of those
+ * icons too: the go-live guide's root was .ovg { position: fixed; inset: 0; display: none }, so once its stylesheet
+ * loaded (a couple of seconds in, for signed-in streamers) every icon vanished and the rest were pinned to the
+ * top-left corner (the owner, 2026-11-01: "broken icons… the play button in the top left… cubes"). Live's own classes
+ * may start with "ovg-" (the guide's .ovg-quest, .ovg-root …) but never be exactly "ovg".
+ */
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const ROOT = path.join(__dirname, '..', 'public');
+const files = [];
+(function walk(dir) {
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
+ const p = path.join(dir, e.name);
+ if (e.isDirectory()) { if (e.name !== 'vendor') walk(p); } else if (/\.(css|js|html)$/.test(e.name)) files.push(p);
+ }
+})(ROOT);
+
+const BARE_SELECTOR = /(^|[\s,}>~+(])\.ovg(?![\w-])/; // .ovg as a whole class in a selector
+const BARE_CLASS = /(class(Name)?\s*=\s*['"]|classList\.(add|toggle|contains)\(\s*['"])ovg(?=['"\s])/; // class="ovg …", className = 'ovg'
+const offenders = [];
+for (const f of files) {
+ const text = fs.readFileSync(f, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '');
+ text.split('\n').forEach((line, i) => {
+ if (BARE_SELECTOR.test(line) || BARE_CLASS.test(line)) offenders.push(`${path.relative(ROOT, f)}:${i + 1}: ${line.trim().slice(0, 120)}`);
+ });
+}
+assert.deepStrictEqual(offenders, [], `the class "ovg" belongs to the shared glyph icons; use .ovg-root or another ovg-… name:\n${offenders.join('\n')}`);
+console.log(` ✓ no rule or element of Live's own uses the glyph icons' class "ovg" (${files.length} files)`);