openvibers/openvibe.games Commits
A fold says what it holds, counted, not "tap to open" (#252)
Changes
@@@ -1313,7 +1313,7 @@shipped.js, which the shared footer loads), the same on every OpenVibe site. A fold on a phone:closed there, open where there is room, and the list stays in the page. --><details class="gm-fold gm-fold-block" id="home-shipped" open>-- <summary><h2>Recently shipped on OpenVibe.Games</h2><span>tap to open</span></summary>++ <summary><h2>Recently shipped on OpenVibe.Games</h2><span>latest 5</span></summary><sectionclass="ov-shipped-home"aria-label="What shipped"@@@ -37,7 +37,7 @@ describe('the home on a phone', () => {})expect(html).toContain('<details class="gm-fold gm-fold-block" id="home-faq" open>')expect(html).toContain(-- '<summary><h2 id="home-faq">Questions</h2><span>tap to open</span></summary>',++ '<summary><h2 id="home-faq">Questions</h2></summary>',)expect(html).toContain('the answers')expect(html).toContain('document.getElementById("home-faq")')@@@ -42,11 +42,27 @@ export function pickBlock(o: {}++/**++ * What a fold holds, counted, for its title row (the owner, 2026-10-31: a fold that shortens a page shows its count):++ * "6 questions", "12 items", "latest 5" for the shipped list, or nothing when there is nothing to count. Replaces the++ * hint the fold used to show instead.++ */++export function foldMeta(body: string, cls = ''): string {++ const s = String(body ?? '')++ const n = (re: RegExp): number => (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)++ const li = n(/<li[\s>]/g)++ const 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>` : ''++}++/*** A fold. The head is the heading the block had; the html is what it holds.*/export function foldBlock(o: { id: string; head: string; html: string }): string {-- return `<details class="gm-fold gm-fold-block" id="${esc(o.id)}" open><summary>${o.head}<span>tap to open</span></summary>${o.html}</details>${foldScript(o.id)}`++ return `<details class="gm-fold gm-fold-block" id="${esc(o.id)}" open><summary>${o.head}${foldMeta(o.html)}</summary>${o.html}</details>${foldScript(o.id)}`}/** The script a fold carries: closed on a phone unless the reader opened it before, and it remembers that. */
@@ -1313,7 +1313,7 @@
@@ -1313,7 +1313,7 @@
shipped.js, which the shared footer loads), the same on every OpenVibe site. A fold on a phone:
shipped.js, which the shared footer loads), the same on every OpenVibe site. A fold on a phone:
closed there, open where there is room, and the list stays in the page. -->
closed there, open where there is room, and the list stays in the page. -->
<details class="gm-fold gm-fold-block" id="home-shipped" open>
<details class="gm-fold gm-fold-block" id="home-shipped" open>
- <summary><h2>Recently shipped on OpenVibe.Games</h2><span>tap to open</span></summary>
+ <summary><h2>Recently shipped on OpenVibe.Games</h2><span>latest 5</span></summary>
<section
<section
class="ov-shipped-home"
class="ov-shipped-home"
aria-label="What shipped"
aria-label="What shipped"
@@ -37,7 +37,7 @@ describe('the home on a phone', () => {
@@ -37,7 +37,7 @@ describe('the home on a phone', () => {
})
})
expect(html).toContain('<details class="gm-fold gm-fold-block" id="home-faq" open>')
expect(html).toContain('<details class="gm-fold gm-fold-block" id="home-faq" open>')
expect(html).toContain(
expect(html).toContain(
- '<summary><h2 id="home-faq">Questions</h2><span>tap to open</span></summary>',
+ '<summary><h2 id="home-faq">Questions</h2></summary>',
)
)
expect(html).toContain('the answers')
expect(html).toContain('the answers')
expect(html).toContain('document.getElementById("home-faq")')
expect(html).toContain('document.getElementById("home-faq")')
@@ -42,11 +42,27 @@ export function pickBlock(o: {
@@ -42,11 +42,27 @@ export function pickBlock(o: {
}
}
+/**
+ * What a fold holds, counted, for its title row (the owner, 2026-10-31: a fold that shortens a page shows its count):
+ * "6 questions", "12 items", "latest 5" for the shipped list, or nothing when there is nothing to count. Replaces the
+ * hint the fold used to show instead.
+ */
+export function foldMeta(body: string, cls = ''): string {
+ const s = String(body ?? '')
+ const n = (re: RegExp): number => (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)
+ const li = n(/<li[\s>]/g)
+ const 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>` : ''
+}
+
/**
/**
* A fold. The head is the heading the block had; the html is what it holds.
* A fold. The head is the heading the block had; the html is what it holds.
*/
*/
export function foldBlock(o: { id: string; head: string; html: string }): string {
export function foldBlock(o: { id: string; head: string; html: string }): string {
- return `<details class="gm-fold gm-fold-block" id="${esc(o.id)}" open><summary>${o.head}<span>tap to open</span></summary>${o.html}</details>${foldScript(o.id)}`
+ return `<details class="gm-fold gm-fold-block" id="${esc(o.id)}" open><summary>${o.head}${foldMeta(o.html)}</summary>${o.html}</details>${foldScript(o.id)}`
}
}
/** The script a fold carries: closed on a phone unless the reader opened it before, and it remembers that. */
/** The script a fold carries: closed on a phone unless the reader opened it before, and it remembers that. */