openvibers/openvibe.reviews Commits
Reviews: a product home built with the showcase kit above the entity list. (#11)
Changes
@@@ -17,7 +17,7 @@"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.96.0","openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.3.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.10.1","pg": "^8.23.0"},"devDependencies": {@@@ -922,9 +922,9 @@}},"node_modules/openvibe-shared": {-- "version": "2.6.0",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",-- "integrity": "sha512-IKKvWTM/9UonQ4msrzM4yir0QcTUNbhyqeN1r5ywWavU4VTsL1sI5QdHQlxge7BAsMrQ4OvMEPlHjuAfUJM3rg==",++ "version": "2.10.1",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.10.1",++ "integrity": "sha512-6fUOw22bSvxg0K33BefAyAkNRkETe9euLNT0CHs2mLIvzYR1q38KiHRUQIWj8FESbVANF0pXMojhBz5TeqpMtg==","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0"@@@ -27,7 +27,7 @@"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.96.0","openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.3.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.10.1","pg": "^8.23.0"},"engines": {@@@ -1,4 +1,5 @@'use strict';++const showcase = require('openvibe-shared/showcase');/*** Server-rendered pages. Everything a reader or an editor does works with plain links and HTML* form posts; the shared navbar is progressive enhancement.@@@ -146,7 +147,7 @@ function createPages({ svc, platform, sync, viewers, config, log = console, limirouter.get('/', async (req, res) => {const all = await svc.listEntities({ limit: 1 });send(req, res, 200, views.home({ entities: await svc.entitiesWithData(60), total: all.total, editor: isEditor(req) }), {-- robots: 'index, follow', cache: 'public', active: 'home', path: '/', summary: SITE_SUMMARY,++ robots: 'index, follow', cache: 'public', active: 'home', path: '/', summary: SITE_SUMMARY, styles: [showcase.STYLESHEET],jsonLd: seo.structuredData.webPage({ url: `${config.baseUrl}/`, name: 'OpenVibe.Reviews', description: 'Review signals from named sources, with provenance and honest aggregates.' }),});});@@@ -95,6 +95,7 @@ function renderPage(o) {navLinks: LINKS.map((l) => ({ label: l.label, href: l.href })),home: '/',css: asset('css/reviews.css'),++ styles: o.styles, // openvibe-shared stylesheet names (the home page's showcase.css)release: RELEASE,mainClass: 'rv-main',header: `<header class="rv-bar"><a class="rv-brand" href="/">${SITE_NAME}</a><form class="rv-search" action="/search" method="get" role="search"><label for="rv-q" class="rv-sr">Search entities</label><input id="rv-q" name="q" type="search" placeholder="Search entities" value="${esc(o.query || '')}"><button type="submit">Search</button></form><noscript><span class="rv-account">${who}</span></noscript></header>`,@@@ -8,6 +8,7 @@* else, and no star glyphs: values are printed as the source stated them.*/const ssr = require('openvibe-publishing/ssr');++const showcase = require('openvibe-shared/showcase');const { html, raw } = ssr;const t = (v) => raw(ssr.timeTag(v));@@@ -71,14 +72,30 @@ function aggregateLine(agg) {return html`${parts.join(' · ')}`;}++/** The front page opens with what OpenVibe.Reviews is for (openvibe-shared/showcase), then the entities. */++function reviewsShowcase() {++ return showcase.hero({++ eyebrow: 'OpenVibe.Reviews',++ title: 'Review scores you can', accent: 'trace',++ lede: 'Ratings and recommendations gathered from named sources. Every number shows where it came from and when it was read, and when no source has said anything there is no score at all.',++ actions: [{ label: 'Browse what is reviewed', href: '#entities', primary: true }, { label: 'How it works', href: '/about' }],++ }) + showcase.features({++ title: 'What every page shows',++ items: [++ { icon: 'ov:search', title: 'Where each number came from', text: 'Every signal keeps its source, the item it came from, and when it was read.' },++ { icon: 'ov:check', title: 'An aggregate you can check', text: 'The inputs and the method are listed. An editor can leave a source out only with the reason shown.' },++ { icon: 'ov:history', title: 'Changes on the record', text: 'Replaced and withdrawn signals stay in the history, beside every revision of the aggregate.' },++ { icon: 'ov:docs', title: 'Summaries by people', text: 'Written or approved by an editor, citing the signals they rest on, and never carrying a rating.' },++ ],++ });++}++function home({ entities, total, editor }) {-- return html`<section class="rv-intro"><h1>OpenVibe.Reviews</h1>--<p>Review signals gathered from named sources. Every number on an entity page shows where it came from and when it was read, the aggregate lists its inputs and how it was computed, and there is no aggregate at all when no source has stated anything. Summaries are written or checked by a person; AI drafts are never published on their own and never produce a rating.</p>--<p><a href="/about">How it works</a>${editor ? html` · <a href="/editor">Editor desk</a>` : ''}</p></section>--<section><h2>Entities with source data</h2>++ return html`${raw(reviewsShowcase())}++<section id="entities"><h2>Entities with source data</h2>${entities.length ? html`<ul class="rv-entities">${entities.map((x) => html`<li><a href="${epath(x.entity)}"><strong>${x.entity.name}</strong></a> <span class="rv-tag">${KIND_LABEL[x.entity.kind]}</span><br><span class="rv-muted">${aggregateLine(x.aggregate)}</span></li>`)}</ul>`: html`<p class="rv-muted">Nothing yet. Entities appear here once a source has stated something about them (or an editor has published a summary).</p>`}--<p class="rv-muted">${n(total)} entit${total === 1 ? 'y' : 'ies'} in total. <a href="/feed.atom">Atom</a> · <a href="/feed.json">JSON Feed</a></p></section>`;++<p class="rv-muted">${n(total)} entit${total === 1 ? 'y' : 'ies'} in total. <a href="/feed.atom">Atom</a> · <a href="/feed.json">JSON Feed</a>${editor ? html` · <a href="/editor">Editor desk</a>` : ''}</p></section>`;}function aboutPage() {@@@ -12,14 +12,14 @@ const { spawn } = require('child_process');const { measure, check, format } = require('openvibe-shared/perf-budget');const BUDGETS = {-- htmlRawKB: 20, // measured 17.8 (fresh database)-- htmlBrotliKB: 5.5, // 4.6++ htmlRawKB: 25, // measured 23.7 (fresh database; 17.8 before the showcase hero and features)++ htmlBrotliKB: 6.5, // 5.9 (4.6 before the showcase)jsFiles: 5, // 5 (theme-loader, web-runtime, navbar, footer, boost: openvibe-shared/shell adds web-runtime)jsRawKB: 257, // 239.1 (212.2 before openvibe-shared/shell's web-runtime.js)jsBrotliKB: 61.5, // 56.3 (49.9 before web-runtime.js)-- cssFiles: 2, // 1-- cssRawKB: 7.5, // 6.7-- cssBrotliKB: 2, // 1.7++ cssFiles: 2, // 2 (reviews.css, openvibe-shared showcase.css)++ cssRawKB: 19.5, // 18.2 (6.7 before showcase.css)++ cssBrotliKB: 4.8, // 4.3 (1.7 before showcase.css)externalFiles: 1, // 0};
@@ -17,7 +17,7 @@
@@ -17,7 +17,7 @@
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.96.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.96.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.3.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.3.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.10.1",
"pg": "^8.23.0"
"pg": "^8.23.0"
},
},
"devDependencies": {
"devDependencies": {
@@ -922,9 +922,9 @@
@@ -922,9 +922,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"node_modules/openvibe-shared": {
- "version": "2.6.0",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",
- "integrity": "sha512-IKKvWTM/9UonQ4msrzM4yir0QcTUNbhyqeN1r5ywWavU4VTsL1sI5QdHQlxge7BAsMrQ4OvMEPlHjuAfUJM3rg==",
+ "version": "2.10.1",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.10.1",
+ "integrity": "sha512-6fUOw22bSvxg0K33BefAyAkNRkETe9euLNT0CHs2mLIvzYR1q38KiHRUQIWj8FESbVANF0pXMojhBz5TeqpMtg==",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0"
"jsonwebtoken": "^9.0.0"
@@ -27,7 +27,7 @@
@@ -27,7 +27,7 @@
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.96.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.96.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.3.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.3.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.10.1",
"pg": "^8.23.0"
"pg": "^8.23.0"
},
},
"engines": {
"engines": {
@@ -1,4 +1,5 @@
@@ -1,4 +1,5 @@
'use strict';
'use strict';
+const showcase = require('openvibe-shared/showcase');
/**
/**
* Server-rendered pages. Everything a reader or an editor does works with plain links and HTML
* Server-rendered pages. Everything a reader or an editor does works with plain links and HTML
* form posts; the shared navbar is progressive enhancement.
* form posts; the shared navbar is progressive enhancement.
@@ -146,7 +147,7 @@ function createPages({ svc, platform, sync, viewers, config, log = console, limi
@@ -146,7 +147,7 @@ function createPages({ svc, platform, sync, viewers, config, log = console, limi
router.get('/', async (req, res) => {
router.get('/', async (req, res) => {
const all = await svc.listEntities({ limit: 1 });
const all = await svc.listEntities({ limit: 1 });
send(req, res, 200, views.home({ entities: await svc.entitiesWithData(60), total: all.total, editor: isEditor(req) }), {
send(req, res, 200, views.home({ entities: await svc.entitiesWithData(60), total: all.total, editor: isEditor(req) }), {
- robots: 'index, follow', cache: 'public', active: 'home', path: '/', summary: SITE_SUMMARY,
+ robots: 'index, follow', cache: 'public', active: 'home', path: '/', summary: SITE_SUMMARY, styles: [showcase.STYLESHEET],
jsonLd: seo.structuredData.webPage({ url: `${config.baseUrl}/`, name: 'OpenVibe.Reviews', description: 'Review signals from named sources, with provenance and honest aggregates.' }),
jsonLd: seo.structuredData.webPage({ url: `${config.baseUrl}/`, name: 'OpenVibe.Reviews', description: 'Review signals from named sources, with provenance and honest aggregates.' }),
});
});
});
});
@@ -95,6 +95,7 @@ function renderPage(o) {
@@ -95,6 +95,7 @@ function renderPage(o) {
navLinks: LINKS.map((l) => ({ label: l.label, href: l.href })),
navLinks: LINKS.map((l) => ({ label: l.label, href: l.href })),
home: '/',
home: '/',
css: asset('css/reviews.css'),
css: asset('css/reviews.css'),
+ styles: o.styles, // openvibe-shared stylesheet names (the home page's showcase.css)
release: RELEASE,
release: RELEASE,
mainClass: 'rv-main',
mainClass: 'rv-main',
header: `<header class="rv-bar"><a class="rv-brand" href="/">${SITE_NAME}</a><form class="rv-search" action="/search" method="get" role="search"><label for="rv-q" class="rv-sr">Search entities</label><input id="rv-q" name="q" type="search" placeholder="Search entities" value="${esc(o.query || '')}"><button type="submit">Search</button></form><noscript><span class="rv-account">${who}</span></noscript></header>`,
header: `<header class="rv-bar"><a class="rv-brand" href="/">${SITE_NAME}</a><form class="rv-search" action="/search" method="get" role="search"><label for="rv-q" class="rv-sr">Search entities</label><input id="rv-q" name="q" type="search" placeholder="Search entities" value="${esc(o.query || '')}"><button type="submit">Search</button></form><noscript><span class="rv-account">${who}</span></noscript></header>`,
@@ -8,6 +8,7 @@
@@ -8,6 +8,7 @@
* else, and no star glyphs: values are printed as the source stated them.
* else, and no star glyphs: values are printed as the source stated them.
*/
*/
const ssr = require('openvibe-publishing/ssr');
const ssr = require('openvibe-publishing/ssr');
+const showcase = require('openvibe-shared/showcase');
const { html, raw } = ssr;
const { html, raw } = ssr;
const t = (v) => raw(ssr.timeTag(v));
const t = (v) => raw(ssr.timeTag(v));
@@ -71,14 +72,30 @@ function aggregateLine(agg) {
@@ -71,14 +72,30 @@ function aggregateLine(agg) {
return html`${parts.join(' · ')}`;
return html`${parts.join(' · ')}`;
}
}
+/** The front page opens with what OpenVibe.Reviews is for (openvibe-shared/showcase), then the entities. */
+function reviewsShowcase() {
+ return showcase.hero({
+ eyebrow: 'OpenVibe.Reviews',
+ title: 'Review scores you can', accent: 'trace',
+ lede: 'Ratings and recommendations gathered from named sources. Every number shows where it came from and when it was read, and when no source has said anything there is no score at all.',
+ actions: [{ label: 'Browse what is reviewed', href: '#entities', primary: true }, { label: 'How it works', href: '/about' }],
+ }) + showcase.features({
+ title: 'What every page shows',
+ items: [
+ { icon: 'ov:search', title: 'Where each number came from', text: 'Every signal keeps its source, the item it came from, and when it was read.' },
+ { icon: 'ov:check', title: 'An aggregate you can check', text: 'The inputs and the method are listed. An editor can leave a source out only with the reason shown.' },
+ { icon: 'ov:history', title: 'Changes on the record', text: 'Replaced and withdrawn signals stay in the history, beside every revision of the aggregate.' },
+ { icon: 'ov:docs', title: 'Summaries by people', text: 'Written or approved by an editor, citing the signals they rest on, and never carrying a rating.' },
+ ],
+ });
+}
+
function home({ entities, total, editor }) {
function home({ entities, total, editor }) {
- return html`<section class="rv-intro"><h1>OpenVibe.Reviews</h1>
-<p>Review signals gathered from named sources. Every number on an entity page shows where it came from and when it was read, the aggregate lists its inputs and how it was computed, and there is no aggregate at all when no source has stated anything. Summaries are written or checked by a person; AI drafts are never published on their own and never produce a rating.</p>
-<p><a href="/about">How it works</a>${editor ? html` · <a href="/editor">Editor desk</a>` : ''}</p></section>
-<section><h2>Entities with source data</h2>
+ return html`${raw(reviewsShowcase())}
+<section id="entities"><h2>Entities with source data</h2>
${entities.length ? html`<ul class="rv-entities">${entities.map((x) => html`<li><a href="${epath(x.entity)}"><strong>${x.entity.name}</strong></a> <span class="rv-tag">${KIND_LABEL[x.entity.kind]}</span><br><span class="rv-muted">${aggregateLine(x.aggregate)}</span></li>`)}</ul>`
${entities.length ? html`<ul class="rv-entities">${entities.map((x) => html`<li><a href="${epath(x.entity)}"><strong>${x.entity.name}</strong></a> <span class="rv-tag">${KIND_LABEL[x.entity.kind]}</span><br><span class="rv-muted">${aggregateLine(x.aggregate)}</span></li>`)}</ul>`
: html`<p class="rv-muted">Nothing yet. Entities appear here once a source has stated something about them (or an editor has published a summary).</p>`}
: html`<p class="rv-muted">Nothing yet. Entities appear here once a source has stated something about them (or an editor has published a summary).</p>`}
-<p class="rv-muted">${n(total)} entit${total === 1 ? 'y' : 'ies'} in total. <a href="/feed.atom">Atom</a> · <a href="/feed.json">JSON Feed</a></p></section>`;
+<p class="rv-muted">${n(total)} entit${total === 1 ? 'y' : 'ies'} in total. <a href="/feed.atom">Atom</a> · <a href="/feed.json">JSON Feed</a>${editor ? html` · <a href="/editor">Editor desk</a>` : ''}</p></section>`;
}
}
function aboutPage() {
function aboutPage() {
@@ -12,14 +12,14 @@ const { spawn } = require('child_process');
@@ -12,14 +12,14 @@ const { spawn } = require('child_process');
const { measure, check, format } = require('openvibe-shared/perf-budget');
const { measure, check, format } = require('openvibe-shared/perf-budget');
const BUDGETS = {
const BUDGETS = {
- htmlRawKB: 20, // measured 17.8 (fresh database)
- htmlBrotliKB: 5.5, // 4.6
+ htmlRawKB: 25, // measured 23.7 (fresh database; 17.8 before the showcase hero and features)
+ htmlBrotliKB: 6.5, // 5.9 (4.6 before the showcase)
jsFiles: 5, // 5 (theme-loader, web-runtime, navbar, footer, boost: openvibe-shared/shell adds web-runtime)
jsFiles: 5, // 5 (theme-loader, web-runtime, navbar, footer, boost: openvibe-shared/shell adds web-runtime)
jsRawKB: 257, // 239.1 (212.2 before openvibe-shared/shell's web-runtime.js)
jsRawKB: 257, // 239.1 (212.2 before openvibe-shared/shell's web-runtime.js)
jsBrotliKB: 61.5, // 56.3 (49.9 before web-runtime.js)
jsBrotliKB: 61.5, // 56.3 (49.9 before web-runtime.js)
- cssFiles: 2, // 1
- cssRawKB: 7.5, // 6.7
- cssBrotliKB: 2, // 1.7
+ cssFiles: 2, // 2 (reviews.css, openvibe-shared showcase.css)
+ cssRawKB: 19.5, // 18.2 (6.7 before showcase.css)
+ cssBrotliKB: 4.8, // 4.3 (1.7 before showcase.css)
externalFiles: 1, // 0
externalFiles: 1, // 0
};
};