openvibers/openvibe.shared Commits

Menus on phones: only the site you are on is lit (hover applies only where a pointer hovers), and launcher rows take one line (#113)

OP OpenVibers committed 19 days ago · d79487affc · 3 files, +32 −3

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex d4caadc..027af50 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -6,6 +6,12 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
## 4.13.0 — unreleased
++- **One lit row in the menus on phones** (`navbar.js`). A tap left `:hover` on the row it touched, so the "all sites"
++ launcher showed two highlighted rows: the site you are on and the last one your finger crossed (the owner, 2026-10-25,
++ on openre.stream). The launcher's and the phone drawer's hover backgrounds now apply only under `@media (hover:
++ hover)`; the site you are on and keyboard focus stay lit everywhere. On phones a launcher row's description is one line
++ (OpenVibe.Network sends short menu labels with the regrouped sites), so the list is shorter and easier to scan.
++ `test/navbar-touch-hover.test.js`.
- **The phone menu always opens on screen** (`navbar.js`). The burger's drawer is anchored to the bar (`position:
absolute`, right under it) instead of the viewport. On a page wider than the phone (openvibe.chat/messages with a long
pasted link was 939 px on a 412 px phone), the fixed drawer opened off-screen and the menu looked missing (the owner,
ddiff --git a/navbar.js b/navbar.js
iindex c64b73d..25f3da5 100644
---- a/navbar.js
++++ b/navbar.js
@@@ -97,7 +97,8 @@
.ovnav-drawer.open { display: flex; animation: openvibe-slide-down .2s ease; }
.ovnav-drawer a { display: flex; align-items: center; gap: 10px; padding: 11px 12px; border-radius: 10px; color: var(--text-primary, #e6edf7); text-decoration: none; font-size: 14.5px; font-weight: 600; }
.ovnav-drawer a.ovnav-sublink { padding-left: 34px; font-weight: 500; color: var(--text-secondary, #a8b3c4); }
-- .ovnav-drawer a:hover, .ovnav-drawer a.active { background: var(--accent-glow, rgba(59,130,246,.14)); }
++ .ovnav-drawer a.active { background: var(--accent-glow, rgba(59,130,246,.14)); }
++ @media (hover: hover) { .ovnav-drawer a:hover { background: var(--accent-glow, rgba(59,130,246,.14)); } }
.ovnav-drawer a[hidden] { display: none; }
.ovnav-drawer .ud-label { padding: 10px 12px 3px; font-size: 10.5px; font-weight: 800; letter-spacing: .9px; text-transform: uppercase; color: var(--text-muted, #7d8aa0); }
.ovnav-drawer-net:empty { display: none; } .ovnav-drawer-net { border-top: 1px solid var(--border, rgba(255,255,255,.08)); margin-top: 4px; }
@@@ -118,7 +119,9 @@
.ovnav-launcher :is(.ovl-app, .ovl-fam) > span:last-child { min-width: 0; }
.ovnav-launcher .ovl-app small { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3; }
.ovnav-launcher .ovl-app.is-here { border-color: color-mix(in srgb, var(--accent, #3b82f6) 55%, transparent); background: var(--accent-glow, rgba(59,130,246,.14)); }
-- .ovnav-launcher .ovl-app:hover, .ovnav-launcher .ovl-fam:hover, .ovnav-launcher a:focus-visible { background: var(--accent-glow, rgba(59,130,246,.14)); outline: none; }
++ /* Hover only where a pointer hovers: on a phone a tap left its row lit beside the site you are on (the owner, 2026-10-25). */
++ .ovnav-launcher a:focus-visible { background: var(--accent-glow, rgba(59,130,246,.14)); outline: none; }
++ @media (hover: hover) { .ovnav-launcher :is(.ovl-app, .ovl-fam):hover { background: var(--accent-glow, rgba(59,130,246,.14)); } }
.ovnav-launcher b { display: block; font-size: 13px; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ovnav-launcher small { display: block; font-size: 11px; color: var(--text-muted, #7d8aa0); margin-top: 1px; }
.ovnav-launcher .ovl-soon { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 4px 4px; }
@@@ -137,7 +140,7 @@
.ovnav-launcher .ovl-all { grid-column: 1 / -1; color: var(--accent-light, var(--accent, #60a5fa)); }
.ovnav-launcher .ovl-h span { text-transform: none; letter-spacing: 0; font-weight: 500; }
.ovnav-launcher .ovl-empty { padding: 18px 8px; color: var(--text-secondary, #a8b3c4); font-size: 13px; }
-- @media (max-width: 480px) { .ovnav-launcher { left: 8px; } .ovnav-launcher :is(.ovl-apps, .ovl-fams) { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
++ @media (max-width: 480px) { .ovnav-launcher { left: 8px; } .ovnav-launcher :is(.ovl-apps, .ovl-fams) { grid-template-columns: repeat(2, minmax(0, 1fr)); } .ovnav-launcher .ovl-app small { -webkit-line-clamp: 1; } }
@media (prefers-reduced-motion: reduce) { .ovnav-launcher { transition: none; } }
.openvibe-navbar-brand .flame { font-size: 18px; text-decoration: none; color: var(--accent, #3b82f6); display: inline-grid; place-items: center; width: 28px; height: 28px; flex: none; }
.openvibe-navbar-brand .name { display: inline-flex; align-items: baseline; font-size: 15px; font-weight: 700; letter-spacing: -.3px; white-space: nowrap; line-height: 1; }
ddiff --git a/test/navbar-touch-hover.test.js b/test/navbar-touch-hover.test.js
nnew file mode 100644
iindex 0000000..21d0e76
---- /dev/null
++++ b/test/navbar-touch-hover.test.js
@@@ -0,0 +1,20 @@
++'use strict';
++// On a phone a tap leaves :hover on whatever it touched, so the launcher showed two lit rows: the site you are on and
++// the last one your finger crossed (the owner, 2026-10-25, on openre.stream). The launcher's and the drawer's hover
++// backgrounds apply only where a pointer really hovers; the site you are on (is-here, active) and keyboard focus
++// stay lit everywhere. On phones a launcher row's description is one line, so the list is short and scannable.
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const src = fs.readFileSync(path.join(__dirname, '..', 'navbar.js'), 'utf8');
++const hoverBlocks = [...src.matchAll(/@media \(hover: hover\) \{([^\n]*)\}/g)].map((m) => m[1]).join('\n');
++const outside = src.replace(/@media \(hover: hover\) \{[^\n]*\}/g, '');
++
++assert.ok(/\.ovnav-launcher :is\(\.ovl-app, \.ovl-fam\):hover/.test(hoverBlocks), 'launcher rows light on hover only where hover exists');
++assert.ok(/\.ovnav-drawer a:hover/.test(hoverBlocks), 'drawer links too');
++assert.ok(!/\.ovl-(app|fam):hover|:is\(\.ovl-app, \.ovl-fam\):hover/.test(outside), 'no launcher hover rule outside (hover: hover)');
++assert.ok(!/\.ovnav-drawer a:hover/.test(outside), 'no drawer hover rule outside (hover: hover)');
++assert.ok(/\.ovnav-launcher \.ovl-app\.is-here \{[^}]*background/.test(outside) && /\.ovnav-launcher a:focus-visible \{[^}]*background/.test(outside), 'the site you are on and keyboard focus are lit on every device');
++assert.ok(/@media \(max-width: 480px\) \{[^\n]*\.ovnav-launcher \.ovl-app small \{ -webkit-line-clamp: 1; \}/.test(src), 'one-line descriptions on phones');
++console.log('navbar-touch-hover: ok');