openvibers/openvibe.work Commits
Home folds say how much they hold (#172)
Changes
@@@ -73,6 +73,7 @@.fold-h > h2 { margin: 0; font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -.02em; flex: 1 1 auto; }.fold-h:focus-within { outline: 2px solid var(--accent, #3b82f6); outline-offset: 2px; }.fold-mark { flex: none; }++.fold-n { flex: none; font-size: .82rem; font-weight: 600; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }.fold-mark::after { content: "+"; font-size: 20px; font-weight: 400; color: var(--text-muted, #7386a3); }.fold-toggle:checked ~ .fold-h .fold-mark::after { content: "\2212"; }.fold-body { display: none; }@@@ -88,7 +89,7 @@.fold { margin-top: 56px; }.fold-toggle { display: none; }.fold-h { min-height: 0; margin-bottom: 10px; cursor: default; }-- .fold-mark { display: none; }++ .fold-mark, .fold-n { display: none; }.fold-body { display: block; }.fold-bare > .fold-h { display: none; }.fold-bare { margin-top: 0; }@@@ -24,11 +24,25 @@ const str = (v) => (v && typeof v === 'object' && typeof v.s === 'string') ? v.s** foldBlock({ id, head, html, bare })*/++/**++ * What a fold holds, counted, for its line ("7 questions", "latest 5", "3 items"): a folded part still says how much++ * is behind it (the owner's rule, 2026-10-31: never hide content to shorten; folds show their count). The 11-01 pass++ * gave every other site this; Work's checkbox folds were missed.++ */++function foldMeta(body, cls = '') {++ const s = typeof body === 'string' ? body : String((body && (body.s || body.html || body.value)) || body || '');++ const n = (re) => (s.match(re) || []).length;++ const shipped = /data-ov-shipped="list"[^>]*?data-limit="(\d+)"|data-limit="(\d+)"[^>]*?data-ov-shipped="list"/.exec(s);++ const q = n(/<details[\s>]/g), li = n(/<li[\s>]/g), a = n(/<a\s/g);++ const text = shipped ? `latest ${shipped[1] || shipped[2]}` : q > 1 ? `${q} questions` : li > 1 ? `${li} items` : a > 1 ? `${a} links` : '';++ return text ? `<span${cls ? ` class="${cls}"` : ''}>${text}</span>` : '';++}++function foldBlock({ id, head, html, bare = false }) {const key = `fold-${esc(id)}`;return `<div class="fold${bare ? ' fold-bare' : ''}" id="${key}">`+ `<input class="fold-toggle" type="checkbox" id="${key}-open">`-- + `<label class="fold-h" for="${key}-open">${str(head)}<span class="fold-mark" aria-hidden="true"></span></label>`++ + `<label class="fold-h" for="${key}-open">${str(head)}${foldMeta(str(html), 'fold-n')}<span class="fold-mark" aria-hidden="true"></span></label>`+ `<div class="fold-body">${str(html)}</div></div>`;}nnew file mode 100644@@@ -0,0 +1,12 @@++'use strict';++// A folded part says how much it holds on its line (the owner's rule: folds show their count), as on every other site.++const assert = require('assert');++const { foldBlock } = require('../server/render/short');++const faq = foldBlock({ id: 'faq', bare: true, head: '<h2>Questions people ask</h2>', html: '<details><summary>a</summary></details><details><summary>b</summary></details><details><summary>c</summary></details>' });++assert.ok(faq.includes('<h2>Questions people ask</h2><span class="fold-n">3 questions</span><span class="fold-mark"'), faq);++const list = foldBlock({ id: 'net', head: '<h2>Part of OpenVibe</h2>', html: '<ul><li>a</li><li>b</li></ul>' });++assert.ok(list.includes('<span class="fold-n">2 items</span>'), 'items');++const shipped = foldBlock({ id: 's', head: '<h2>Recently shipped</h2>', html: '<ol data-ov-shipped="list" data-limit="5"><li>x</li></ol>' });++assert.ok(shipped.includes('<span class="fold-n">latest 5</span>'), 'the shipped list says how many it shows');++assert.ok(!foldBlock({ id: 'e', head: '<h2>x</h2>', html: '<p>one</p>' }).includes('fold-n'), 'nothing to count, no count');++console.log('fold-counts: all passed');
@@ -73,6 +73,7 @@
@@ -73,6 +73,7 @@
.fold-h > h2 { margin: 0; font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -.02em; flex: 1 1 auto; }
.fold-h > h2 { margin: 0; font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -.02em; flex: 1 1 auto; }
.fold-h:focus-within { outline: 2px solid var(--accent, #3b82f6); outline-offset: 2px; }
.fold-h:focus-within { outline: 2px solid var(--accent, #3b82f6); outline-offset: 2px; }
.fold-mark { flex: none; }
.fold-mark { flex: none; }
+.fold-n { flex: none; font-size: .82rem; font-weight: 600; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }
.fold-mark::after { content: "+"; font-size: 20px; font-weight: 400; color: var(--text-muted, #7386a3); }
.fold-mark::after { content: "+"; font-size: 20px; font-weight: 400; color: var(--text-muted, #7386a3); }
.fold-toggle:checked ~ .fold-h .fold-mark::after { content: "\2212"; }
.fold-toggle:checked ~ .fold-h .fold-mark::after { content: "\2212"; }
.fold-body { display: none; }
.fold-body { display: none; }
@@ -88,7 +89,7 @@
@@ -88,7 +89,7 @@
.fold { margin-top: 56px; }
.fold { margin-top: 56px; }
.fold-toggle { display: none; }
.fold-toggle { display: none; }
.fold-h { min-height: 0; margin-bottom: 10px; cursor: default; }
.fold-h { min-height: 0; margin-bottom: 10px; cursor: default; }
- .fold-mark { display: none; }
+ .fold-mark, .fold-n { display: none; }
.fold-body { display: block; }
.fold-body { display: block; }
.fold-bare > .fold-h { display: none; }
.fold-bare > .fold-h { display: none; }
.fold-bare { margin-top: 0; }
.fold-bare { margin-top: 0; }
@@ -24,11 +24,25 @@ const str = (v) => (v && typeof v === 'object' && typeof v.s === 'string') ? v.s
@@ -24,11 +24,25 @@ const str = (v) => (v && typeof v === 'object' && typeof v.s === 'string') ? v.s
*
*
* foldBlock({ id, head, html, bare })
* foldBlock({ id, head, html, bare })
*/
*/
+/**
+ * What a fold holds, counted, for its line ("7 questions", "latest 5", "3 items"): a folded part still says how much
+ * is behind it (the owner's rule, 2026-10-31: never hide content to shorten; folds show their count). The 11-01 pass
+ * gave every other site this; Work's checkbox folds were missed.
+ */
+function foldMeta(body, cls = '') {
+ const s = typeof body === 'string' ? body : String((body && (body.s || body.html || body.value)) || body || '');
+ const n = (re) => (s.match(re) || []).length;
+ const shipped = /data-ov-shipped="list"[^>]*?data-limit="(\d+)"|data-limit="(\d+)"[^>]*?data-ov-shipped="list"/.exec(s);
+ const q = n(/<details[\s>]/g), li = n(/<li[\s>]/g), a = n(/<a\s/g);
+ const text = shipped ? `latest ${shipped[1] || shipped[2]}` : q > 1 ? `${q} questions` : li > 1 ? `${li} items` : a > 1 ? `${a} links` : '';
+ return text ? `<span${cls ? ` class="${cls}"` : ''}>${text}</span>` : '';
+}
+
function foldBlock({ id, head, html, bare = false }) {
function foldBlock({ id, head, html, bare = false }) {
const key = `fold-${esc(id)}`;
const key = `fold-${esc(id)}`;
return `<div class="fold${bare ? ' fold-bare' : ''}" id="${key}">`
return `<div class="fold${bare ? ' fold-bare' : ''}" id="${key}">`
+ `<input class="fold-toggle" type="checkbox" id="${key}-open">`
+ `<input class="fold-toggle" type="checkbox" id="${key}-open">`
- + `<label class="fold-h" for="${key}-open">${str(head)}<span class="fold-mark" aria-hidden="true"></span></label>`
+ + `<label class="fold-h" for="${key}-open">${str(head)}${foldMeta(str(html), 'fold-n')}<span class="fold-mark" aria-hidden="true"></span></label>`
+ `<div class="fold-body">${str(html)}</div></div>`;
+ `<div class="fold-body">${str(html)}</div></div>`;
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
+'use strict';
+// A folded part says how much it holds on its line (the owner's rule: folds show their count), as on every other site.
+const assert = require('assert');
+const { foldBlock } = require('../server/render/short');
+const faq = foldBlock({ id: 'faq', bare: true, head: '<h2>Questions people ask</h2>', html: '<details><summary>a</summary></details><details><summary>b</summary></details><details><summary>c</summary></details>' });
+assert.ok(faq.includes('<h2>Questions people ask</h2><span class="fold-n">3 questions</span><span class="fold-mark"'), faq);
+const list = foldBlock({ id: 'net', head: '<h2>Part of OpenVibe</h2>', html: '<ul><li>a</li><li>b</li></ul>' });
+assert.ok(list.includes('<span class="fold-n">2 items</span>'), 'items');
+const shipped = foldBlock({ id: 's', head: '<h2>Recently shipped</h2>', html: '<ol data-ov-shipped="list" data-limit="5"><li>x</li></ol>' });
+assert.ok(shipped.includes('<span class="fold-n">latest 5</span>'), 'the shipped list says how many it shows');
+assert.ok(!foldBlock({ id: 'e', head: '<h2>x</h2>', html: '<p>one</p>' }).includes('fold-n'), 'nothing to count, no count');
+console.log('fold-counts: all passed');