openvibers/openvibe.network Commits

The network's share card on /login, the account hub, /updates and /status (SEO-21) (#545)

OP OpenVibers committed 10 days ago · b16c9d4256 · 5 files, +45 −0

Five pages answered without og:image, so a link to them pasted in chat showed no
picture: /login (no social tags at all), the account hub (/machines, /themes…),
/updates (none either) and /status. They carry the card the home and legal pages
use, with the large Twitter card.

Changes

ddiff --git a/public/login.html b/public/login.html
iindex 4ed4d8f3..27ca1424 100644
---- a/public/login.html
++++ b/public/login.html
@@@ -11,6 +11,15 @@
<link rel="apple-touch-icon" href="/assets/logo-192.png">
<link rel="manifest" href="/manifest.webmanifest">
<meta name="description" content="Sign in to OpenVibe — one account across OpenVibe.Live, OpenVibe.Tools, OpenVibe.Games, and OpenVibe.Media.">
++<meta property="og:type" content="website">
++<meta property="og:url" content="https://openvibe.network/login">
++<meta property="og:title" content="Sign in to OpenVibe">
++<meta property="og:description" content="Sign in to OpenVibe — one account across OpenVibe.Live, OpenVibe.Tools, OpenVibe.Games, and OpenVibe.Media.">
++<meta property="og:site_name" content="OpenVibe.Network">
++<meta property="og:image" content="https://openvibe.network/shared/social/network.jpg">
++<meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site">
++<meta name="twitter:card" content="summary_large_image">
++<meta name="twitter:image" content="https://openvibe.network/shared/social/network.jpg">
<link rel="stylesheet" href="/css/login.css">
<!-- The OpenVibe glyphs draw every fa- icon here (no Font Awesome since 2026-11-01). -->
<script src="/shared/ov-glyphs.js" defer></script>
ddiff --git a/public/my.html b/public/my.html
iindex 3b407d49..6d4a35fe 100644
---- a/public/my.html
++++ b/public/my.html
@@@ -18,6 +18,10 @@
<meta property="og:title" content="My Account - OpenVibe">
<meta property="og:description" content="Personal dashboard for managing your OpenVibe account and preferences.">
<meta property="og:site_name" content="OpenVibe">
++<meta property="og:image" content="https://openvibe.network/shared/social/network.jpg">
++<meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site">
++<meta name="twitter:card" content="summary_large_image">
++<meta name="twitter:image" content="https://openvibe.network/shared/social/network.jpg">
<link rel="canonical" href="https://openvibe.network/my">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
ddiff --git a/server/status/routes.js b/server/status/routes.js
iindex 55658332..e01d42f4 100644
---- a/server/status/routes.js
++++ b/server/status/routes.js
@@@ -1,4 +1,7 @@
'use strict';
++
++// The network's share card (SEO-21): a status link pasted in chat shows it.
++const SHARE_CARD = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');
/**
* Operator status (roadmap Track O): what each OpenVibe service is doing right now, stated as
* observed rather than hoped.
@@@ -189,6 +192,7 @@ function renderPage(list, slo, generatedAt, devPath = null, toolsJob = null, hea
<title>Status · OpenVibe.Network</title>
<meta name="description" content="Observed status of each OpenVibe service: readiness, release and when it was last checked.">
<meta name="robots" content="noindex, nofollow">
++<meta property="og:title" content="Status · OpenVibe.Network"><meta property="og:description" content="Observed status of each OpenVibe service."><meta property="og:url" content="https://openvibe.network/status"><meta property="og:type" content="website"><meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${SHARE_CARD}"><meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="${SHARE_CARD}">
${boost.meta(releaseId)}
${require('openvibe-shared/app-icon').headTags({ site: 'network', iconBase: '/assets' })}
<meta name="color-scheme" content="dark light">
ddiff --git a/server/updates/routes.js b/server/updates/routes.js
iindex ffbef591..2ab381e8 100644
---- a/server/updates/routes.js
++++ b/server/updates/routes.js
@@@ -1,4 +1,7 @@
'use strict';
++
++// The network's share card (SEO-21): link previews of this page show it, as the home and legal pages do.
++const SHARE_CARD = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');
const cache = require('openvibe-shared/cache-policy');
/**
* What shipped, network-wide (roadmap WS-A):
@@@ -121,6 +124,7 @@ function renderPage({ site, filtered, body, releaseId = '' }) {
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${esc(title)} · OpenVibe.Network</title>
<meta name="description" content="Every change deployed to the OpenVibe network, newest first: each site's commits as they ship, and the Patch notes posts that gather them.">
++<meta property="og:title" content="${esc(title)} · OpenVibe.Network"><meta property="og:description" content="Every change deployed to the OpenVibe network, newest first."><meta property="og:url" content="https://openvibe.network/updates"><meta property="og:type" content="website"><meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${SHARE_CARD}"><meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="${SHARE_CARD}">
<link rel="canonical" href="https://openvibe.network/updates${filtered && site ? `?site=${esc(site)}` : ''}">
${filtered ? '<meta name="robots" content="noindex, follow">' : ''}
<link rel="alternate" type="application/json" href="/api/v1/changelog${site ? `?service=${esc(site)}` : ''}">
ddiff --git a/test/share-card-pages.test.js b/test/share-card-pages.test.js
nnew file mode 100644
iindex 00000000..296e9dfa
---- /dev/null
++++ b/test/share-card-pages.test.js
@@@ -0,0 +1,24 @@
++'use strict';
++// SEO-21: the network's share card on the five pages that had none (11-03 check: /login, /machines, /themes, /updates
++// and /status answered 200 without og:image, so a link pasted in chat showed no picture). The home, legal, sites and
++// stats pages already carry it.
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++const read = (f) => fs.readFileSync(path.join(__dirname, '..', f), 'utf8');
++
++for (const f of ['public/login.html', 'public/my.html']) {
++ const html = read(f);
++ assert.match(html, /<meta property="og:image" content="https:\/\/openvibe\.network\/shared\/social\/network\.jpg">/, `${f}: the card`);
++ assert.match(html, /<meta name="twitter:card" content="summary_large_image">/, `${f}: the large card`);
++ assert.strictEqual((html.match(/property="og:image"/g) || []).length, 1, `${f}: once`);
++}
++assert.match(read('public/login.html'), /<meta property="og:title" content="Sign in to OpenVibe">/);
++for (const f of ['server/updates/routes.js', 'server/status/routes.js']) {
++ const src = read(f);
++ assert.match(src, /const SHARE_CARD = require\('openvibe-shared\/social'\)\.url\('network', 'https:\/\/openvibe\.network\/shared'\);/, `${f}: the card's hashed URL`);
++ assert.match(src, /<meta property="og:image" content="\$\{SHARE_CARD\}">/, `${f}: in the head`);
++}
++const card = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');
++assert.match(card, /^https:\/\/openvibe\.network\/shared\/social\/network\.jpg/, 'the card resolves');
++console.log('share card pages: ok');