openvibers/openvibe.live Commits
Home: no tabs again; every part stacked on every screen (#873)
Changes
@@@ -16,7 +16,6 @@],"selectors": ["#app",-- "#openvibe-bell-mount","#page-home","#page-home .container > .section-header:first-child","#page-home .hero",@@@ -27,8 +26,6 @@"*::before",".badge",".btn",-- ".btn-danger",-- ".btn-follow",".btn-lg",".btn-openvibe-bucks-mini",".btn-openvibe-coins-mini",@@@ -55,7 +52,6 @@".ch-offline-screen",".ch-panel-bar > .ch-vods-filter-bar",".ch-panel-bar > .clips-taken-filters",-- ".ch-panel-hint b",".ch-panel-hint i",".ch-tab",".ch-tab i",@@@ -65,7 +61,6 @@".ch-tab.active",".ch-tab.active::after",".ch-tabs",-- ".chat-ai-badge",".chat-avatar",".chat-avatar-letter",".chat-avatar-wrap",@@@ -78,24 +73,29 @@".chat-crossfeed-badge",".chat-crossfeed-global",".chat-crossfeed-stream",++ ".chat-edited",".chat-emote",++ ".chat-emote-animated",".chat-header",".chat-header-actions",".chat-input-area",".chat-input-row",".chat-input-row .chat-send-btn",++ ".chat-input-row .ovc-v2 textarea.chat-textarea",++ ".chat-input-row > .ovc-v2",".chat-link",".chat-messages",".chat-mode-select",".chat-mode-select option:disabled",".chat-msg",".chat-msg .chat-user",-- ".chat-msg-crossfeed",".chat-msg-actions",++ ".chat-msg-crossfeed",++ ".chat-msg-tts-off",++ ".chat-msg-tts-off .chat-user::after",".chat-msg.system",++ ".chat-msg:first-child > .chat-msg-actions",".chat-nickels-float .rewards-coin-balance",-- ".chat-relay-badge",-- ".chat-relay-badge i",".chat-send-btn",".chat-settings-btn",".chat-sidebar",@@@ -117,6 +117,19 @@".chat-tts-toggle",".chat-tts-toggle.tts-active",".chat-users-panel",++ ".clip-chat-avatar",++ ".clip-chat-card",++ ".clip-chat-cta",++ ".clip-chat-cta i",++ ".clip-chat-dur",++ ".clip-chat-info",++ ".clip-chat-label",++ ".clip-chat-meta",++ ".clip-chat-meta > span",++ ".clip-chat-play",++ ".clip-chat-thumb",++ ".clip-chat-thumb img",++ ".clip-chat-title",".container",".content-container",".cta-ambient",@@@ -133,21 +146,13 @@".cta-method-num",".cta-section-label",".cta-section-label i",-- ".digest-chip",-- ".digest-hot-line b",-- ".digest-hot-line i",-- ".digest-stat b",-- ".digest-stat i",-- ".digest-title i",-- ".egg-key",-- ".egg-key--letter",".emote-picker",".emote-picker-btn",".emote-picker-btn.gif-btn",".emote-picker-grid",".empty-state",-- ".empty-state i",".fab-label",++ ".fcw-input-area .chat-input-row .ovc-v2 textarea.chat-textarea",".fcw-unread-badge",".floating-chat-fab",".floating-chat-widget",@@@ -165,13 +170,13 @@".global-chat-main .chat-input-area",".global-chat-main .chat-input-row",".global-chat-main .chat-input-row .chat-textarea",++ ".global-chat-main .chat-input-row .ovc-v2 textarea.chat-textarea",".global-chat-main .chat-input-row input",".global-chat-messages",-- ".goal-bar",-- ".goal-fill",".hero",".hero .hero-tagline",".hero h1",++ ".hero h1 .ov-mark",".hero p",".hero-aurora",".hero-bg",@@@ -182,7 +187,6 @@".hero-float",".hero-float img",".hero-float--clip .hero-float-badge",-- ".hero-float--moment .hero-float-badge",".hero-float--paste .hero-float-badge",".hero-float--vod .hero-float-badge",".hero-float-body",@@@ -197,11 +201,11 @@".hero-rotate-wrap",".hero-rotate.visible",".hero-scrim",-- ".hero-slogan-timer b",".hero-slogan-timer i",".hero-stat",".hero-stat > i",".hero-stat > i::before",++ ".hero-stat--live > i",".hero-stat-chart-hint",".hero-stat-delta b",".hero-stat-label",@@@ -275,21 +279,17 @@".offline-global-chat .chat-input-area",".offline-global-chat .chat-input-row",".offline-global-chat .chat-input-row .chat-textarea",++ ".offline-global-chat .chat-input-row .ovc-v2 textarea.chat-textarea",".offline-global-chat .chat-input-row input",".offline-global-chat .chat-messages",".openvibe-navbar.navbar",".openvibe-navbar.navbar .openvibe-navbar-links a.ovnav-link",".openvibe-navbar.navbar .openvibe-navbar-links a.ovnav-link.active",".openvibe-navbar.navbar.ovnav-top",-- ".ov-comet",-- ".ov-dot",-- ".ov-glow",-- ".ov-orbit",-- ".ov-orbit--tail",++ ".ov-mark--ph",".ov-rail",".ov-rail > .moments-row",".ov-rail-bar",-- ".ov-rail-bar > span",".ov-rail-bar[hidden]",".ov-rail-btn",".ov-rail-btn:disabled",@@@ -297,15 +297,9 @@".ov-rail-prev",".ov-rail-track",".ov-rail-track > *",-- ".ov-rail.is-scrollable > .ov-rail-track",".ov-rail:not(.is-end) > .ov-rail-track",".ov-rail:not(.is-scrollable) > .ov-rail-btn",".ov-rail:not(.is-start) > .ov-rail-track",-- ".ov-ring",-- ".ov-spark",-- ".ov-spark--2",-- ".ov-spark--3",-- ".ov-v",".page",".page.active",".paste-modal",@@@ -313,21 +307,14 @@".paste-modal-overlay",".paste-modal-upload",".pastes-grid",-- ".pastes-page-info",".pastes-pagination",".pc-tools-row > button",".pc-tools-row > button.btn-openvibe-bucks-mini",".pc-tools-row > button.btn-openvibe-coins-mini",".pc-tools-row > button.chat-nickels-float",".pc-tools-row > button.chat-tts-toggle.tts-active",-- ".pulse-act i",".pulse-grid",-- ".pulse-kicker i",-- ".pulse-rank b",-- ".pulse-sub b",".rewards-panel",-- ".rs-lite .ov-orbit",-- ".rs-lite .ov-spark",".screenshot-details-grid",".section-header",".section-header .badge",@@@ -343,12 +330,16 @@".section-header h2 > i:first-child",".section-header h2 > i:first-child::before",".section-header::after",-- ".sgg-title i",".stream-card",++ ".stream-card-audio",++ ".stream-card-audio i",".stream-card-avatar",".stream-card-avatar img",".stream-card-duration",".stream-card-info",++ ".stream-card-live",++ ".stream-card-live::before",++ ".stream-card-metaright i",".stream-card-streamer",".stream-card-thumb",".stream-card-thumb i",@@@ -357,12 +348,15 @@".stream-card-viewers",".stream-card-viewers b",".stream-card-viewers i",++ ".stream-card.is-live",++ ".stream-card.is-live .stream-card-avatar",++ ".stream-card.is-live .stream-card-info",++ ".stream-card.is-live .stream-card-thumb img",++ ".stream-card.is-live::after",++ ".stream-card.is-live::before",".stream-grid",".stream-layout",-- ".streamer-group-card .card-ai-overview",".streamer-group-name",-- ".streamer-group-stream-info",-- ".streamer-group-stream-thumb",".toast-container",".tour",".vc-channel-body",@@@ -381,7 +375,6 @@"a","body","body .floating-chat-fab",-- "body .messenger-toggle","body .mobile-chat-toggle","body :is(.modal-overlay, .bc-ws-confirm-overlay, .bc-modal, .bc-perm-overlay, .bucks-log-overlay, .user-ai-modal-overlay, .paste-modal-overlay, .vc-modal-overlay, .chat-slur-nudge-modal, .cosmetics-modal-overlay, .link-trust-overlay, .link-preview-overlay, .cgw-pop-overlay, .image-censor-overlay)","body.ov-nav-overlay .navbar.ovnav-top",@@@ -395,7 +388,6 @@"input","select","select.form-input",-- "textarea",-- ".hero h1 .ov-mark"++ "textarea"]}@@@ -35,7 +35,7 @@"css": ["/css/features/home.css","/css/home-fx.css",-- "/css/home-tour.css", "/shared/ov-parts.css"++ "/css/home-tour.css"],"js": ["/shared/kit-web.js",@@@ -97,16 +97,10 @@<div class="agent-cards" id="home-agents-grid"></div></div>-- <!-- Below Live Now, a phone (600 px and under) shows one part at a time as tabs: For you, Catch up, OpenVibe (the-- owner, 2026-11-11: "consolidate these into tabs, self-contained tabs, so the page isn't so freaking huge … at-- least on mobile"). Every part stays in this HTML for crawlers and readers; a wider screen stacks them as before.-- openvibe-shared ov-parts.css (showcase.parts()) draws it with radios and :has(), no script. -->-- <div class="ov-parts ov-parts--front home-parts" data-parts="3">-- <input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-foryou" value="foryou" checked>-- <input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-catchup" value="catchup">-- <input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-openvibe" value="openvibe">-- <div class="ov-parts-bar" role="group" aria-label="The rest of the home page"><label for="ovp-home-foryou">For you</label><label for="ovp-home-catchup">Catch up</label><label for="ovp-home-openvibe">OpenVibe</label></div>-- <section class="ov-part" data-part="foryou" aria-label="For you">++ <!-- Below Live Now, every part of the home is stacked on every screen: For you, Catch up (the videos, clips and++ pastes), OpenVibe. No tabs (the owner, 2026-11-13: "get rid of these tabs … I want … how it was back"; the++ same as 10-31 and 11-07: never hide content behind tabs). Everything is in the page for readers and crawlers. -->++ <section class="home-part" data-part="foryou" aria-label="For you"><!-- Around OpenVibe: the digest, the star spotlight and the pulse, every one shown on every screen (the owner,2026-10-31: "don't reduce size by removing features"). --><div class="home-around" id="home-around">@@@ -142,7 +136,7 @@</div></div><!-- /home-around --></section>-- <section class="ov-part" data-part="catchup" aria-label="Catch up">++ <section class="home-part" data-part="catchup" aria-label="Catch up"><!-- What people made, above the introduction to the site (roadmap 32.7: the home leads with livecontent and creators): channels that were just on, their recordings, the clips people took@@@ -195,7 +189,7 @@</div></div><!-- /home-catchup --></section>-- <section class="ov-part" data-part="openvibe" aria-label="OpenVibe">++ <section class="home-part" data-part="openvibe" aria-label="OpenVibe"><!-- New here?: the restream tour and the About banner, one after the other on every screen (2026-11-07: thetab row that showed one at a time on a phone is gone; the owner's rule is never to hide content behind@@@ -375,7 +369,6 @@</footer><!--/ov:network--></div></section>-- </div><!-- /ov-parts --></div>@@@ -1213,27 +1213,11 @@ function demoteHomeIntroSections() {if (!last) return;block.dataset.ovDemoted = '1';block.classList.add('home-intro-demoted');-- // On a phone the intro is in the OpenVibe tab (home-parts): it moves to the end of its own part, never out of it.-- const part = block.closest('.ov-part');++ // The intro stays inside the OpenVibe part (it holds New here? and the network): to the end of that part.++ const part = block.closest('.home-part');try { (part || last).appendChild(block); } catch { /* */ }}--/* A link to something inside a phone tab that is not open (#home-network, #ovnet-g-streams…) opens that tab first, so-- * the jump lands on what it names. Wide screens stack the parts and need nothing. */--function openHomePartFor(hash) {-- let el = null;-- try { el = hash && hash.length > 1 ? document.getElementById(decodeURIComponent(hash.slice(1))) : null; } catch { el = null; }-- const part = el && el.closest('.home-parts > .ov-part');-- if (!part) return;-- const radio = document.getElementById(`ovp-home-${part.dataset.part}`);-- if (radio && !radio.checked) { radio.checked = true; requestAnimationFrame(() => { try { el.scrollIntoView({ block: 'start' }); } catch { /* */ } }); }--}--window.addEventListener('hashchange', () => openHomePartFor(location.hash));--document.addEventListener('click', (e) => {-- const a = e.target && e.target.closest && e.target.closest('a[href^="#"]');-- if (a) openHomePartFor(a.getAttribute('href'));--}, true);--/* ── The OpenVibe network (2026-11-07 redesign) ──────────────────────────────────────────────────────────────* The section's tiles are in the page already (scripts/build-network-section.js, from OpenVibe.Network's frame), so* crawlers and a reader without scripts get every site. Here it comes alive:@@@ -1368,7 +1352,6 @@ function initHomeNetwork() {async function loadHome() {initHomeNetwork(); // the OpenVibe network: every site, alive (no tabs: everything shows)demoteHomeIntroSections();-- openHomePartFor(location.hash);void loadHomeChangelog();_initHomeAbout();updateNavHeroTransparency(); // transparent nav over the hero at the top@@@ -1,5 +1,5 @@/**-- * Home tabs: there are none any more (2026-11-07, the owner's rule: never hide content behind tabs).++ * Home tabs: there are none (2026-11-07 and again 2026-11-13, the owner's rule: never hide content behind tabs).** The explainer at the foot (New here?: the restream tour and the About banner) shows both, one after the other, and* the OpenVibe network is its own section with every site. The content blocks are never tabbed again (the owner, 2026-10-31: "now I can't see the videos and clips on the homepage…@@@ -138,25 +138,21 @@ check('the OpenVibe network is its own section: every site a real link, by groupassert.ok(/data-ovnet-switcher><span class="ovnet-orb" aria-hidden="true"><svg class="ovmb"[^>]*><rect class="ovmb-bar"/.test(net) && net.includes('<b>Every site is in the menu</b>') && !/one tap away in the/.test(net), 'the line about the menu carries the menu button as the bar draws it now, and says where it is');});--check('on a phone the rest of the home is three parts as tabs (For you, Catch up, OpenVibe), every one in the HTML', () => {-- // The owner, 2026-11-11: "consolidate these into tabs, self-contained tabs, so the page isn't so freaking huge … at-- // least on mobile". openvibe-shared ov-parts.css draws it (radios and :has(), no script); wide screens stack them.-- const start = home.indexOf('<div class="ov-parts ov-parts--front home-parts" data-parts="3">');-- assert.ok(start > home.indexOf('id="stream-grid-live"'), 'below Live Now');-- const parts = [...home.slice(start).matchAll(/<section class="ov-part" data-part="([a-z]+)"/g)].map((m) => m[1]);++check('the rest of the home is three parts stacked on every screen (For you, Catch up, OpenVibe), with no tabs', () => {++ // The owner, 2026-11-13, of the phone tabs added on 11-12: "get rid of these tabs … I want … how it was back … so that++ // the homepage has all the content and it's more SEO friendly". The same rule as 10-31 and 11-07.++ assert.ok(!home.includes('ov-parts') && !home.includes('ovp-home') && !/type="radio"[^>]*name="ovp-/.test(home), 'no tab wrapper, radios or bar');++ const parts = [...home.matchAll(/<section class="home-part" data-part="([a-z]+)"/g)].map((m) => m[1]);assert.deepStrictEqual(parts, ['foryou', 'catchup', 'openvibe']);-- for (const [id, label] of [['foryou', 'For you'], ['catchup', 'Catch up'], ['openvibe', 'OpenVibe']]) {-- assert.ok(home.includes(`<input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-${id}" value="${id}"`), `${id}: its radio`);-- assert.ok(home.includes(`<label for="ovp-home-${id}">${label}</label>`), `${id}: its tab`);-- }const at = (needle) => home.indexOf(needle);const sec = (id) => at(`data-part="${id}"`);++ assert.ok(at('id="stream-grid-live"') < sec('foryou'), 'below Live Now');assert.ok(sec('foryou') < at('id="home-around"') && at('id="home-around"') < sec('catchup'), 'For you holds Around OpenVibe');-- assert.ok(sec('catchup') < at('id="home-catchup"') && at('id="home-catchup"') < sec('openvibe'), 'Catch up holds the rails');++ assert.ok(sec('catchup') < at('id="home-catchup"') && at('id="home-catchup"') < sec('openvibe'), 'Catch up holds the videos, clips and pastes');assert.ok(sec('openvibe') < at('id="home-intro"') && at('id="home-intro"') < at('id="home-network"'), 'OpenVibe holds New here? and the network');const features = JSON.parse(fs.readFileSync(path.join(__dirname, '../public/features.json'), 'utf8'));-- assert.ok(JSON.stringify(features).includes('/shared/ov-parts.css'), 'the home links the tabs\' stylesheet (blocking, so nothing jumps)');-- assert.ok(/function openHomePartFor\(hash\)/.test(js) && /closest\('\.ov-part'\)/.test(js), 'a link into a closed tab opens it; a returning reader\'s New here? stays inside its tab');++ assert.ok(!JSON.stringify(features).includes('/shared/ov-parts.css'), 'the home links no tab stylesheet');++ assert.ok(!/openHomePartFor/.test(js), 'no code that opens a closed tab, because there are none');});check('the network section is built by its script, between its markers, and nothing in it is a tab', () => {
@@ -16,7 +16,6 @@
@@ -16,7 +16,6 @@
],
],
"selectors": [
"selectors": [
"#app",
"#app",
- "#openvibe-bell-mount",
"#page-home",
"#page-home",
"#page-home .container > .section-header:first-child",
"#page-home .container > .section-header:first-child",
"#page-home .hero",
"#page-home .hero",
@@ -27,8 +26,6 @@
@@ -27,8 +26,6 @@
"*::before",
"*::before",
".badge",
".badge",
".btn",
".btn",
- ".btn-danger",
- ".btn-follow",
".btn-lg",
".btn-lg",
".btn-openvibe-bucks-mini",
".btn-openvibe-bucks-mini",
".btn-openvibe-coins-mini",
".btn-openvibe-coins-mini",
@@ -55,7 +52,6 @@
@@ -55,7 +52,6 @@
".ch-offline-screen",
".ch-offline-screen",
".ch-panel-bar > .ch-vods-filter-bar",
".ch-panel-bar > .ch-vods-filter-bar",
".ch-panel-bar > .clips-taken-filters",
".ch-panel-bar > .clips-taken-filters",
- ".ch-panel-hint b",
".ch-panel-hint i",
".ch-panel-hint i",
".ch-tab",
".ch-tab",
".ch-tab i",
".ch-tab i",
@@ -65,7 +61,6 @@
@@ -65,7 +61,6 @@
".ch-tab.active",
".ch-tab.active",
".ch-tab.active::after",
".ch-tab.active::after",
".ch-tabs",
".ch-tabs",
- ".chat-ai-badge",
".chat-avatar",
".chat-avatar",
".chat-avatar-letter",
".chat-avatar-letter",
".chat-avatar-wrap",
".chat-avatar-wrap",
@@ -78,24 +73,29 @@
@@ -78,24 +73,29 @@
".chat-crossfeed-badge",
".chat-crossfeed-badge",
".chat-crossfeed-global",
".chat-crossfeed-global",
".chat-crossfeed-stream",
".chat-crossfeed-stream",
+ ".chat-edited",
".chat-emote",
".chat-emote",
+ ".chat-emote-animated",
".chat-header",
".chat-header",
".chat-header-actions",
".chat-header-actions",
".chat-input-area",
".chat-input-area",
".chat-input-row",
".chat-input-row",
".chat-input-row .chat-send-btn",
".chat-input-row .chat-send-btn",
+ ".chat-input-row .ovc-v2 textarea.chat-textarea",
+ ".chat-input-row > .ovc-v2",
".chat-link",
".chat-link",
".chat-messages",
".chat-messages",
".chat-mode-select",
".chat-mode-select",
".chat-mode-select option:disabled",
".chat-mode-select option:disabled",
".chat-msg",
".chat-msg",
".chat-msg .chat-user",
".chat-msg .chat-user",
- ".chat-msg-crossfeed",
".chat-msg-actions",
".chat-msg-actions",
+ ".chat-msg-crossfeed",
+ ".chat-msg-tts-off",
+ ".chat-msg-tts-off .chat-user::after",
".chat-msg.system",
".chat-msg.system",
+ ".chat-msg:first-child > .chat-msg-actions",
".chat-nickels-float .rewards-coin-balance",
".chat-nickels-float .rewards-coin-balance",
- ".chat-relay-badge",
- ".chat-relay-badge i",
".chat-send-btn",
".chat-send-btn",
".chat-settings-btn",
".chat-settings-btn",
".chat-sidebar",
".chat-sidebar",
@@ -117,6 +117,19 @@
@@ -117,6 +117,19 @@
".chat-tts-toggle",
".chat-tts-toggle",
".chat-tts-toggle.tts-active",
".chat-tts-toggle.tts-active",
".chat-users-panel",
".chat-users-panel",
+ ".clip-chat-avatar",
+ ".clip-chat-card",
+ ".clip-chat-cta",
+ ".clip-chat-cta i",
+ ".clip-chat-dur",
+ ".clip-chat-info",
+ ".clip-chat-label",
+ ".clip-chat-meta",
+ ".clip-chat-meta > span",
+ ".clip-chat-play",
+ ".clip-chat-thumb",
+ ".clip-chat-thumb img",
+ ".clip-chat-title",
".container",
".container",
".content-container",
".content-container",
".cta-ambient",
".cta-ambient",
@@ -133,21 +146,13 @@
@@ -133,21 +146,13 @@
".cta-method-num",
".cta-method-num",
".cta-section-label",
".cta-section-label",
".cta-section-label i",
".cta-section-label i",
- ".digest-chip",
- ".digest-hot-line b",
- ".digest-hot-line i",
- ".digest-stat b",
- ".digest-stat i",
- ".digest-title i",
- ".egg-key",
- ".egg-key--letter",
".emote-picker",
".emote-picker",
".emote-picker-btn",
".emote-picker-btn",
".emote-picker-btn.gif-btn",
".emote-picker-btn.gif-btn",
".emote-picker-grid",
".emote-picker-grid",
".empty-state",
".empty-state",
- ".empty-state i",
".fab-label",
".fab-label",
+ ".fcw-input-area .chat-input-row .ovc-v2 textarea.chat-textarea",
".fcw-unread-badge",
".fcw-unread-badge",
".floating-chat-fab",
".floating-chat-fab",
".floating-chat-widget",
".floating-chat-widget",
@@ -165,13 +170,13 @@
@@ -165,13 +170,13 @@
".global-chat-main .chat-input-area",
".global-chat-main .chat-input-area",
".global-chat-main .chat-input-row",
".global-chat-main .chat-input-row",
".global-chat-main .chat-input-row .chat-textarea",
".global-chat-main .chat-input-row .chat-textarea",
+ ".global-chat-main .chat-input-row .ovc-v2 textarea.chat-textarea",
".global-chat-main .chat-input-row input",
".global-chat-main .chat-input-row input",
".global-chat-messages",
".global-chat-messages",
- ".goal-bar",
- ".goal-fill",
".hero",
".hero",
".hero .hero-tagline",
".hero .hero-tagline",
".hero h1",
".hero h1",
+ ".hero h1 .ov-mark",
".hero p",
".hero p",
".hero-aurora",
".hero-aurora",
".hero-bg",
".hero-bg",
@@ -182,7 +187,6 @@
@@ -182,7 +187,6 @@
".hero-float",
".hero-float",
".hero-float img",
".hero-float img",
".hero-float--clip .hero-float-badge",
".hero-float--clip .hero-float-badge",
- ".hero-float--moment .hero-float-badge",
".hero-float--paste .hero-float-badge",
".hero-float--paste .hero-float-badge",
".hero-float--vod .hero-float-badge",
".hero-float--vod .hero-float-badge",
".hero-float-body",
".hero-float-body",
@@ -197,11 +201,11 @@
@@ -197,11 +201,11 @@
".hero-rotate-wrap",
".hero-rotate-wrap",
".hero-rotate.visible",
".hero-rotate.visible",
".hero-scrim",
".hero-scrim",
- ".hero-slogan-timer b",
".hero-slogan-timer i",
".hero-slogan-timer i",
".hero-stat",
".hero-stat",
".hero-stat > i",
".hero-stat > i",
".hero-stat > i::before",
".hero-stat > i::before",
+ ".hero-stat--live > i",
".hero-stat-chart-hint",
".hero-stat-chart-hint",
".hero-stat-delta b",
".hero-stat-delta b",
".hero-stat-label",
".hero-stat-label",
@@ -275,21 +279,17 @@
@@ -275,21 +279,17 @@
".offline-global-chat .chat-input-area",
".offline-global-chat .chat-input-area",
".offline-global-chat .chat-input-row",
".offline-global-chat .chat-input-row",
".offline-global-chat .chat-input-row .chat-textarea",
".offline-global-chat .chat-input-row .chat-textarea",
+ ".offline-global-chat .chat-input-row .ovc-v2 textarea.chat-textarea",
".offline-global-chat .chat-input-row input",
".offline-global-chat .chat-input-row input",
".offline-global-chat .chat-messages",
".offline-global-chat .chat-messages",
".openvibe-navbar.navbar",
".openvibe-navbar.navbar",
".openvibe-navbar.navbar .openvibe-navbar-links a.ovnav-link",
".openvibe-navbar.navbar .openvibe-navbar-links a.ovnav-link",
".openvibe-navbar.navbar .openvibe-navbar-links a.ovnav-link.active",
".openvibe-navbar.navbar .openvibe-navbar-links a.ovnav-link.active",
".openvibe-navbar.navbar.ovnav-top",
".openvibe-navbar.navbar.ovnav-top",
- ".ov-comet",
- ".ov-dot",
- ".ov-glow",
- ".ov-orbit",
- ".ov-orbit--tail",
+ ".ov-mark--ph",
".ov-rail",
".ov-rail",
".ov-rail > .moments-row",
".ov-rail > .moments-row",
".ov-rail-bar",
".ov-rail-bar",
- ".ov-rail-bar > span",
".ov-rail-bar[hidden]",
".ov-rail-bar[hidden]",
".ov-rail-btn",
".ov-rail-btn",
".ov-rail-btn:disabled",
".ov-rail-btn:disabled",
@@ -297,15 +297,9 @@
@@ -297,15 +297,9 @@
".ov-rail-prev",
".ov-rail-prev",
".ov-rail-track",
".ov-rail-track",
".ov-rail-track > *",
".ov-rail-track > *",
- ".ov-rail.is-scrollable > .ov-rail-track",
".ov-rail:not(.is-end) > .ov-rail-track",
".ov-rail:not(.is-end) > .ov-rail-track",
".ov-rail:not(.is-scrollable) > .ov-rail-btn",
".ov-rail:not(.is-scrollable) > .ov-rail-btn",
".ov-rail:not(.is-start) > .ov-rail-track",
".ov-rail:not(.is-start) > .ov-rail-track",
- ".ov-ring",
- ".ov-spark",
- ".ov-spark--2",
- ".ov-spark--3",
- ".ov-v",
".page",
".page",
".page.active",
".page.active",
".paste-modal",
".paste-modal",
@@ -313,21 +307,14 @@
@@ -313,21 +307,14 @@
".paste-modal-overlay",
".paste-modal-overlay",
".paste-modal-upload",
".paste-modal-upload",
".pastes-grid",
".pastes-grid",
- ".pastes-page-info",
".pastes-pagination",
".pastes-pagination",
".pc-tools-row > button",
".pc-tools-row > button",
".pc-tools-row > button.btn-openvibe-bucks-mini",
".pc-tools-row > button.btn-openvibe-bucks-mini",
".pc-tools-row > button.btn-openvibe-coins-mini",
".pc-tools-row > button.btn-openvibe-coins-mini",
".pc-tools-row > button.chat-nickels-float",
".pc-tools-row > button.chat-nickels-float",
".pc-tools-row > button.chat-tts-toggle.tts-active",
".pc-tools-row > button.chat-tts-toggle.tts-active",
- ".pulse-act i",
".pulse-grid",
".pulse-grid",
- ".pulse-kicker i",
- ".pulse-rank b",
- ".pulse-sub b",
".rewards-panel",
".rewards-panel",
- ".rs-lite .ov-orbit",
- ".rs-lite .ov-spark",
".screenshot-details-grid",
".screenshot-details-grid",
".section-header",
".section-header",
".section-header .badge",
".section-header .badge",
@@ -343,12 +330,16 @@
@@ -343,12 +330,16 @@
".section-header h2 > i:first-child",
".section-header h2 > i:first-child",
".section-header h2 > i:first-child::before",
".section-header h2 > i:first-child::before",
".section-header::after",
".section-header::after",
- ".sgg-title i",
".stream-card",
".stream-card",
+ ".stream-card-audio",
+ ".stream-card-audio i",
".stream-card-avatar",
".stream-card-avatar",
".stream-card-avatar img",
".stream-card-avatar img",
".stream-card-duration",
".stream-card-duration",
".stream-card-info",
".stream-card-info",
+ ".stream-card-live",
+ ".stream-card-live::before",
+ ".stream-card-metaright i",
".stream-card-streamer",
".stream-card-streamer",
".stream-card-thumb",
".stream-card-thumb",
".stream-card-thumb i",
".stream-card-thumb i",
@@ -357,12 +348,15 @@
@@ -357,12 +348,15 @@
".stream-card-viewers",
".stream-card-viewers",
".stream-card-viewers b",
".stream-card-viewers b",
".stream-card-viewers i",
".stream-card-viewers i",
+ ".stream-card.is-live",
+ ".stream-card.is-live .stream-card-avatar",
+ ".stream-card.is-live .stream-card-info",
+ ".stream-card.is-live .stream-card-thumb img",
+ ".stream-card.is-live::after",
+ ".stream-card.is-live::before",
".stream-grid",
".stream-grid",
".stream-layout",
".stream-layout",
- ".streamer-group-card .card-ai-overview",
".streamer-group-name",
".streamer-group-name",
- ".streamer-group-stream-info",
- ".streamer-group-stream-thumb",
".toast-container",
".toast-container",
".tour",
".tour",
".vc-channel-body",
".vc-channel-body",
@@ -381,7 +375,6 @@
@@ -381,7 +375,6 @@
"a",
"a",
"body",
"body",
"body .floating-chat-fab",
"body .floating-chat-fab",
- "body .messenger-toggle",
"body .mobile-chat-toggle",
"body .mobile-chat-toggle",
"body :is(.modal-overlay, .bc-ws-confirm-overlay, .bc-modal, .bc-perm-overlay, .bucks-log-overlay, .user-ai-modal-overlay, .paste-modal-overlay, .vc-modal-overlay, .chat-slur-nudge-modal, .cosmetics-modal-overlay, .link-trust-overlay, .link-preview-overlay, .cgw-pop-overlay, .image-censor-overlay)",
"body :is(.modal-overlay, .bc-ws-confirm-overlay, .bc-modal, .bc-perm-overlay, .bucks-log-overlay, .user-ai-modal-overlay, .paste-modal-overlay, .vc-modal-overlay, .chat-slur-nudge-modal, .cosmetics-modal-overlay, .link-trust-overlay, .link-preview-overlay, .cgw-pop-overlay, .image-censor-overlay)",
"body.ov-nav-overlay .navbar.ovnav-top",
"body.ov-nav-overlay .navbar.ovnav-top",
@@ -395,7 +388,6 @@
@@ -395,7 +388,6 @@
"input",
"input",
"select",
"select",
"select.form-input",
"select.form-input",
- "textarea",
- ".hero h1 .ov-mark"
+ "textarea"
]
]
}
}
@@ -35,7 +35,7 @@
@@ -35,7 +35,7 @@
"css": [
"css": [
"/css/features/home.css",
"/css/features/home.css",
"/css/home-fx.css",
"/css/home-fx.css",
- "/css/home-tour.css", "/shared/ov-parts.css"
+ "/css/home-tour.css"
],
],
"js": [
"js": [
"/shared/kit-web.js",
"/shared/kit-web.js",
@@ -97,16 +97,10 @@
@@ -97,16 +97,10 @@
<div class="agent-cards" id="home-agents-grid"></div>
<div class="agent-cards" id="home-agents-grid"></div>
</div>
</div>
- <!-- Below Live Now, a phone (600 px and under) shows one part at a time as tabs: For you, Catch up, OpenVibe (the
- owner, 2026-11-11: "consolidate these into tabs, self-contained tabs, so the page isn't so freaking huge … at
- least on mobile"). Every part stays in this HTML for crawlers and readers; a wider screen stacks them as before.
- openvibe-shared ov-parts.css (showcase.parts()) draws it with radios and :has(), no script. -->
- <div class="ov-parts ov-parts--front home-parts" data-parts="3">
- <input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-foryou" value="foryou" checked>
- <input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-catchup" value="catchup">
- <input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-openvibe" value="openvibe">
- <div class="ov-parts-bar" role="group" aria-label="The rest of the home page"><label for="ovp-home-foryou">For you</label><label for="ovp-home-catchup">Catch up</label><label for="ovp-home-openvibe">OpenVibe</label></div>
- <section class="ov-part" data-part="foryou" aria-label="For you">
+ <!-- Below Live Now, every part of the home is stacked on every screen: For you, Catch up (the videos, clips and
+ pastes), OpenVibe. No tabs (the owner, 2026-11-13: "get rid of these tabs … I want … how it was back"; the
+ same as 10-31 and 11-07: never hide content behind tabs). Everything is in the page for readers and crawlers. -->
+ <section class="home-part" data-part="foryou" aria-label="For you">
<!-- Around OpenVibe: the digest, the star spotlight and the pulse, every one shown on every screen (the owner,
<!-- Around OpenVibe: the digest, the star spotlight and the pulse, every one shown on every screen (the owner,
2026-10-31: "don't reduce size by removing features"). -->
2026-10-31: "don't reduce size by removing features"). -->
<div class="home-around" id="home-around">
<div class="home-around" id="home-around">
@@ -142,7 +136,7 @@
@@ -142,7 +136,7 @@
</div>
</div>
</div><!-- /home-around -->
</div><!-- /home-around -->
</section>
</section>
- <section class="ov-part" data-part="catchup" aria-label="Catch up">
+ <section class="home-part" data-part="catchup" aria-label="Catch up">
<!-- What people made, above the introduction to the site (roadmap 32.7: the home leads with live
<!-- What people made, above the introduction to the site (roadmap 32.7: the home leads with live
content and creators): channels that were just on, their recordings, the clips people took
content and creators): channels that were just on, their recordings, the clips people took
@@ -195,7 +189,7 @@
@@ -195,7 +189,7 @@
</div>
</div>
</div><!-- /home-catchup -->
</div><!-- /home-catchup -->
</section>
</section>
- <section class="ov-part" data-part="openvibe" aria-label="OpenVibe">
+ <section class="home-part" data-part="openvibe" aria-label="OpenVibe">
<!-- New here?: the restream tour and the About banner, one after the other on every screen (2026-11-07: the
<!-- New here?: the restream tour and the About banner, one after the other on every screen (2026-11-07: the
tab row that showed one at a time on a phone is gone; the owner's rule is never to hide content behind
tab row that showed one at a time on a phone is gone; the owner's rule is never to hide content behind
@@ -375,7 +369,6 @@
@@ -375,7 +369,6 @@
</footer>
</footer>
<!--/ov:network--></div>
<!--/ov:network--></div>
</section>
</section>
- </div><!-- /ov-parts -->
</div>
</div>
@@ -1213,27 +1213,11 @@ function demoteHomeIntroSections() {
@@ -1213,27 +1213,11 @@ function demoteHomeIntroSections() {
if (!last) return;
if (!last) return;
block.dataset.ovDemoted = '1';
block.dataset.ovDemoted = '1';
block.classList.add('home-intro-demoted');
block.classList.add('home-intro-demoted');
- // On a phone the intro is in the OpenVibe tab (home-parts): it moves to the end of its own part, never out of it.
- const part = block.closest('.ov-part');
+ // The intro stays inside the OpenVibe part (it holds New here? and the network): to the end of that part.
+ const part = block.closest('.home-part');
try { (part || last).appendChild(block); } catch { /* */ }
try { (part || last).appendChild(block); } catch { /* */ }
}
}
-/* A link to something inside a phone tab that is not open (#home-network, #ovnet-g-streams…) opens that tab first, so
- * the jump lands on what it names. Wide screens stack the parts and need nothing. */
-function openHomePartFor(hash) {
- let el = null;
- try { el = hash && hash.length > 1 ? document.getElementById(decodeURIComponent(hash.slice(1))) : null; } catch { el = null; }
- const part = el && el.closest('.home-parts > .ov-part');
- if (!part) return;
- const radio = document.getElementById(`ovp-home-${part.dataset.part}`);
- if (radio && !radio.checked) { radio.checked = true; requestAnimationFrame(() => { try { el.scrollIntoView({ block: 'start' }); } catch { /* */ } }); }
-}
-window.addEventListener('hashchange', () => openHomePartFor(location.hash));
-document.addEventListener('click', (e) => {
- const a = e.target && e.target.closest && e.target.closest('a[href^="#"]');
- if (a) openHomePartFor(a.getAttribute('href'));
-}, true);
-
/* ── The OpenVibe network (2026-11-07 redesign) ──────────────────────────────────────────────────────────────
/* ── The OpenVibe network (2026-11-07 redesign) ──────────────────────────────────────────────────────────────
* The section's tiles are in the page already (scripts/build-network-section.js, from OpenVibe.Network's frame), so
* The section's tiles are in the page already (scripts/build-network-section.js, from OpenVibe.Network's frame), so
* crawlers and a reader without scripts get every site. Here it comes alive:
* crawlers and a reader without scripts get every site. Here it comes alive:
@@ -1368,7 +1352,6 @@ function initHomeNetwork() {
@@ -1368,7 +1352,6 @@ function initHomeNetwork() {
async function loadHome() {
async function loadHome() {
initHomeNetwork(); // the OpenVibe network: every site, alive (no tabs: everything shows)
initHomeNetwork(); // the OpenVibe network: every site, alive (no tabs: everything shows)
demoteHomeIntroSections();
demoteHomeIntroSections();
- openHomePartFor(location.hash);
void loadHomeChangelog();
void loadHomeChangelog();
_initHomeAbout();
_initHomeAbout();
updateNavHeroTransparency(); // transparent nav over the hero at the top
updateNavHeroTransparency(); // transparent nav over the hero at the top
@@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/**
/**
- * Home tabs: there are none any more (2026-11-07, the owner's rule: never hide content behind tabs).
+ * Home tabs: there are none (2026-11-07 and again 2026-11-13, the owner's rule: never hide content behind tabs).
*
*
* The explainer at the foot (New here?: the restream tour and the About banner) shows both, one after the other, and
* The explainer at the foot (New here?: the restream tour and the About banner) shows both, one after the other, and
* the OpenVibe network is its own section with every site. The content blocks are never tabbed again (the owner, 2026-10-31: "now I can't see the videos and clips on the homepage…
* the OpenVibe network is its own section with every site. The content blocks are never tabbed again (the owner, 2026-10-31: "now I can't see the videos and clips on the homepage…
@@ -138,25 +138,21 @@ check('the OpenVibe network is its own section: every site a real link, by group
@@ -138,25 +138,21 @@ check('the OpenVibe network is its own section: every site a real link, by group
assert.ok(/data-ovnet-switcher><span class="ovnet-orb" aria-hidden="true"><svg class="ovmb"[^>]*><rect class="ovmb-bar"/.test(net) && net.includes('<b>Every site is in the menu</b>') && !/one tap away in the/.test(net), 'the line about the menu carries the menu button as the bar draws it now, and says where it is');
assert.ok(/data-ovnet-switcher><span class="ovnet-orb" aria-hidden="true"><svg class="ovmb"[^>]*><rect class="ovmb-bar"/.test(net) && net.includes('<b>Every site is in the menu</b>') && !/one tap away in the/.test(net), 'the line about the menu carries the menu button as the bar draws it now, and says where it is');
});
});
-check('on a phone the rest of the home is three parts as tabs (For you, Catch up, OpenVibe), every one in the HTML', () => {
- // The owner, 2026-11-11: "consolidate these into tabs, self-contained tabs, so the page isn't so freaking huge … at
- // least on mobile". openvibe-shared ov-parts.css draws it (radios and :has(), no script); wide screens stack them.
- const start = home.indexOf('<div class="ov-parts ov-parts--front home-parts" data-parts="3">');
- assert.ok(start > home.indexOf('id="stream-grid-live"'), 'below Live Now');
- const parts = [...home.slice(start).matchAll(/<section class="ov-part" data-part="([a-z]+)"/g)].map((m) => m[1]);
+check('the rest of the home is three parts stacked on every screen (For you, Catch up, OpenVibe), with no tabs', () => {
+ // The owner, 2026-11-13, of the phone tabs added on 11-12: "get rid of these tabs … I want … how it was back … so that
+ // the homepage has all the content and it's more SEO friendly". The same rule as 10-31 and 11-07.
+ assert.ok(!home.includes('ov-parts') && !home.includes('ovp-home') && !/type="radio"[^>]*name="ovp-/.test(home), 'no tab wrapper, radios or bar');
+ const parts = [...home.matchAll(/<section class="home-part" data-part="([a-z]+)"/g)].map((m) => m[1]);
assert.deepStrictEqual(parts, ['foryou', 'catchup', 'openvibe']);
assert.deepStrictEqual(parts, ['foryou', 'catchup', 'openvibe']);
- for (const [id, label] of [['foryou', 'For you'], ['catchup', 'Catch up'], ['openvibe', 'OpenVibe']]) {
- assert.ok(home.includes(`<input type="radio" class="ov-parts-r" name="ovp-home" id="ovp-home-${id}" value="${id}"`), `${id}: its radio`);
- assert.ok(home.includes(`<label for="ovp-home-${id}">${label}</label>`), `${id}: its tab`);
- }
const at = (needle) => home.indexOf(needle);
const at = (needle) => home.indexOf(needle);
const sec = (id) => at(`data-part="${id}"`);
const sec = (id) => at(`data-part="${id}"`);
+ assert.ok(at('id="stream-grid-live"') < sec('foryou'), 'below Live Now');
assert.ok(sec('foryou') < at('id="home-around"') && at('id="home-around"') < sec('catchup'), 'For you holds Around OpenVibe');
assert.ok(sec('foryou') < at('id="home-around"') && at('id="home-around"') < sec('catchup'), 'For you holds Around OpenVibe');
- assert.ok(sec('catchup') < at('id="home-catchup"') && at('id="home-catchup"') < sec('openvibe'), 'Catch up holds the rails');
+ assert.ok(sec('catchup') < at('id="home-catchup"') && at('id="home-catchup"') < sec('openvibe'), 'Catch up holds the videos, clips and pastes');
assert.ok(sec('openvibe') < at('id="home-intro"') && at('id="home-intro"') < at('id="home-network"'), 'OpenVibe holds New here? and the network');
assert.ok(sec('openvibe') < at('id="home-intro"') && at('id="home-intro"') < at('id="home-network"'), 'OpenVibe holds New here? and the network');
const features = JSON.parse(fs.readFileSync(path.join(__dirname, '../public/features.json'), 'utf8'));
const features = JSON.parse(fs.readFileSync(path.join(__dirname, '../public/features.json'), 'utf8'));
- assert.ok(JSON.stringify(features).includes('/shared/ov-parts.css'), 'the home links the tabs\' stylesheet (blocking, so nothing jumps)');
- assert.ok(/function openHomePartFor\(hash\)/.test(js) && /closest\('\.ov-part'\)/.test(js), 'a link into a closed tab opens it; a returning reader\'s New here? stays inside its tab');
+ assert.ok(!JSON.stringify(features).includes('/shared/ov-parts.css'), 'the home links no tab stylesheet');
+ assert.ok(!/openHomePartFor/.test(js), 'no code that opens a closed tab, because there are none');
});
});
check('the network section is built by its script, between its markers, and nothing in it is a tab', () => {
check('the network section is built by its script, between its markers, and nothing in it is a tab', () => {