openvibers/openvibe.community Commits
The OpenVibe Frame and the shared update system on openvibe.community: the home shows what shipped and /updates is the shared log (openvibe-shared/frame 1.11.1), the footer links it, and the shared navbar signs out through this site (logoutUrl)
Changes
@@@ -19,7 +19,7 @@"multer": "^2.4.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.35.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.7.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1"++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.11.1"},"engines": {"node": ">=20.0.0"@@@ -1082,9 +1082,9 @@}},"node_modules/openvibe-shared": {-- "version": "1.5.1",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1",-- "integrity": "sha512-1XWRFwN8br3iiy2Z8fmnXQMgR76VlfMpHjP1xr5uKLCJmtvtNSWO1BgA1kQmVtyBY7g+1n6YFIjahaD4qWbD/Q==",++ "version": "1.11.1",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.11.1",++ "integrity": "sha512-hBaZlZRVZjkGfsPQE16rQIou2lUuusADea3Evx1tVjB84FTHGHS7ZALfcXaNOk7dR53HOVTJrQ0njmScdreUiw==","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0"@@@ -28,7 +28,7 @@"multer": "^2.4.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.35.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.7.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1"++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.11.1"},"engines": {"node": ">=20.0.0"@@@ -211,6 +211,8 @@ function createApp(opts = {}) {html(res, pages.homePage({ latest, trending, languages, user: req.user }));}));++ app.get('/updates', (req, res) => html(res, pages.updatesPage()));++app.get('/pastes', withUser, wrap(async (req, res) => {const [result, languages] = await Promise.all([catalog.browse(req.query), catalog.languages()]);html(res, pages.browsePage(result, languages));@@@ -3,7 +3,7 @@/*** Page shell — every page on the site is server-rendered through this: full <head> SEO* (title, description, canonical, robots, Open Graph, Twitter card, JSON-LD), the shared-- * OpenVibe chrome (theme-loader first so there is no flash, navbar.js + footer.js from the++ * OpenVibe Frame (theme-loader first so there is no flash, navbar.js + footer.js from the* Network), this site's small stylesheet and its progressive script.*/const crypto = require('crypto');@@@ -54,6 +54,7 @@ function navbarInit(opts) {silentLogin: `${config.baseUrl}/auth/login?silent=1&next={url}`,sessionUrl: '/auth/me',loginUrl: `/auth/login?next=${encodeURIComponent(opts.canonicalPath || '/')}`,++ logoutUrl: '/auth/logout?next={path}', // Sign out in the shared navbar ends this site's session too};return cfg;}@@@ -64,6 +65,7 @@ function footerInit(opts) {variant: opts.footerVariant || 'full',mount: '#ov-footer',brandName: SITE_NAME,++ updates: '/updates', // the footer's "shipped X ago" line and Updates link open this site's logtagline: 'Community-run and open source. Free speech within the rules — the people of OpenVibe.',legalBase: config.liveUrl,links: [{@@@ -87,7 +89,7 @@ function footerInit(opts) {* ogImage, jsonLd (array), body (main HTML), active ('home'|'pastes'|'spaces'|'pulse'|'new'|'my'),* feeds ([{ title, href }] RSS alternates; default: the latest-pastes feed),* historyType ('page'|'paste'), historyTitle, footerVariant ('full'|'compact'), bodyClass,-- * published/modified (ISO, for article:*), noChrome (error pages during outages)++ * published/modified (ISO, for article:*), noFrame (error pages during outages)*/function renderPage(o) {const title = o.title ? `${o.title} · ${SITE_NAME}` : `${SITE_NAME} — the people of OpenVibe`;@@@ -135,11 +137,11 @@ ${jsonLdScript(o.jsonLd)}<main id="main" class="page">${o.body || ''}</main>--${require('openvibe-shared/footer').ssr({ service: 'community', variant: 'full' })}++${require('openvibe-shared/frame').footer({ service: 'community', variant: 'full', updates: '/updates' })}<script>window.__OV_PAGE = ${JSON.stringify({ navbar: nav, footer: foot }).replace(/</g, '\\u003c')};document.addEventListener('DOMContentLoaded', function () {-- try { if (window.OpenVibeNavbar) OpenVibeNavbar.init(window.__OV_PAGE.navbar); } catch (e) { /* chrome is optional */ }++ try { if (window.OpenVibeNavbar) OpenVibeNavbar.init(window.__OV_PAGE.navbar); } catch (e) { /* the Frame is optional */ }try { if (window.OpenVibeFooter) OpenVibeFooter.init(window.__OV_PAGE.footer); } catch (e) { /* */ }});</script>@@@ -9,6 +9,7 @@ const config = require('../config');const live = require('../live-client');const seo = require('../seo');const { renderPage, SITE_NAME, DEFAULT_OG_IMAGE } = require('./layout');++const frame = require('openvibe-shared/frame');const { highlight, escapeHtml: esc, languageLabel, extensionFor, LANGUAGES } = require('./highlight');const NETWORK_URL = 'https://openvibe.network';@@@ -135,7 +136,8 @@ function homePage({ latest, trending, languages, user }) {<div class="coming-item"><i class="fa-solid fa-comments" aria-hidden="true"></i><h3><a href="/s/general">Threads</a></h3><p>Long-form discussion that outlives a chat scrollback: start one in any open space.</p></div><div class="coming-item"><i class="fa-solid fa-wave-square" aria-hidden="true"></i><h3><a href="/pulse">Pulse</a></h3><p>What is happening across the OpenVibe network, in one feed.</p></div></div>--</section>`;++</section>++<section class="section">${frame.shipped({ service: 'community', title: 'Recently shipped on OpenVibe.Community' })}</section>`;return renderPage({title: null,description: 'The people of OpenVibe. A community-run, open source home for pastes — code, logs and screenshots with a link — spaces and threads, and soon submissions. Free speech within the rules.',@@@ -146,6 +148,16 @@ function homePage({ latest, trending, languages, user }) {});}++// ── What shipped: the shared update log every OpenVibe site has ──++function updatesPage() {++ return renderPage({++ title: 'What shipped on OpenVibe.Community',++ description: 'Every change deployed to OpenVibe.Community, newest first, with the Patch notes that gather them.',++ canonicalPath: '/updates',++ body: frame.updatesBody({ service: 'community', siteName: 'OpenVibe.Community' }) + frame.shippedScript(),++ });++}++// ── Browse ───────────────────────────────────────────────────function browsePage(result, languages) {const { pastes, total, page, pages, q, sort, lang, type = 'pastes', windowed, windowSize } = result;@@@ -384,4 +396,4 @@ function errorPage({ status = 500, title = 'Something went wrong', message = '',return renderPage({ title, description: message || title, canonicalPath: '/', robots: 'noindex,nofollow', footerVariant: 'compact', body });}--module.exports = { homePage, browsePage, pastePage, newPage, myPage, errorPage, pasteCard, cardGrid, timeAgo, timeTag, fmtDate, num, authorHtml };++module.exports = { homePage, updatesPage, browsePage, pastePage, newPage, myPage, errorPage, pasteCard, cardGrid, timeAgo, timeTag, fmtDate, num, authorHtml };nnew file mode 100644@@@ -0,0 +1,16 @@++'use strict';++// The shared update system on openvibe.community: the home shows what shipped, /updates is the log++// (openvibe-shared/frame markup, the same on every OpenVibe site), the footer links it, and the++// shared navbar signs out through this site (logoutUrl).++const assert = require('assert');++const pages = require('../server/render/pages');++++const home = pages.homePage({ latest: [], trending: [], languages: [], user: null });++assert.ok(home.includes('data-ov-shipped="latest" data-service="community" href="/updates"'), 'home pill');++assert.ok(home.includes('data-ov-shipped="list" data-service="community"'), 'home recent list');++assert.ok(home.includes('"logoutUrl":"/auth/logout?next={path}"'));++assert.ok(home.includes('"updates":"/updates"'));++const up = pages.updatesPage();++assert.ok(up.includes('What shipped on OpenVibe.Community') && up.includes('data-ov-shipped="log" data-service="community"'));++assert.ok(/<link rel="canonical" href="[^"]*\/updates">/.test(up));++console.log('shipped pages: all checks passed');
@@ -19,7 +19,7 @@
@@ -19,7 +19,7 @@
"multer": "^2.4.0",
"multer": "^2.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.35.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.35.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.7.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.7.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1"
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.11.1"
},
},
"engines": {
"engines": {
"node": ">=20.0.0"
"node": ">=20.0.0"
@@ -1082,9 +1082,9 @@
@@ -1082,9 +1082,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"node_modules/openvibe-shared": {
- "version": "1.5.1",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1",
- "integrity": "sha512-1XWRFwN8br3iiy2Z8fmnXQMgR76VlfMpHjP1xr5uKLCJmtvtNSWO1BgA1kQmVtyBY7g+1n6YFIjahaD4qWbD/Q==",
+ "version": "1.11.1",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.11.1",
+ "integrity": "sha512-hBaZlZRVZjkGfsPQE16rQIou2lUuusADea3Evx1tVjB84FTHGHS7ZALfcXaNOk7dR53HOVTJrQ0njmScdreUiw==",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0"
"jsonwebtoken": "^9.0.0"
@@ -28,7 +28,7 @@
@@ -28,7 +28,7 @@
"multer": "^2.4.0",
"multer": "^2.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.35.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.35.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.7.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.7.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1"
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.11.1"
},
},
"engines": {
"engines": {
"node": ">=20.0.0"
"node": ">=20.0.0"
@@ -211,6 +211,8 @@ function createApp(opts = {}) {
@@ -211,6 +211,8 @@ function createApp(opts = {}) {
html(res, pages.homePage({ latest, trending, languages, user: req.user }));
html(res, pages.homePage({ latest, trending, languages, user: req.user }));
}));
}));
+ app.get('/updates', (req, res) => html(res, pages.updatesPage()));
+
app.get('/pastes', withUser, wrap(async (req, res) => {
app.get('/pastes', withUser, wrap(async (req, res) => {
const [result, languages] = await Promise.all([catalog.browse(req.query), catalog.languages()]);
const [result, languages] = await Promise.all([catalog.browse(req.query), catalog.languages()]);
html(res, pages.browsePage(result, languages));
html(res, pages.browsePage(result, languages));
@@ -3,7 +3,7 @@
@@ -3,7 +3,7 @@
/**
/**
* Page shell — every page on the site is server-rendered through this: full <head> SEO
* Page shell — every page on the site is server-rendered through this: full <head> SEO
* (title, description, canonical, robots, Open Graph, Twitter card, JSON-LD), the shared
* (title, description, canonical, robots, Open Graph, Twitter card, JSON-LD), the shared
- * OpenVibe chrome (theme-loader first so there is no flash, navbar.js + footer.js from the
+ * OpenVibe Frame (theme-loader first so there is no flash, navbar.js + footer.js from the
* Network), this site's small stylesheet and its progressive script.
* Network), this site's small stylesheet and its progressive script.
*/
*/
const crypto = require('crypto');
const crypto = require('crypto');
@@ -54,6 +54,7 @@ function navbarInit(opts) {
@@ -54,6 +54,7 @@ function navbarInit(opts) {
silentLogin: `${config.baseUrl}/auth/login?silent=1&next={url}`,
silentLogin: `${config.baseUrl}/auth/login?silent=1&next={url}`,
sessionUrl: '/auth/me',
sessionUrl: '/auth/me',
loginUrl: `/auth/login?next=${encodeURIComponent(opts.canonicalPath || '/')}`,
loginUrl: `/auth/login?next=${encodeURIComponent(opts.canonicalPath || '/')}`,
+ logoutUrl: '/auth/logout?next={path}', // Sign out in the shared navbar ends this site's session too
};
};
return cfg;
return cfg;
}
}
@@ -64,6 +65,7 @@ function footerInit(opts) {
@@ -64,6 +65,7 @@ function footerInit(opts) {
variant: opts.footerVariant || 'full',
variant: opts.footerVariant || 'full',
mount: '#ov-footer',
mount: '#ov-footer',
brandName: SITE_NAME,
brandName: SITE_NAME,
+ updates: '/updates', // the footer's "shipped X ago" line and Updates link open this site's log
tagline: 'Community-run and open source. Free speech within the rules — the people of OpenVibe.',
tagline: 'Community-run and open source. Free speech within the rules — the people of OpenVibe.',
legalBase: config.liveUrl,
legalBase: config.liveUrl,
links: [{
links: [{
@@ -87,7 +89,7 @@ function footerInit(opts) {
@@ -87,7 +89,7 @@ function footerInit(opts) {
* ogImage, jsonLd (array), body (main HTML), active ('home'|'pastes'|'spaces'|'pulse'|'new'|'my'),
* ogImage, jsonLd (array), body (main HTML), active ('home'|'pastes'|'spaces'|'pulse'|'new'|'my'),
* feeds ([{ title, href }] RSS alternates; default: the latest-pastes feed),
* feeds ([{ title, href }] RSS alternates; default: the latest-pastes feed),
* historyType ('page'|'paste'), historyTitle, footerVariant ('full'|'compact'), bodyClass,
* historyType ('page'|'paste'), historyTitle, footerVariant ('full'|'compact'), bodyClass,
- * published/modified (ISO, for article:*), noChrome (error pages during outages)
+ * published/modified (ISO, for article:*), noFrame (error pages during outages)
*/
*/
function renderPage(o) {
function renderPage(o) {
const title = o.title ? `${o.title} · ${SITE_NAME}` : `${SITE_NAME} — the people of OpenVibe`;
const title = o.title ? `${o.title} · ${SITE_NAME}` : `${SITE_NAME} — the people of OpenVibe`;
@@ -135,11 +137,11 @@ ${jsonLdScript(o.jsonLd)}
@@ -135,11 +137,11 @@ ${jsonLdScript(o.jsonLd)}
<main id="main" class="page">
<main id="main" class="page">
${o.body || ''}
${o.body || ''}
</main>
</main>
-${require('openvibe-shared/footer').ssr({ service: 'community', variant: 'full' })}
+${require('openvibe-shared/frame').footer({ service: 'community', variant: 'full', updates: '/updates' })}
<script>
<script>
window.__OV_PAGE = ${JSON.stringify({ navbar: nav, footer: foot }).replace(/</g, '\\u003c')};
window.__OV_PAGE = ${JSON.stringify({ navbar: nav, footer: foot }).replace(/</g, '\\u003c')};
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('DOMContentLoaded', function () {
- try { if (window.OpenVibeNavbar) OpenVibeNavbar.init(window.__OV_PAGE.navbar); } catch (e) { /* chrome is optional */ }
+ try { if (window.OpenVibeNavbar) OpenVibeNavbar.init(window.__OV_PAGE.navbar); } catch (e) { /* the Frame is optional */ }
try { if (window.OpenVibeFooter) OpenVibeFooter.init(window.__OV_PAGE.footer); } catch (e) { /* */ }
try { if (window.OpenVibeFooter) OpenVibeFooter.init(window.__OV_PAGE.footer); } catch (e) { /* */ }
});
});
</script>
</script>
@@ -9,6 +9,7 @@ const config = require('../config');
@@ -9,6 +9,7 @@ const config = require('../config');
const live = require('../live-client');
const live = require('../live-client');
const seo = require('../seo');
const seo = require('../seo');
const { renderPage, SITE_NAME, DEFAULT_OG_IMAGE } = require('./layout');
const { renderPage, SITE_NAME, DEFAULT_OG_IMAGE } = require('./layout');
+const frame = require('openvibe-shared/frame');
const { highlight, escapeHtml: esc, languageLabel, extensionFor, LANGUAGES } = require('./highlight');
const { highlight, escapeHtml: esc, languageLabel, extensionFor, LANGUAGES } = require('./highlight');
const NETWORK_URL = 'https://openvibe.network';
const NETWORK_URL = 'https://openvibe.network';
@@ -135,7 +136,8 @@ function homePage({ latest, trending, languages, user }) {
@@ -135,7 +136,8 @@ function homePage({ latest, trending, languages, user }) {
<div class="coming-item"><i class="fa-solid fa-comments" aria-hidden="true"></i><h3><a href="/s/general">Threads</a></h3><p>Long-form discussion that outlives a chat scrollback: start one in any open space.</p></div>
<div class="coming-item"><i class="fa-solid fa-comments" aria-hidden="true"></i><h3><a href="/s/general">Threads</a></h3><p>Long-form discussion that outlives a chat scrollback: start one in any open space.</p></div>
<div class="coming-item"><i class="fa-solid fa-wave-square" aria-hidden="true"></i><h3><a href="/pulse">Pulse</a></h3><p>What is happening across the OpenVibe network, in one feed.</p></div>
<div class="coming-item"><i class="fa-solid fa-wave-square" aria-hidden="true"></i><h3><a href="/pulse">Pulse</a></h3><p>What is happening across the OpenVibe network, in one feed.</p></div>
</div>
</div>
-</section>`;
+</section>
+<section class="section">${frame.shipped({ service: 'community', title: 'Recently shipped on OpenVibe.Community' })}</section>`;
return renderPage({
return renderPage({
title: null,
title: null,
description: 'The people of OpenVibe. A community-run, open source home for pastes — code, logs and screenshots with a link — spaces and threads, and soon submissions. Free speech within the rules.',
description: 'The people of OpenVibe. A community-run, open source home for pastes — code, logs and screenshots with a link — spaces and threads, and soon submissions. Free speech within the rules.',
@@ -146,6 +148,16 @@ function homePage({ latest, trending, languages, user }) {
@@ -146,6 +148,16 @@ function homePage({ latest, trending, languages, user }) {
});
});
}
}
+// ── What shipped: the shared update log every OpenVibe site has ──
+function updatesPage() {
+ return renderPage({
+ title: 'What shipped on OpenVibe.Community',
+ description: 'Every change deployed to OpenVibe.Community, newest first, with the Patch notes that gather them.',
+ canonicalPath: '/updates',
+ body: frame.updatesBody({ service: 'community', siteName: 'OpenVibe.Community' }) + frame.shippedScript(),
+ });
+}
+
// ── Browse ───────────────────────────────────────────────────
// ── Browse ───────────────────────────────────────────────────
function browsePage(result, languages) {
function browsePage(result, languages) {
const { pastes, total, page, pages, q, sort, lang, type = 'pastes', windowed, windowSize } = result;
const { pastes, total, page, pages, q, sort, lang, type = 'pastes', windowed, windowSize } = result;
@@ -384,4 +396,4 @@ function errorPage({ status = 500, title = 'Something went wrong', message = '',
@@ -384,4 +396,4 @@ function errorPage({ status = 500, title = 'Something went wrong', message = '',
return renderPage({ title, description: message || title, canonicalPath: '/', robots: 'noindex,nofollow', footerVariant: 'compact', body });
return renderPage({ title, description: message || title, canonicalPath: '/', robots: 'noindex,nofollow', footerVariant: 'compact', body });
}
}
-module.exports = { homePage, browsePage, pastePage, newPage, myPage, errorPage, pasteCard, cardGrid, timeAgo, timeTag, fmtDate, num, authorHtml };
+module.exports = { homePage, updatesPage, browsePage, pastePage, newPage, myPage, errorPage, pasteCard, cardGrid, timeAgo, timeTag, fmtDate, num, authorHtml };
new file mode 100644
new file mode 100644
@@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
+'use strict';
+// The shared update system on openvibe.community: the home shows what shipped, /updates is the log
+// (openvibe-shared/frame markup, the same on every OpenVibe site), the footer links it, and the
+// shared navbar signs out through this site (logoutUrl).
+const assert = require('assert');
+const pages = require('../server/render/pages');
+
+const home = pages.homePage({ latest: [], trending: [], languages: [], user: null });
+assert.ok(home.includes('data-ov-shipped="latest" data-service="community" href="/updates"'), 'home pill');
+assert.ok(home.includes('data-ov-shipped="list" data-service="community"'), 'home recent list');
+assert.ok(home.includes('"logoutUrl":"/auth/logout?next={path}"'));
+assert.ok(home.includes('"updates":"/updates"'));
+const up = pages.updatesPage();
+assert.ok(up.includes('What shipped on OpenVibe.Community') && up.includes('data-ov-shipped="log" data-service="community"'));
+assert.ok(/<link rel="canonical" href="[^"]*\/updates">/.test(up));
+console.log('shipped pages: all checks passed');