openvibers/openvibe.deals Commits

Deals: the empty home draws the kit's empty state with one button (#284)

OP OpenVibers committed 3 days ago · ff10aef533 · 4 files, +11 −7

* Deals: the empty home draws the kit's empty state with one button

When no deal has been posted, the home says so in the shared kit's empty
state (icon, title, one line, one primary button to post the first deal)
instead of a bare sentence with an underlined link. The page now loads
kit.css for it. test/pages.test.js checks the empty state and its button.

* Deals: load kit.css only on the empty home, with the budget raised

The shared empty state is the only thing on the home that needs kit.css,
so a home with deals loads exactly what it did before. The size budgets
now describe the empty home: html 43 KB, three stylesheets, 100 KB raw
and 21 KB brotli CSS.

Changes

ddiff --git a/server/http/pages.js b/server/http/pages.js
iindex 92ddcab..b333e6a 100644
---- a/server/http/pages.js
++++ b/server/http/pages.js
@@@ -214,7 +214,8 @@ function createPages(ctx) {
title: 'Today\'s deals, every price with its time',
description: 'Deals from Amazon, Walmart, Best Buy and more, by shop, category and end date, with price watches and crowdfunding. Every price says when it was seen.',
// The home page carries the site summary an AI can read (ai-summary meta + WebPage JSON-LD).
-- summary: SITE_SUMMARY, styles: [showcase.STYLESHEET],
++ // The empty home draws the shared kit's empty state; its look and button are in kit.css, loaded only then.
++ summary: SITE_SUMMARY, styles: [showcase.STYLESHEET, ...(total === 0 ? ['kit.css'] : [])],
decision: pageDecision('/', { empty: total === 0 }),
canonical: seo.canonicalUrl(config.baseUrl, '/'),
feeds: FEEDS,
ddiff --git a/server/render/home.js b/server/render/home.js
iindex 21c92c5..d56adfa 100644
---- a/server/render/home.js
++++ b/server/render/home.js
@@@ -11,6 +11,7 @@
*/
const { html, raw } = require('openvibe-publishing/ssr');
const showcase = require('openvibe-shared/showcase');
++const kit = require('openvibe-shared/kit');
const { ago, when, priceText } = require('./views');
const { remindLink } = require('./remind');
const { campaignCard } = require('../http/crowdfunding');
@@@ -150,7 +151,7 @@ function homePage(d, urls) {
];
return html`${hero}
--${d.empty ? html`<p class="empty hm-empty">No deals have been posted yet. <a href="/submit">Submit the first one</a>.</p>` : ''}
++${d.empty ? raw(kit.empty({ icon: 'tag', title: 'No deals yet', text: 'No deal has been posted yet.', action: { href: '/submit', label: 'Post the first deal', icon: 'plus' } })) : ''}
${raw(pickBlock({ key: 'deals', label: 'The deals', head: 'The deals', panes: dealPanes }))}
${raw(pickBlock({ key: 'browse', label: 'Ways to browse', head: 'Ways to browse', panes: browsePanes }))}
<details class="hm-fold"><summary>How it works<span>prices, votes, shops, watches</span></summary>${raw(showcase.features({
ddiff --git a/test/pages.test.js b/test/pages.test.js
iindex 0b9f89d..6267e7e 100644
---- a/test/pages.test.js
++++ b/test/pages.test.js
@@@ -26,7 +26,9 @@ const { boot, check, done, robotsOf, jsonLd, HOUR } = require('./helpers/boot');
assert.strictEqual((await t.ctx.store.db.prepare('SELECT COUNT(*) AS n FROM deal_offers').get()).n, 0);
const r = await t.get('/');
assert.strictEqual(r.status, 200);
-- assert.match(r.text, /No deals have been posted yet/);
++ assert.match(r.text, /class="ovk-empty"/, 'the empty home draws the kit empty state');
++ assert.match(r.text, /No deal has been posted yet/);
++ assert.match(r.text, /class="ovk-btn[^"]*" href="\/submit"/, 'the empty state offers one button forward');
assert.strictEqual(robotsOf(r.text), 'noindex, follow');
assert.match(r.headers.get('cache-control'), /public, max-age=60/);
});
ddiff --git a/test/perf-budget.test.js b/test/perf-budget.test.js
iindex 4914b6a..14a0fa3 100644
---- a/test/perf-budget.test.js
++++ b/test/perf-budget.test.js
@@@ -15,14 +15,14 @@ const { measure, check, format } = require('openvibe-shared/perf-budget');
// 2026-11-08: openvibe-shared v4.150.0; CI measured JS 353.9 KB raw / 84.4 KB brotli.
// 2026-11-08: openvibe-shared v4.149.0; CI measured JS 352.9 KB raw / 84.2 KB brotli.
const BUDGETS = {
-- htmlRawKB: 42, // 41.1 with openvibe-shared 4.66.0: the mark with depth and motion, ov-fx loaded on request (2026-10-31); 40.1 with the short home's pick blocks and folds (2026-10-30); 33.2 with the Part of OpenVibe section (Shared 4.13, 2026-10-26); 29.1 with the curated front page's search, questions (FAQ + JSON-LD) and closing call (2026-10-22); 23.5 before
++ htmlRawKB: 43, // 42.4 measured 2026-11-10: the empty home's kit empty state (the measured database is fresh); 41.1 with openvibe-shared 4.66.0: the mark with depth and motion, ov-fx loaded on request (2026-10-31); 40.1 with the short home's pick blocks and folds (2026-10-30); 33.2 with the Part of OpenVibe section (Shared 4.13, 2026-10-26); 29.1 with the curated front page's search, questions (FAQ + JSON-LD) and closing call (2026-10-22); 23.5 before
htmlBrotliKB: 10, // 8.3 openvibe-shared 4.15 footer: the compact footer opens into the whole one, and the pulse line; 7.1 with the curated front page (6.0 before; 4.5 before the showcase)
jsFiles: 5, // 5 (openvibe-shared 2.10's shell adds web-runtime.js)
jsRawKB: 375.1, // 375.1: measured 367.1 with openvibe-shared 4.161.0, plus room for 4.162.0–4.163.0, 2026-11-09
jsBrotliKB: 89.5, // 89.5: measured 87.5 with openvibe-shared 4.163.0, plus room for 4.162.0–4.163.0, 2026-11-09
-- cssFiles: 2, // 2 (deals.css, openvibe-shared showcase.css)
-- cssRawKB: 51, // 49.9 with 2026-11-01: category and store tiles (2026-11-01); 48.2 with the pick chips and fold rules (2026-10-30); 45.1 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 43.3 touch targets on phones (2026-10-29); 38.2 openvibe-shared 4.26.1 (hero visual); 30.4 with Shared 4.13.0 (2026-10-26: account links); 24.2 with the front page's stats, cards, chips and questions (19.0 before)
-- cssBrotliKB: 11, // 10.1 with the pick chips and fold rules (2026-10-30); 8.1 openvibe-shared 4.26.1 (hero visual); 6.5 with Shared 4.13.0 (2026-10-26: account links); 5.4 with the front page (2026-10-22); 4.7 with the crowdfunding rules; 1.5 before showcase.css
++ cssFiles: 3, // 3 on the empty home (deals.css, shared showcase.css and kit.css for the empty state); 2 on every other home
++ cssRawKB: 100, // 98.7 measured 2026-11-10: kit.css on the empty home; 49.9 with 2026-11-01: category and store tiles (2026-11-01); 48.2 with the pick chips and fold rules (2026-10-30); 45.1 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 43.3 touch targets on phones (2026-10-29); 38.2 openvibe-shared 4.26.1 (hero visual); 30.4 with Shared 4.13.0 (2026-10-26: account links); 24.2 with the front page's stats, cards, chips and questions (19.0 before)
++ cssBrotliKB: 21, // 20.2 measured 2026-11-10: kit.css on the empty home; 10.1 with the pick chips and fold rules (2026-10-30); 8.1 openvibe-shared 4.26.1 (hero visual); 6.5 with Shared 4.13.0 (2026-10-26: account links); 5.4 with the front page (2026-10-22); 4.7 with the crowdfunding rules; 1.5 before showcase.css
externalFiles: 1, // 0
};