openvibers/openvibe.domains Commits

Fix the home page folds' summary names (#137)

OP OpenVibers committed 3 days ago · 2329159889 · 3 files, +26 −4

The wide-screen rule hid every span inside a fold summary, including the heading words that showcase wraps in a span, so both summaries had no visible text (axe summary-name). Mark the count with hm-fold-n and hide only that.

Changes

ddiff --git a/public/css/domains.css b/public/css/domains.css
iindex cbd26ef..a401253 100644
---- a/public/css/domains.css
++++ b/public/css/domains.css
@@@ -294,13 +294,13 @@ html[data-ov-motion=off] .dm-bar span{transform: none !important}
.hm-fold-block > summary { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 44px; cursor: pointer; list-style: none; }
.hm-fold-block > summary::-webkit-details-marker { display: none; }
.hm-fold-block > summary h2 { margin: 0; font: 700 clamp(19px, 2.2vw, 26px)/1.2 var(--ov-font, 'Inter', system-ui, sans-serif); }
--.hm-fold-block > summary span { color: var(--text-muted, #7386a3); font-weight: 600; font-size: .86rem; white-space: nowrap; }
++.hm-fold-block > summary .hm-fold-n { color: var(--text-muted, #7386a3); font-weight: 600; font-size: .86rem; white-space: nowrap; }
.hm-fold-block > summary:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 2px; }
@media (min-width: 641px) {
.hm-fold-block { border: 0; background: none; border-radius: 0; margin: 56px auto 0; padding: 0; }
.hm-fold-block > summary { display: block; min-height: 0; }
.hm-fold-block > summary h2 { margin: 0 0 6px; font: 700 clamp(22px, 2.6vw, 30px)/1.2 var(--ov-font, 'Inter', system-ui, sans-serif); }
-- .hm-fold-block > summary span { display: none; }
++ .hm-fold-block > summary .hm-fold-n { display: none; }
.hm-fold-block .hm-sec, .hm-fold-block .sc-sec { margin: 0; max-width: none; padding: 0; }
}
@media (max-width: 640px) { .hm-fold-block { margin-top: 24px; } .hm-fold-block > summary h2 { font-size: 1.05rem; } }
ddiff --git a/server/views/short.js b/server/views/short.js
iindex a821d49..8e58dd5 100644
---- a/server/views/short.js
++++ b/server/views/short.js
@@@ -63,7 +63,7 @@ function foldMeta(body, cls = '') {
* foldBlock({ id, head, html })
*/
function foldBlock({ id, head, html }) {
-- return `<details class="hm-fold hm-fold-block" id="${esc(id)}" open><summary>${head}${foldMeta(html)}</summary>${html}</details>${foldScript(id)}`;
++ return `<details class="hm-fold hm-fold-block" id="${esc(id)}" open><summary>${head}${foldMeta(html, 'hm-fold-n')}</summary>${html}</details>${foldScript(id)}`;
}
/** The script a fold carries: closed on a phone unless the reader opened it before, and it remembers that. */
@@@ -93,7 +93,7 @@ function foldSection(html, needle, id) {
// The lede under the heading goes with it: the fold's heading says enough on a phone.
const lede = /<p class="sc-lede"[^>]*>[\s\S]*?<\/p>/.exec(inner);
if (lede) inner = inner.slice(0, lede.index) + inner.slice(lede.index + lede[0].length);
-- const fold = `<details class="hm-fold hm-fold-block" id="${esc(id)}" open><summary>${head}${foldMeta(inner.trim())}</summary>${inner.trim()}</details>${foldScript(id)}`;
++ const fold = `<details class="hm-fold hm-fold-block" id="${esc(id)}" open><summary>${head}${foldMeta(inner.trim(), 'hm-fold-n')}</summary>${inner.trim()}</details>${foldScript(id)}`;
return html.slice(0, start) + openTag + fold + html.slice(close);
}
ddiff --git a/test/home-short.test.js b/test/home-short.test.js
iindex 02decc7..7e6755f 100644
---- a/test/home-short.test.js
++++ b/test/home-short.test.js
@@@ -25,6 +25,28 @@ const { boot, check, done } = require('./helpers');
assert.ok(r.text.includes('<section class="sc-sec" id="faq"') || r.text.includes('aria-labelledby="sc-questions"'), 'the questions keep their section');
});
++ await check('each fold summary says what it holds, and only its count is hidden on a wide screen', async () => {
++ const r = await t.get('/');
++ const folds = [...r.text.matchAll(/<details class="hm-fold hm-fold-block" id="([^"]+)"[^>]*>([\s\S]*?)<\/details>/g)];
++ assert.ok(folds.length >= 2, 'the home has the questions and API folds');
++ for (const [, id, inner] of folds) {
++ const summary = /<summary>([\s\S]*?)<\/summary>/.exec(inner);
++ assert.ok(summary, `${id} has a summary`);
++ assert.match(summary[1], /<span class="hm-fold-n">/, `${id} marks its count, so the stylesheet can hide only the count`);
++ const words = summary[1]
++ .replace(/<span class="hm-fold-n">[\s\S]*?<\/span>/g, '')
++ .replace(/<span[^>]*aria-hidden="true"[^>]*>[\s\S]*?<\/span>/g, '')
++ .replace(/<[^>]+>/g, ' ')
++ .replace(/&[^;]+;/g, ' ')
++ .replace(/\s+/g, ' ').trim();
++ assert.ok(words.length > 2, `${id} names what it holds in words ("${words}")`);
++ }
++ // The wide-screen rule hides the count only; a rule for every span would hide the heading's own words.
++ const css = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'domains.css'), 'utf8');
++ assert.ok(!/\.hm-fold-block > summary span\s*\{[^}]*display:\s*none/.test(css), 'no rule hides every span in a fold summary');
++ assert.match(css, /\.hm-fold-block > summary \.hm-fold-n\s*\{[^}]*display:\s*none/, 'the wide-screen rule hides the count');
++ });
++
await check('the hero is one name priced, not sc.room\'s default motif (MOTION-1)', async () => {
const r = await t.get('/');
assert.match(r.text, /<div class="dm-motif" aria-hidden="true">/);