openvibers/openvibe.blog Commits
The week becomes a fold, so the home fits under four screens (#141)
Changes
@@@ -141,7 +141,7 @@ function createPublicRoutes(ctx) {jsonLd: [blogLd, ...homePage.homeJsonLd({ base: config.baseUrl.replace(/\/+$/, ''), items })],styles: [showcase.STYLESHEET], bodyClass: 'blog-home',// The rule that shows the picked item of each pick list: one per item, written for this page.-- inlineStyles: [`@supports selector(:has(*)){@media (max-width:640px){${pickListRules('week', week.length)}${pickListRules('desks', deskCount)}}}`],++ inlineStyles: [`@supports selector(:has(*)){@media (max-width:640px){${pickListRules('desks', deskCount)}}}`],body: homePage.homeBody({ blog, items, pager, feeds, stats, week, latestDesks, tags, series: seriesCounts, memberItems, signedIn: req.viewer.kind === 'user' })// The shipped list is a part a reader rarely needs: a fold on a phone, the section it was where there is room.+ foldBlock({ id: 'shipped', head: '<h2 id="bh-shipped-h">Recently shipped on OpenVibe.Blog</h2>', html: frame.shipped({ service: 'blog', title: 'Recently shipped on OpenVibe.Blog' }) }),@@@ -71,14 +71,12 @@ function homeBody(o) {${blog.description ? h`<p class="sc-lede">${blog.description}</p>` : ''}${feeds.length ? h`<p class="feeds">Follow: ${feeds.map((f) => h`<a href="${f.href}" type="${f.mime}">${f.label}</a> `)}</p>` : ''}${items.length ? h`<ol class="bh-cards">${items.map(postCard)}</ol>${raw(ssr.paginationHtml(pager))}<p class="bh-more bh-all"><a href="/@${blog.handle}">Every post, newest first</a></p>` : h`<p class="empty">Nothing published here yet.</p>`}</section>--${week.length ? raw(pickList({-- key: 'week',-- label: 'This week across OpenVibe',-- head: 'This week across OpenVibe',-- labels: week.map((w) => siteName(w.service)),-- html: h`<section class="sc-sec bh-sec" aria-labelledby="bh-week-h"><h2 id="bh-week-h">This week across OpenVibe</h2>++${week.length ? raw(foldBlock({++ id: 'week',++ head: '<h2 id="bh-week-h">This week across OpenVibe</h2>',++ html: h`<section class="sc-sec bh-sec" aria-labelledby="bh-week-h"><h2>This week across OpenVibe</h2><p class="sc-lede">${plural(stats.weekChanges, 'change')} shipped to ${plural(stats.weekSites, 'site')} in the last seven days. Patch notes on this blog round them up.</p>--<ol class="bh-bars pick-list">${week.map((w, i) => h`<li data-i="${i}"><a href="https://openvibe.network/updates?site=${encodeURIComponent(w.service)}">${siteName(w.service)}</a><span class="bh-bar" aria-hidden="true"><span style="width:${String(Math.max(2, Math.round((w.changes / top) * 100)))}%"></span></span><span class="bh-n">${plural(w.changes, 'change')}</span></li>`)}</ol>++<ol class="bh-bars">${week.map((w) => h`<li><a href="https://openvibe.network/updates?site=${encodeURIComponent(w.service)}">${siteName(w.service)}</a><span class="bh-bar" aria-hidden="true"><span style="width:${String(Math.max(2, Math.round((w.changes / top) * 100)))}%"></span></span><span class="bh-n">${plural(w.changes, 'change')}</span></li>`)}</ol><p class="bh-more"><a href="https://openvibe.network/updates">Every change, as it ships</a>${series.length ? h` · <a href="${series[0].url}">${series[0].title}</a>` : ''}</p></section>`,})) : ''}${desks.length ? raw(pickList({@@@ -1,9 +1,4 @@'use strict';--/**-- * The home on a phone (the owner's short-pages rule, 2026-10-30): the lists of the same kind are one pick block, a-- * row of chips picks one of them, and the parts a reader rarely needs are folds. Radio inputs and :has(), no script-- * for the chips; every item stays in the page for crawlers; a wider screen shows them all and no chips.-- */const assert = require('assert');const { boot, check, done } = require('./helpers/boot');@@@ -17,64 +12,49 @@ const { boot, check, done } = require('./helpers/boot');const entry = db.prepare('INSERT INTO changelog_entries (service, repo, sha, subject, deployed_at, release) VALUES (?, ?, ?, ?, ?, ?)');await entry.run('live', 'OpenVibers/live', 'sha1', 'change 1', iso(now - 86400_000), 'r1');await entry.run('wiki', 'OpenVibers/wiki', 'sha2', 'change 2', iso(now - 2 * 86400_000), 'r1');-- await entry.run('news', 'OpenVibers/news', 'sha3', 'change 3', iso(now - 3 * 86400_000), 'r1');const desk = db.prepare('INSERT INTO blog_desk_posts (id, desk, slug, status, title, dek, period_from, period_to, created_at, published_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');await desk.run('dp_news', 'news', 'headlines-oct-21', 'published', 'Headlines of Oct 21', 'What governments announced.', now - 2 * 86400_000, now - 86400_000, now, now, now);await desk.run('dp_satire', 'satire', 'too-many-vibes', 'published', 'Is it possible to take too many vibes?', 'A sober inquiry.', now - 86400_000, now, now, now, now);const post = await t.get('/api/v1/blogs/openvibe/posts', { as: t.official, json: { body: 'A letter from the team.\n\nThe network ships.', title: 'A letter from the team', tags: 'live,patch-notes' } });assert.strictEqual(post.status, 201, post.text);-- await t.get(`/api/v1/posts/${post.json().post.id}/publish`, { as: t.official, json: {} });++ await t.get('/api/v1/posts/' + post.json().post.id + '/publish', { as: t.official, json: {} });});-- await check('the week is one pick block: a chip per site, the first picked, every site in the page', async () => {++ await check('the AI desks are a pick block: a chip per desk, the first picked, every desk in the page', async () => {const r = await t.get('/');assert.strictEqual(r.status, 200, r.text);const page = r.text;-- const start = page.indexOf('<div class="pick" id="pick-week">');-- assert.ok(start > 0, 'the pick block is on the home');-- const block = page.slice(start, page.indexOf('<div class="pick" id="pick-desks">'));-- assert.match(block, /<div class="pick-row" role="radiogroup" aria-label="This week across OpenVibe">/);-- const chips = [...block.matchAll(/<input type="radio" name="pick-week" id="pk-week-(\d+)" value="\1"( checked)?><label for="pk-week-\1">([^<]+)<\/label>/g)];-- assert.ok(chips.length >= 1, `a chip per site (${chips.length})`);-- assert.deepStrictEqual(chips.filter((m) => m[2]).map((m) => m[1]), [chips[0][1]], 'the first site is picked');-- // Every site stays in the page, with the index its chip picks.-- const bars = [...block.matchAll(/<li data-i="(\d+)"><a href="https:\/\/openvibe.network\/updates/g)];-- assert.strictEqual(bars.length, chips.length, 'every site is in the page');-- assert.deepStrictEqual(bars.map((m) => m[1]), chips.map((m) => m[1]), 'each site knows its chip');-- });---- await check('the AI desks are a pick block too: a chip per desk, every desk in the page', async () => {-- const r = await t.get('/');-- const page = r.text;const start = page.indexOf('<div class="pick" id="pick-desks">');-- assert.ok(start > 0, 'the desks are a pick block');++ assert.ok(start > 0, 'the desks are a pick block on the home');const block = page.slice(start, start + 6000);++ assert.match(block, /<div class="pick-row" role="radiogroup" aria-label="From the AI desks">/);const chips = [...block.matchAll(/<input type="radio" name="pick-desks" id="pk-desks-(\d+)" value="\1"( checked)?><label for="pk-desks-\1">([^<]+)<\/label>/g)];-- assert.ok(chips.length >= 1, `a chip per desk (${chips.length})`);++ assert.ok(chips.length >= 1, 'a chip per desk (' + chips.length + ')');assert.deepStrictEqual(chips.filter((m) => m[2]).map((m) => m[1]), [chips[0][1]], 'the first desk is picked');const desks = [...block.matchAll(/<li data-i="(\d+)"><p class="bh-desk">/g)];assert.strictEqual(desks.length, chips.length, 'every desk is in the page');++ assert.deepStrictEqual(desks.map((m) => m[1]), chips.map((m) => m[1]), 'each desk knows its chip');});-- await check('the CSS guard: the chips are hidden and the items all show until 640 px and where :has() is understood', async () => {++ await check('the CSS guard: the chips are hidden and the desks all show until 640 px and where :has() is understood', async () => {const r = await t.get('/');const page = r.text;-- assert.match(page, /<style>@supports selector\(:has\(\*\)\)\{@media \(max-width:640px\)\{\.pick#pick-week:has\(#pk-week-0:checked\) \.pick-list>li\[data-i="0"\]\{display:block\}/, 'the rule that shows the picked item');++ assert.match(page, /<style>@supports selector\(:has\(\*\)\)\{@media \(max-width:640px\)\{\.pick#pick-desks:has\(#pk-desks-0:checked\) \.pick-list>li\[data-i="0"\]\{display:block\}/, 'the rule that shows the picked desk');const css = require('fs').readFileSync(require('path').join(__dirname, '..', 'public', 'css', 'blog.css'), 'utf8');assert.match(css, /\.pick-row \{ display: none; \}/, 'the chips are hidden by default');assert.match(css, /@supports selector\(:has\(\*\)\) \{ @media \(max-width: 640px\) \{/, 'the phone rules are under :has() and 640 px');assert.match(css, /\.pick-row label \{[^}]*min-height: 44px/, 'a chip is a 44 px target');-- assert.match(css, /\.pick \.pick-list > li \{ display: none; \}/, 'the items are hidden on a phone');++ assert.match(css, /\.pick \.pick-list > li \{ display: none; \}/, 'the desks are hidden on a phone');});await check('the parts a reader rarely needs are folds, open in the page and closed on a phone', async () => {const r = await t.get('/');const page = r.text;-- for (const id of ['topics', 'faq', 'shipped']) {-- assert.ok(page.includes(`<details class="bl-fold bl-fold-block" id="${id}" open>`), `${id} is a fold, open in the page`);-- assert.ok(page.includes(`document.getElementById("${id}")`), `${id} has the script that closes it on a phone`);++ for (const id of ['week', 'topics', 'faq', 'shipped']) {++ assert.ok(page.includes('<details class="bl-fold bl-fold-block" id="' + id + '" open>'), id + ' is a fold, open in the page');++ assert.ok(page.includes('document.getElementById("' + id + '")'), id + ' has the script that closes it on a phone');}-- // The content of the folds stays in the page.++ assert.match(page, /<h2 id="bh-week-h">This week across OpenVibe<\/h2>/);assert.match(page, /<h2 id="bh-tags-h">Topics<\/h2>/);assert.match(page, /<h2 id="bh-faq-h">Questions<\/h2>/);assert.match(page, /<h2 id="bh-shipped-h">Recently shipped on OpenVibe.Blog<\/h2>/);
@@ -141,7 +141,7 @@ function createPublicRoutes(ctx) {
@@ -141,7 +141,7 @@ function createPublicRoutes(ctx) {
jsonLd: [blogLd, ...homePage.homeJsonLd({ base: config.baseUrl.replace(/\/+$/, ''), items })],
jsonLd: [blogLd, ...homePage.homeJsonLd({ base: config.baseUrl.replace(/\/+$/, ''), items })],
styles: [showcase.STYLESHEET], bodyClass: 'blog-home',
styles: [showcase.STYLESHEET], bodyClass: 'blog-home',
// The rule that shows the picked item of each pick list: one per item, written for this page.
// The rule that shows the picked item of each pick list: one per item, written for this page.
- inlineStyles: [`@supports selector(:has(*)){@media (max-width:640px){${pickListRules('week', week.length)}${pickListRules('desks', deskCount)}}}`],
+ inlineStyles: [`@supports selector(:has(*)){@media (max-width:640px){${pickListRules('desks', deskCount)}}}`],
body: homePage.homeBody({ blog, items, pager, feeds, stats, week, latestDesks, tags, series: seriesCounts, memberItems, signedIn: req.viewer.kind === 'user' })
body: homePage.homeBody({ blog, items, pager, feeds, stats, week, latestDesks, tags, series: seriesCounts, memberItems, signedIn: req.viewer.kind === 'user' })
// The shipped list is a part a reader rarely needs: a fold on a phone, the section it was where there is room.
// The shipped list is a part a reader rarely needs: a fold on a phone, the section it was where there is room.
+ foldBlock({ id: 'shipped', head: '<h2 id="bh-shipped-h">Recently shipped on OpenVibe.Blog</h2>', html: frame.shipped({ service: 'blog', title: 'Recently shipped on OpenVibe.Blog' }) }),
+ foldBlock({ id: 'shipped', head: '<h2 id="bh-shipped-h">Recently shipped on OpenVibe.Blog</h2>', html: frame.shipped({ service: 'blog', title: 'Recently shipped on OpenVibe.Blog' }) }),
@@ -71,14 +71,12 @@ function homeBody(o) {
@@ -71,14 +71,12 @@ function homeBody(o) {
${blog.description ? h`<p class="sc-lede">${blog.description}</p>` : ''}
${blog.description ? h`<p class="sc-lede">${blog.description}</p>` : ''}
${feeds.length ? h`<p class="feeds">Follow: ${feeds.map((f) => h`<a href="${f.href}" type="${f.mime}">${f.label}</a> `)}</p>` : ''}
${feeds.length ? h`<p class="feeds">Follow: ${feeds.map((f) => h`<a href="${f.href}" type="${f.mime}">${f.label}</a> `)}</p>` : ''}
${items.length ? h`<ol class="bh-cards">${items.map(postCard)}</ol>${raw(ssr.paginationHtml(pager))}<p class="bh-more bh-all"><a href="/@${blog.handle}">Every post, newest first</a></p>` : h`<p class="empty">Nothing published here yet.</p>`}</section>
${items.length ? h`<ol class="bh-cards">${items.map(postCard)}</ol>${raw(ssr.paginationHtml(pager))}<p class="bh-more bh-all"><a href="/@${blog.handle}">Every post, newest first</a></p>` : h`<p class="empty">Nothing published here yet.</p>`}</section>
-${week.length ? raw(pickList({
- key: 'week',
- label: 'This week across OpenVibe',
- head: 'This week across OpenVibe',
- labels: week.map((w) => siteName(w.service)),
- html: h`<section class="sc-sec bh-sec" aria-labelledby="bh-week-h"><h2 id="bh-week-h">This week across OpenVibe</h2>
+${week.length ? raw(foldBlock({
+ id: 'week',
+ head: '<h2 id="bh-week-h">This week across OpenVibe</h2>',
+ html: h`<section class="sc-sec bh-sec" aria-labelledby="bh-week-h"><h2>This week across OpenVibe</h2>
<p class="sc-lede">${plural(stats.weekChanges, 'change')} shipped to ${plural(stats.weekSites, 'site')} in the last seven days. Patch notes on this blog round them up.</p>
<p class="sc-lede">${plural(stats.weekChanges, 'change')} shipped to ${plural(stats.weekSites, 'site')} in the last seven days. Patch notes on this blog round them up.</p>
-<ol class="bh-bars pick-list">${week.map((w, i) => h`<li data-i="${i}"><a href="https://openvibe.network/updates?site=${encodeURIComponent(w.service)}">${siteName(w.service)}</a><span class="bh-bar" aria-hidden="true"><span style="width:${String(Math.max(2, Math.round((w.changes / top) * 100)))}%"></span></span><span class="bh-n">${plural(w.changes, 'change')}</span></li>`)}</ol>
+<ol class="bh-bars">${week.map((w) => h`<li><a href="https://openvibe.network/updates?site=${encodeURIComponent(w.service)}">${siteName(w.service)}</a><span class="bh-bar" aria-hidden="true"><span style="width:${String(Math.max(2, Math.round((w.changes / top) * 100)))}%"></span></span><span class="bh-n">${plural(w.changes, 'change')}</span></li>`)}</ol>
<p class="bh-more"><a href="https://openvibe.network/updates">Every change, as it ships</a>${series.length ? h` · <a href="${series[0].url}">${series[0].title}</a>` : ''}</p></section>`,
<p class="bh-more"><a href="https://openvibe.network/updates">Every change, as it ships</a>${series.length ? h` · <a href="${series[0].url}">${series[0].title}</a>` : ''}</p></section>`,
})) : ''}
})) : ''}
${desks.length ? raw(pickList({
${desks.length ? raw(pickList({
@@ -1,9 +1,4 @@
@@ -1,9 +1,4 @@
'use strict';
'use strict';
-/**
- * The home on a phone (the owner's short-pages rule, 2026-10-30): the lists of the same kind are one pick block, a
- * row of chips picks one of them, and the parts a reader rarely needs are folds. Radio inputs and :has(), no script
- * for the chips; every item stays in the page for crawlers; a wider screen shows them all and no chips.
- */
const assert = require('assert');
const assert = require('assert');
const { boot, check, done } = require('./helpers/boot');
const { boot, check, done } = require('./helpers/boot');
@@ -17,64 +12,49 @@ const { boot, check, done } = require('./helpers/boot');
@@ -17,64 +12,49 @@ const { boot, check, done } = require('./helpers/boot');
const entry = db.prepare('INSERT INTO changelog_entries (service, repo, sha, subject, deployed_at, release) VALUES (?, ?, ?, ?, ?, ?)');
const entry = db.prepare('INSERT INTO changelog_entries (service, repo, sha, subject, deployed_at, release) VALUES (?, ?, ?, ?, ?, ?)');
await entry.run('live', 'OpenVibers/live', 'sha1', 'change 1', iso(now - 86400_000), 'r1');
await entry.run('live', 'OpenVibers/live', 'sha1', 'change 1', iso(now - 86400_000), 'r1');
await entry.run('wiki', 'OpenVibers/wiki', 'sha2', 'change 2', iso(now - 2 * 86400_000), 'r1');
await entry.run('wiki', 'OpenVibers/wiki', 'sha2', 'change 2', iso(now - 2 * 86400_000), 'r1');
- await entry.run('news', 'OpenVibers/news', 'sha3', 'change 3', iso(now - 3 * 86400_000), 'r1');
const desk = db.prepare('INSERT INTO blog_desk_posts (id, desk, slug, status, title, dek, period_from, period_to, created_at, published_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
const desk = db.prepare('INSERT INTO blog_desk_posts (id, desk, slug, status, title, dek, period_from, period_to, created_at, published_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
await desk.run('dp_news', 'news', 'headlines-oct-21', 'published', 'Headlines of Oct 21', 'What governments announced.', now - 2 * 86400_000, now - 86400_000, now, now, now);
await desk.run('dp_news', 'news', 'headlines-oct-21', 'published', 'Headlines of Oct 21', 'What governments announced.', now - 2 * 86400_000, now - 86400_000, now, now, now);
await desk.run('dp_satire', 'satire', 'too-many-vibes', 'published', 'Is it possible to take too many vibes?', 'A sober inquiry.', now - 86400_000, now, now, now, now);
await desk.run('dp_satire', 'satire', 'too-many-vibes', 'published', 'Is it possible to take too many vibes?', 'A sober inquiry.', now - 86400_000, now, now, now, now);
const post = await t.get('/api/v1/blogs/openvibe/posts', { as: t.official, json: { body: 'A letter from the team.\n\nThe network ships.', title: 'A letter from the team', tags: 'live,patch-notes' } });
const post = await t.get('/api/v1/blogs/openvibe/posts', { as: t.official, json: { body: 'A letter from the team.\n\nThe network ships.', title: 'A letter from the team', tags: 'live,patch-notes' } });
assert.strictEqual(post.status, 201, post.text);
assert.strictEqual(post.status, 201, post.text);
- await t.get(`/api/v1/posts/${post.json().post.id}/publish`, { as: t.official, json: {} });
+ await t.get('/api/v1/posts/' + post.json().post.id + '/publish', { as: t.official, json: {} });
});
});
- await check('the week is one pick block: a chip per site, the first picked, every site in the page', async () => {
+ await check('the AI desks are a pick block: a chip per desk, the first picked, every desk in the page', async () => {
const r = await t.get('/');
const r = await t.get('/');
assert.strictEqual(r.status, 200, r.text);
assert.strictEqual(r.status, 200, r.text);
const page = r.text;
const page = r.text;
- const start = page.indexOf('<div class="pick" id="pick-week">');
- assert.ok(start > 0, 'the pick block is on the home');
- const block = page.slice(start, page.indexOf('<div class="pick" id="pick-desks">'));
- assert.match(block, /<div class="pick-row" role="radiogroup" aria-label="This week across OpenVibe">/);
- const chips = [...block.matchAll(/<input type="radio" name="pick-week" id="pk-week-(\d+)" value="\1"( checked)?><label for="pk-week-\1">([^<]+)<\/label>/g)];
- assert.ok(chips.length >= 1, `a chip per site (${chips.length})`);
- assert.deepStrictEqual(chips.filter((m) => m[2]).map((m) => m[1]), [chips[0][1]], 'the first site is picked');
- // Every site stays in the page, with the index its chip picks.
- const bars = [...block.matchAll(/<li data-i="(\d+)"><a href="https:\/\/openvibe.network\/updates/g)];
- assert.strictEqual(bars.length, chips.length, 'every site is in the page');
- assert.deepStrictEqual(bars.map((m) => m[1]), chips.map((m) => m[1]), 'each site knows its chip');
- });
-
- await check('the AI desks are a pick block too: a chip per desk, every desk in the page', async () => {
- const r = await t.get('/');
- const page = r.text;
const start = page.indexOf('<div class="pick" id="pick-desks">');
const start = page.indexOf('<div class="pick" id="pick-desks">');
- assert.ok(start > 0, 'the desks are a pick block');
+ assert.ok(start > 0, 'the desks are a pick block on the home');
const block = page.slice(start, start + 6000);
const block = page.slice(start, start + 6000);
+ assert.match(block, /<div class="pick-row" role="radiogroup" aria-label="From the AI desks">/);
const chips = [...block.matchAll(/<input type="radio" name="pick-desks" id="pk-desks-(\d+)" value="\1"( checked)?><label for="pk-desks-\1">([^<]+)<\/label>/g)];
const chips = [...block.matchAll(/<input type="radio" name="pick-desks" id="pk-desks-(\d+)" value="\1"( checked)?><label for="pk-desks-\1">([^<]+)<\/label>/g)];
- assert.ok(chips.length >= 1, `a chip per desk (${chips.length})`);
+ assert.ok(chips.length >= 1, 'a chip per desk (' + chips.length + ')');
assert.deepStrictEqual(chips.filter((m) => m[2]).map((m) => m[1]), [chips[0][1]], 'the first desk is picked');
assert.deepStrictEqual(chips.filter((m) => m[2]).map((m) => m[1]), [chips[0][1]], 'the first desk is picked');
const desks = [...block.matchAll(/<li data-i="(\d+)"><p class="bh-desk">/g)];
const desks = [...block.matchAll(/<li data-i="(\d+)"><p class="bh-desk">/g)];
assert.strictEqual(desks.length, chips.length, 'every desk is in the page');
assert.strictEqual(desks.length, chips.length, 'every desk is in the page');
+ assert.deepStrictEqual(desks.map((m) => m[1]), chips.map((m) => m[1]), 'each desk knows its chip');
});
});
- await check('the CSS guard: the chips are hidden and the items all show until 640 px and where :has() is understood', async () => {
+ await check('the CSS guard: the chips are hidden and the desks all show until 640 px and where :has() is understood', async () => {
const r = await t.get('/');
const r = await t.get('/');
const page = r.text;
const page = r.text;
- assert.match(page, /<style>@supports selector\(:has\(\*\)\)\{@media \(max-width:640px\)\{\.pick#pick-week:has\(#pk-week-0:checked\) \.pick-list>li\[data-i="0"\]\{display:block\}/, 'the rule that shows the picked item');
+ assert.match(page, /<style>@supports selector\(:has\(\*\)\)\{@media \(max-width:640px\)\{\.pick#pick-desks:has\(#pk-desks-0:checked\) \.pick-list>li\[data-i="0"\]\{display:block\}/, 'the rule that shows the picked desk');
const css = require('fs').readFileSync(require('path').join(__dirname, '..', 'public', 'css', 'blog.css'), 'utf8');
const css = require('fs').readFileSync(require('path').join(__dirname, '..', 'public', 'css', 'blog.css'), 'utf8');
assert.match(css, /\.pick-row \{ display: none; \}/, 'the chips are hidden by default');
assert.match(css, /\.pick-row \{ display: none; \}/, 'the chips are hidden by default');
assert.match(css, /@supports selector\(:has\(\*\)\) \{ @media \(max-width: 640px\) \{/, 'the phone rules are under :has() and 640 px');
assert.match(css, /@supports selector\(:has\(\*\)\) \{ @media \(max-width: 640px\) \{/, 'the phone rules are under :has() and 640 px');
assert.match(css, /\.pick-row label \{[^}]*min-height: 44px/, 'a chip is a 44 px target');
assert.match(css, /\.pick-row label \{[^}]*min-height: 44px/, 'a chip is a 44 px target');
- assert.match(css, /\.pick \.pick-list > li \{ display: none; \}/, 'the items are hidden on a phone');
+ assert.match(css, /\.pick \.pick-list > li \{ display: none; \}/, 'the desks are hidden on a phone');
});
});
await check('the parts a reader rarely needs are folds, open in the page and closed on a phone', async () => {
await check('the parts a reader rarely needs are folds, open in the page and closed on a phone', async () => {
const r = await t.get('/');
const r = await t.get('/');
const page = r.text;
const page = r.text;
- for (const id of ['topics', 'faq', 'shipped']) {
- assert.ok(page.includes(`<details class="bl-fold bl-fold-block" id="${id}" open>`), `${id} is a fold, open in the page`);
- assert.ok(page.includes(`document.getElementById("${id}")`), `${id} has the script that closes it on a phone`);
+ for (const id of ['week', 'topics', 'faq', 'shipped']) {
+ assert.ok(page.includes('<details class="bl-fold bl-fold-block" id="' + id + '" open>'), id + ' is a fold, open in the page');
+ assert.ok(page.includes('document.getElementById("' + id + '")'), id + ' has the script that closes it on a phone');
}
}
- // The content of the folds stays in the page.
+ assert.match(page, /<h2 id="bh-week-h">This week across OpenVibe<\/h2>/);
assert.match(page, /<h2 id="bh-tags-h">Topics<\/h2>/);
assert.match(page, /<h2 id="bh-tags-h">Topics<\/h2>/);
assert.match(page, /<h2 id="bh-faq-h">Questions<\/h2>/);
assert.match(page, /<h2 id="bh-faq-h">Questions<\/h2>/);
assert.match(page, /<h2 id="bh-shipped-h">Recently shipped on OpenVibe.Blog<\/h2>/);
assert.match(page, /<h2 id="bh-shipped-h">Recently shipped on OpenVibe.Blog<\/h2>/);