openvibers/openvibe.network Commits
sites: the hub carries the network share card (#411)
Changes
@@@ -17,6 +17,9 @@ const openSites = (list = SITES) => list.filter((site) => site.status === 'open'// account and themes behind every other one).const groupsOf = (sites) => GROUPS.map((group) => ({ group, sites: sites.filter((site) => groupOf(site.id) === group.id), also: PRODUCTS.filter((p) => groupOf(p.id) === group.id) })).filter((x) => x.sites.length);++// The network's own share card, the same one the home pages carry (an indexable page without og:image is the one++// thing the SEO audit still finds on this page).++const shareCard = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared') || 'https://openvibe.network/assets/logo-512.png';const card = (site) => `<a class="sc-card" id="${esc(site.id)}" href="https://${esc(site.host)}/"><span class="sc-ic sc-ic-ov"><span class="ov-icon sc-ovi" data-icon="${esc(site.icon)}" style="--ovi-size:40px" aria-hidden="true">${icons.svg(site.icon)}</span></span><span><b>${esc(siteName(site))}</b><small>${esc(siteLine(site))}</small></span></a>`;function render({ releaseId = '', sites = SITES } = {}) {@@@ -47,6 +50,8 @@ function render({ releaseId = '', sites = SITES } = {}) {<meta name="robots" content="index, follow"><link rel="canonical" href="https://openvibe.network/sites"><meta property="og:title" content="${esc(title)}"><meta property="og:description" content="${esc(desc)}"><meta property="og:type" content="website"><meta property="og:url" content="https://openvibe.network/sites">++<meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${esc(shareCard)}">++<meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="${esc(title)}"><meta name="twitter:description" content="${esc(desc)}"><meta name="twitter:image" content="${esc(shareCard)}">${require('../boost').meta(releaseId)}${require('openvibe-shared/app-icon').headTags({ site: 'network', iconBase: '/assets' })}<meta name="color-scheme" content="dark light">@@@ -93,6 +93,8 @@ const cache = require('openvibe-shared/cache-policy');assert.ok(/<meta name="robots" content="index,\s*follow">/.test(hubHead), '/sites says index, follow');assert.ok(hubHead.includes(`<title>All ${openSites.length} OpenVibe sites · OpenVibe.Network</title>`), 'the title carries the real count');assert.ok(/<meta name="description" content="[^"]{50,170}">/.test(hubHead), '/sites has a real description');++ assert.ok(/<meta property="og:image" content="https:\/\/openvibe\.network\/shared\/social\/network\.jpg\?v=/.test(hubHead), '/sites carries the network share card (an indexable page without og:image is an audit finding)');++ assert.ok(/<meta name="twitter:card" content="summary_large_image">/.test(hubHead), '/sites has a large share card');const hubLd = JSON.parse(hub.body.match(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/)[1]);assert.strictEqual(hubLd['@type'], 'CollectionPage', 'the JSON-LD is a CollectionPage');assert.strictEqual(hubLd.mainEntity['@type'], 'ItemList', 'with an ItemList');
@@ -17,6 +17,9 @@ const openSites = (list = SITES) => list.filter((site) => site.status === 'open'
@@ -17,6 +17,9 @@ const openSites = (list = SITES) => list.filter((site) => site.status === 'open'
// account and themes behind every other one).
// account and themes behind every other one).
const groupsOf = (sites) => GROUPS.map((group) => ({ group, sites: sites.filter((site) => groupOf(site.id) === group.id), also: PRODUCTS.filter((p) => groupOf(p.id) === group.id) })).filter((x) => x.sites.length);
const groupsOf = (sites) => GROUPS.map((group) => ({ group, sites: sites.filter((site) => groupOf(site.id) === group.id), also: PRODUCTS.filter((p) => groupOf(p.id) === group.id) })).filter((x) => x.sites.length);
+// The network's own share card, the same one the home pages carry (an indexable page without og:image is the one
+// thing the SEO audit still finds on this page).
+const shareCard = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared') || 'https://openvibe.network/assets/logo-512.png';
const card = (site) => `<a class="sc-card" id="${esc(site.id)}" href="https://${esc(site.host)}/"><span class="sc-ic sc-ic-ov"><span class="ov-icon sc-ovi" data-icon="${esc(site.icon)}" style="--ovi-size:40px" aria-hidden="true">${icons.svg(site.icon)}</span></span><span><b>${esc(siteName(site))}</b><small>${esc(siteLine(site))}</small></span></a>`;
const card = (site) => `<a class="sc-card" id="${esc(site.id)}" href="https://${esc(site.host)}/"><span class="sc-ic sc-ic-ov"><span class="ov-icon sc-ovi" data-icon="${esc(site.icon)}" style="--ovi-size:40px" aria-hidden="true">${icons.svg(site.icon)}</span></span><span><b>${esc(siteName(site))}</b><small>${esc(siteLine(site))}</small></span></a>`;
function render({ releaseId = '', sites = SITES } = {}) {
function render({ releaseId = '', sites = SITES } = {}) {
@@ -47,6 +50,8 @@ function render({ releaseId = '', sites = SITES } = {}) {
@@ -47,6 +50,8 @@ function render({ releaseId = '', sites = SITES } = {}) {
<meta name="robots" content="index, follow">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://openvibe.network/sites">
<link rel="canonical" href="https://openvibe.network/sites">
<meta property="og:title" content="${esc(title)}"><meta property="og:description" content="${esc(desc)}"><meta property="og:type" content="website"><meta property="og:url" content="https://openvibe.network/sites">
<meta property="og:title" content="${esc(title)}"><meta property="og:description" content="${esc(desc)}"><meta property="og:type" content="website"><meta property="og:url" content="https://openvibe.network/sites">
+<meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${esc(shareCard)}">
+<meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="${esc(title)}"><meta name="twitter:description" content="${esc(desc)}"><meta name="twitter:image" content="${esc(shareCard)}">
${require('../boost').meta(releaseId)}
${require('../boost').meta(releaseId)}
${require('openvibe-shared/app-icon').headTags({ site: 'network', iconBase: '/assets' })}
${require('openvibe-shared/app-icon').headTags({ site: 'network', iconBase: '/assets' })}
<meta name="color-scheme" content="dark light">
<meta name="color-scheme" content="dark light">
@@ -93,6 +93,8 @@ const cache = require('openvibe-shared/cache-policy');
@@ -93,6 +93,8 @@ const cache = require('openvibe-shared/cache-policy');
assert.ok(/<meta name="robots" content="index,\s*follow">/.test(hubHead), '/sites says index, follow');
assert.ok(/<meta name="robots" content="index,\s*follow">/.test(hubHead), '/sites says index, follow');
assert.ok(hubHead.includes(`<title>All ${openSites.length} OpenVibe sites · OpenVibe.Network</title>`), 'the title carries the real count');
assert.ok(hubHead.includes(`<title>All ${openSites.length} OpenVibe sites · OpenVibe.Network</title>`), 'the title carries the real count');
assert.ok(/<meta name="description" content="[^"]{50,170}">/.test(hubHead), '/sites has a real description');
assert.ok(/<meta name="description" content="[^"]{50,170}">/.test(hubHead), '/sites has a real description');
+ assert.ok(/<meta property="og:image" content="https:\/\/openvibe\.network\/shared\/social\/network\.jpg\?v=/.test(hubHead), '/sites carries the network share card (an indexable page without og:image is an audit finding)');
+ assert.ok(/<meta name="twitter:card" content="summary_large_image">/.test(hubHead), '/sites has a large share card');
const hubLd = JSON.parse(hub.body.match(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/)[1]);
const hubLd = JSON.parse(hub.body.match(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/)[1]);
assert.strictEqual(hubLd['@type'], 'CollectionPage', 'the JSON-LD is a CollectionPage');
assert.strictEqual(hubLd['@type'], 'CollectionPage', 'the JSON-LD is a CollectionPage');
assert.strictEqual(hubLd.mainEntity['@type'], 'ItemList', 'with an ItemList');
assert.strictEqual(hubLd.mainEntity['@type'], 'ItemList', 'with an ItemList');