openvibers/openvibe.blog Commits
A blog on the vibe preset follows the reader's OpenVibe theme (the official blog's front page pinned vibe's blue over the season's colours) (#91)
Changes
@@@ -125,8 +125,15 @@ function createBlogs({ store, config }) {return await q.byId.get(blog.id);},-- /** CSS custom properties of the blog's preset, for its content surface. */-- themeVars(blog) { return (THEMES[blog.theme] || THEMES.vibe).variables; },++ /**++ * CSS custom properties of the blog's preset, for its content surface. `vibe` is the network's own default: a++ * blog that keeps it follows whatever theme the reader has on OpenVibe (a season's colours included) instead of++ * pinning vibe's values, so the official blog's front page matches every other site.++ */++ themeVars(blog) {++ if (!THEMES[blog.theme] || blog.theme === 'vibe') return {};++ return THEMES[blog.theme].variables;++ },async feedSettings(blog) { return await q.feed.get(blog.id) || { blog_id: blog.id, rss: 1, atom: 1, json: 1, item_count: 20, full_content: 1 }; },@@@ -71,7 +71,8 @@ function renderPage(o) {notificationsRealtime: true, // the bell hears new notifications over OpenVibe.Events (Shared 1.22.0)};const footer = { service: 'blog', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME, updates: '/updates' };-- const style = o.theme ? ` style="${esc(themeStyle(o.theme.vars))}" data-blog-theme="${esc(o.theme.slug)}"` : '';++ const vars = o.theme ? themeStyle(o.theme.vars) : '';++ const style = o.theme ? `${vars ? ` style="${esc(vars)}"` : ''} data-blog-theme="${esc(o.theme.slug)}"` : '';const account = signedIn? `<a href="/write">Write</a> · <a href="/auth/logout?next=${loginNext}">Sign out</a>`: `<a href="/auth/login?next=${loginNext}">Sign in with OpenVibe</a>`;@@@ -54,6 +54,10 @@ const split = (html) => ({ head: html.slice(0, html.indexOf('</head>')), body: hassert.ok(body.includes('OpenVibeFooter.init(window.__OV_PAGE.footer)'), 'the footer is initialised');assert.ok(/<main id="main" class="page blog-surface" style="--[^"]+" data-blog-theme="paper">/.test(body), 'the theme preset stays on the content surface');assert.strictEqual(count(r.text, /<main\b/g), 1, 'one <main>');++ // vibe is the network's default: a blog on it follows the reader's OpenVibe theme, so no colours are pinned.++ const { renderPage } = require('../server/render/layout');++ const vibe = renderPage({ decision: { robots: 'index, follow' }, config: { baseUrl: 'https://openvibe.blog' }, body: 'x', theme: { slug: 'vibe', vars: {} } });++ assert.ok(vibe.includes('<main id="main" class="page blog-surface" data-blog-theme="vibe">'), 'vibe pins no colours');});await check('the editor stays noindex; the home page keeps its feeds, the Blog JSON-LD and the AI summary', async () => {nnew file mode 100644@@@ -0,0 +1,20 @@++'use strict';++/**++ * Blog theme presets on the content surface: `vibe`, the network's own default, pins no colours (a blog on it++ * follows the reader's OpenVibe theme, a season's colours included: the official blog's front page was the one++ * blue page among the network's homes in the 2026-10-27 visual pass); a preset a blog chose keeps its values.++ */++const assert = require('assert');++const { createBlogs, THEME_PRESETS } = require('../server/domain/blogs');++++const stub = { prepare: () => ({ get: () => null, all: () => [], run: () => ({}) }) };++const blogs = createBlogs({ store: { db: stub }, config: {} });++++assert.deepStrictEqual(blogs.themeVars({ theme: 'vibe' }), {}, 'vibe follows the network theme');++assert.deepStrictEqual(blogs.themeVars({ theme: null }), {}, 'no preset: the network theme');++assert.deepStrictEqual(blogs.themeVars({ theme: 'no-such-theme' }), {}, 'an unknown preset: the network theme');++for (const preset of THEME_PRESETS.filter((p) => p !== 'vibe')) {++ const vars = blogs.themeVars({ theme: preset });++ assert.ok(vars['--bg-primary'] && vars['--accent'], `${preset} keeps its own colours`);++}++console.log('theme presets: all checks passed');
@@ -125,8 +125,15 @@ function createBlogs({ store, config }) {
@@ -125,8 +125,15 @@ function createBlogs({ store, config }) {
return await q.byId.get(blog.id);
return await q.byId.get(blog.id);
},
},
- /** CSS custom properties of the blog's preset, for its content surface. */
- themeVars(blog) { return (THEMES[blog.theme] || THEMES.vibe).variables; },
+ /**
+ * CSS custom properties of the blog's preset, for its content surface. `vibe` is the network's own default: a
+ * blog that keeps it follows whatever theme the reader has on OpenVibe (a season's colours included) instead of
+ * pinning vibe's values, so the official blog's front page matches every other site.
+ */
+ themeVars(blog) {
+ if (!THEMES[blog.theme] || blog.theme === 'vibe') return {};
+ return THEMES[blog.theme].variables;
+ },
async feedSettings(blog) { return await q.feed.get(blog.id) || { blog_id: blog.id, rss: 1, atom: 1, json: 1, item_count: 20, full_content: 1 }; },
async feedSettings(blog) { return await q.feed.get(blog.id) || { blog_id: blog.id, rss: 1, atom: 1, json: 1, item_count: 20, full_content: 1 }; },
@@ -71,7 +71,8 @@ function renderPage(o) {
@@ -71,7 +71,8 @@ function renderPage(o) {
notificationsRealtime: true, // the bell hears new notifications over OpenVibe.Events (Shared 1.22.0)
notificationsRealtime: true, // the bell hears new notifications over OpenVibe.Events (Shared 1.22.0)
};
};
const footer = { service: 'blog', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME, updates: '/updates' };
const footer = { service: 'blog', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME, updates: '/updates' };
- const style = o.theme ? ` style="${esc(themeStyle(o.theme.vars))}" data-blog-theme="${esc(o.theme.slug)}"` : '';
+ const vars = o.theme ? themeStyle(o.theme.vars) : '';
+ const style = o.theme ? `${vars ? ` style="${esc(vars)}"` : ''} data-blog-theme="${esc(o.theme.slug)}"` : '';
const account = signedIn
const account = signedIn
? `<a href="/write">Write</a> · <a href="/auth/logout?next=${loginNext}">Sign out</a>`
? `<a href="/write">Write</a> · <a href="/auth/logout?next=${loginNext}">Sign out</a>`
: `<a href="/auth/login?next=${loginNext}">Sign in with OpenVibe</a>`;
: `<a href="/auth/login?next=${loginNext}">Sign in with OpenVibe</a>`;
@@ -54,6 +54,10 @@ const split = (html) => ({ head: html.slice(0, html.indexOf('</head>')), body: h
@@ -54,6 +54,10 @@ const split = (html) => ({ head: html.slice(0, html.indexOf('</head>')), body: h
assert.ok(body.includes('OpenVibeFooter.init(window.__OV_PAGE.footer)'), 'the footer is initialised');
assert.ok(body.includes('OpenVibeFooter.init(window.__OV_PAGE.footer)'), 'the footer is initialised');
assert.ok(/<main id="main" class="page blog-surface" style="--[^"]+" data-blog-theme="paper">/.test(body), 'the theme preset stays on the content surface');
assert.ok(/<main id="main" class="page blog-surface" style="--[^"]+" data-blog-theme="paper">/.test(body), 'the theme preset stays on the content surface');
assert.strictEqual(count(r.text, /<main\b/g), 1, 'one <main>');
assert.strictEqual(count(r.text, /<main\b/g), 1, 'one <main>');
+ // vibe is the network's default: a blog on it follows the reader's OpenVibe theme, so no colours are pinned.
+ const { renderPage } = require('../server/render/layout');
+ const vibe = renderPage({ decision: { robots: 'index, follow' }, config: { baseUrl: 'https://openvibe.blog' }, body: 'x', theme: { slug: 'vibe', vars: {} } });
+ assert.ok(vibe.includes('<main id="main" class="page blog-surface" data-blog-theme="vibe">'), 'vibe pins no colours');
});
});
await check('the editor stays noindex; the home page keeps its feeds, the Blog JSON-LD and the AI summary', async () => {
await check('the editor stays noindex; the home page keeps its feeds, the Blog JSON-LD and the AI summary', async () => {
new file mode 100644
new file mode 100644
@@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
+'use strict';
+/**
+ * Blog theme presets on the content surface: `vibe`, the network's own default, pins no colours (a blog on it
+ * follows the reader's OpenVibe theme, a season's colours included: the official blog's front page was the one
+ * blue page among the network's homes in the 2026-10-27 visual pass); a preset a blog chose keeps its values.
+ */
+const assert = require('assert');
+const { createBlogs, THEME_PRESETS } = require('../server/domain/blogs');
+
+const stub = { prepare: () => ({ get: () => null, all: () => [], run: () => ({}) }) };
+const blogs = createBlogs({ store: { db: stub }, config: {} });
+
+assert.deepStrictEqual(blogs.themeVars({ theme: 'vibe' }), {}, 'vibe follows the network theme');
+assert.deepStrictEqual(blogs.themeVars({ theme: null }), {}, 'no preset: the network theme');
+assert.deepStrictEqual(blogs.themeVars({ theme: 'no-such-theme' }), {}, 'an unknown preset: the network theme');
+for (const preset of THEME_PRESETS.filter((p) => p !== 'vibe')) {
+ const vars = blogs.themeVars({ theme: preset });
+ assert.ok(vars['--bg-primary'] && vars['--accent'], `${preset} keeps its own colours`);
+}
+console.log('theme presets: all checks passed');