Files
thejayman77 667b1a82c3 brand: standardize "Upbeat Bytes" → "upbeatBytes" everywhere
Per the logo + brand: the name is upbeatBytes (camelCase). Swept all user-facing
strings — titles/og:site_name/og:title, logo alt text, share pages (share.py),
emails (email_send), classifier prompt (llm), digest/unsubscribe (api), PWA
manifest, game share text, sign-in, the SPA shell + patch-static-heads (play
title) — plus README/publish.sh and the email test fixture. (SMTP From env was
already upbeatBytes.) Domains (upbeatbytes.com) unchanged. 425 BE + 36 FE green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 20:01:20 -04:00

85 lines
3.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Post-build: give specific prerendered shells their OWN social/canonical metadata.
//
// The app is a static SPA (ssr=false), so every prerendered shell ships app.html's
// HOMEPAGE <head> — meaning a shared /play or /word link previews as the news homepage,
// and its canonical points at "/". Client svelte:head can't fix that for non-JS scrapers
// (Twitter/Slack/iMessage) or for canonical dedup. So we rewrite each page's static head
// here, at build time. Deep-linked variants (e.g. /play?game=…) inherit the same file.
import { readFile, writeFile } from 'node:fs/promises';
const BASE = 'https://upbeatbytes.com';
// Per-page <head> overrides. Keep titles/descriptions in sync with each page's intent.
const PAGES = [
{
file: 'news.html', path: '/news',
title: 'News · upbeatBytes — calm, constructive news',
desc: 'Calm, constructive news, newest first — and a daily Highlights brief. ' +
'No ads, no paywalls, no doomscrolling.',
},
{
file: 'play.html', path: '/play',
title: 'Play · upbeatBytes — calm daily games',
desc: 'A calm set of daily games — Daily Word, Word Search, Bloom, and Memory Match. ' +
'A friendly little break from the doomscroll.',
},
{
file: 'word.html', path: '/word',
title: 'Word of the Day · upbeatBytes',
desc: 'A new uplifting word every day — its meaning in plain language, how to say it, and how to use it.',
},
{
file: 'quote.html', path: '/quote',
title: 'Quote of the Day · upbeatBytes',
desc: 'A hopeful, hand-picked quote each day, with a short note on what it means.',
},
{
file: 'onthisday.html', path: '/onthisday',
title: 'On This Day · upbeatBytes',
desc: 'One genuinely good thing that happened on this day in history.',
},
{
file: 'art.html', path: '/art',
title: 'Daily Art · upbeatBytes',
desc: "A masterwork a day from the world's open museum collections — beautifully framed, " +
'with a short note on what youre looking at.',
},
];
function subsFor(url, title, desc) {
return [
[/<title>[\s\S]*?<\/title>/, `<title>${title}</title>`],
[/<meta name="description" content="[^"]*"\s*\/>/, `<meta name="description" content="${desc}" />`],
[/<link rel="canonical" href="https:\/\/upbeatbytes\.com\/"\s*\/>/, `<link rel="canonical" href="${url}" />`],
[/<meta property="og:title" content="[^"]*"\s*\/>/, `<meta property="og:title" content="${title}" />`],
[/<meta property="og:description" content="[^"]*"\s*\/>/, `<meta property="og:description" content="${desc}" />`],
[/<meta property="og:url" content="https:\/\/upbeatbytes\.com\/"\s*\/>/, `<meta property="og:url" content="${url}" />`],
[/<meta name="twitter:title" content="[^"]*"\s*\/>/, `<meta name="twitter:title" content="${title}" />`],
[/<meta name="twitter:description" content="[^"]*"\s*\/>/, `<meta name="twitter:description" content="${desc}" />`],
];
}
for (const { file, path, title, desc } of PAGES) {
const fileUrl = new URL(`../build/${file}`, import.meta.url);
let html;
try {
html = await readFile(fileUrl, 'utf8');
} catch {
console.error(`patch-static-heads: build/${file} is missing (route renamed/removed?)`);
process.exit(1);
}
const missed = [];
for (const [re, repl] of subsFor(BASE + path, title, desc)) {
if (!re.test(html)) { missed.push(re.source.slice(0, 40)); continue; }
html = html.replace(re, repl);
}
// Fail loudly if the homepage head drifted — better a broken build than silently
// shipping the wrong preview/canonical again.
if (missed.length) {
console.error(`patch-static-heads: ${file} — these head tags were not found (app.html changed?):\n ` + missed.join('\n '));
process.exit(1);
}
await writeFile(fileUrl, html);
console.log(`patch-static-heads: rewrote build/${file} head → ${path}`);
}