openvibers/openvibe.network Commits

Network home: what the network is now, no doubled periods, 1 tool (#213)

OP OpenVibers committed 29 days ago · 51fa13982b · 3 files, +9 −3

Final-refresh pass on openvibe.network's front door. A read of the live page found three things.

- **The hero line was from the network's first month:** "Live streaming, 170 online tools, chat, games, community pastes, a wiki, a blog and a shared media library". It now says what the network is: "Live streaming from a browser tab, 170 online tools, chat, games, a wiki and a blog; agents that do tasks for you; jobs, food help and places to rent; and the platform underneath, for anyone to build on." Going live from a browser stays first, per the headline rule.
- **Doubled periods.** The sites section joined `${tagline}. ${what}`, so a tagline that already ends a sentence got a second one: "What should we eat?.", "Many models, one API. Every answer explained..". This touched Food, Inventory, Events, AI, Search, Play and Zone. `asSentence()` now adds the period only when one is missing.
- **"1 tools"** on the YouTube and Pastes families is now "1 tool".

`test/home-front-door.test.js` asserts no doubled sentence end, no "1 tools", and that the hero still leads with going live from a browser.

Changes

ddiff --git a/public/index.html b/public/index.html
iindex 383595c0..e69aa77e 100644
---- a/public/index.html
++++ b/public/index.html
@@@ -198,7 +198,7 @@ footer{border-top:1px solid var(--border);background:var(--bg-secondary)}
<div class="hero-main">
<div class="hero-badge"><span class="ov-mark" data-size="20" data-variant="network"></span> The OpenVibe Network — open source, community run</div>
<h1>The open network<br><span class="grad">for what you do online.</span></h1>
-- <p class="sub">Live streaming, <!--OV:COUNT--> online tools, chat, games, community pastes, a wiki, a blog and a shared media library. Open source, run by the people who use it, and open to everyone without an account. Sign in once and every site already knows you.</p>
++ <p class="sub">Live streaming from a browser tab, <!--OV:COUNT--> online tools, chat, games, a wiki and a blog; agents that do tasks for you; jobs, food help and places to rent; and the platform underneath, for anyone to build on. Open source, run by the people who use it, and open to everyone without an account. Sign in once and every site already knows you.</p>
<form class="intent-bar" action="https://openvibe.tools/search" method="get" role="search">
<label for="intent-q" class="sr-only">What do you want to do?</label>
<i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
ddiff --git a/server/home/render.js b/server/home/render.js
iindex 7fefdcef..8188d8d4 100644
---- a/server/home/render.js
++++ b/server/home/render.js
@@@ -136,6 +136,8 @@ ${icons.CSS}`;
// The sites section's heading; the JSON-LD ItemList of the same sites carries it as its name, so the
// structured data names something a visitor can see (browser check, WS-Q task 3).
const sitesHeading = () => `${inWords(OPEN.length)} sites, one front door`;
++/** A tagline as the start of a sentence: a period only when it does not already end one ("What should we eat?"). */
++const asSentence = (t) => (/[.!?…]$/.test(String(t).trim()) ? String(t).trim() : `${String(t).trim()}.`);
// Markup inside a kit section after its grid (the kit closes the section itself); an empty section stays empty.
const inside = (section, extra) => (section && extra ? section.replace(/<\/section>$/, () => `${extra}</section>`) : section);
@@@ -151,12 +153,12 @@ function body(catalog, act) {
const sites = showcase.features({
id: 'network', title: sitesHeading(),
lede: 'Stream, chat, build, share, play, write and store. Everything is open to visitors; signing in once carries your name, theme and notifications to all of it.',
-- items: OPEN.map((site) => ({ icon: `ov:${site.icon}`, title: siteName(site), text: site.tagline ? `${site.tagline}. ${site.what}` : site.what, href: `https://${site.host}/` })),
++ items: OPEN.map((site) => ({ icon: `ov:${site.icon}`, title: siteName(site), text: site.tagline ? `${asSentence(site.tagline)} ${site.what}` : site.what, href: `https://${site.host}/` })),
});
const tools = inside(showcase.features({
id: 'tools', title: catalog.tools.length ? `${catalog.tools.length} tools that just open` : 'Tools that just open',
lede: 'No installs and no sign-up wall. Every tool has its own short address, so yt.openvibe.tools or dns.openvibe.tools takes you straight there.',
-- items: fams.length ? fams.map((f) => ({ icon: `ov:${f.icon}`, title: f.name, text: `${count(f)} tools · ${f.tagline || ''}`, href: f.path ? `https://openvibe.tools${f.path}` : f.url }))
++ items: fams.length ? fams.map((f) => ({ icon: `ov:${f.icon}`, title: f.name, text: `${count(f)} ${count(f) === 1 ? 'tool' : 'tools'} · ${f.tagline || ''}`, href: f.path ? `https://openvibe.tools${f.path}` : f.url }))
: [{ icon: 'ov:tools', title: 'OpenVibe.Tools', text: 'Converters, downloaders, PDF and image tools, developer utilities and network diagnostics.', href: 'https://openvibe.tools/' }],
}), `${chips(popular.map((t) => [t.url, t.tagline || '', t.icon, t.name]))}<p class="home-more"><a href="https://openvibe.tools/">Browse every tool at openvibe.tools →</a> · <a href="https://yt.openvibe.tools/">yt.openvibe.tools</a> · <a href="https://dns.openvibe.tools/">dns.openvibe.tools</a></p>`);
const account = showcase.features({
ddiff --git a/test/home-front-door.test.js b/test/home-front-door.test.js
iindex ed4b0df4..7e10c8d8 100644
---- a/test/home-front-door.test.js
++++ b/test/home-front-door.test.js
@@@ -55,6 +55,10 @@ assert.ok(!/class="home-(sec|card|grid|fams|fam|dev)\b/.test(html), 'no hand-bui
assert.strictEqual((html.match(/<h1[\s>]/g) || []).length, 1, 'one h1: the hero');
assert.match(html, /<meta name="ai-summary" content="One account for \d+ open sites \(live, /);
assert.ok(/"@type":"WebPage"/.test(html), 'the summary has its WebPage JSON-LD');
++// A tagline that already ends a sentence ("What should we eat?") gets no second period; a family of one is "1 tool".
++assert.ok(!/[.?!]\. /.test(html.replace(/<[^>]+>/g, ' ')), 'no doubled sentence end after a site tagline');
++assert.ok(!/\b1 tools\b/.test(html), 'one tool is "1 tool"');
++assert.ok(/Live streaming from a browser tab, /.test(html), 'the hero line still leads with going live from a browser');
for (const s of open) assert.ok(html.includes(`<a class="sc-card" href="https://${s.host}/">`), `the sites section links ${s.host}`);
for (const href of ['https://openvibe.tools/api/catalog.json', '/llms.txt', 'https://openvibe.tools/llms.txt', 'https://github.com/OpenVibers', 'https://openvibe.codes/', 'https://yt.openvibe.tools/', 'https://dns.openvibe.tools/']) assert.ok(html.includes(`href="${href}"`), `the page still links ${href}`);
assert.strictEqual((html.match(/<section[\s>]/g) || []).length, (html.match(/<\/section>/g) || []).length, 'every section is closed once');