Skip to content

Commit e65ce4b

Browse files
TMHSDigitalclaude
andcommitted
Homepage uses the shared header and footer (#253); no client re-render of static sections (#258)
- index.html takes <!--SITE_HEADER-->, <!--SITE_FOOTER--> and <!--REPO_URL--> from build.mjs (shared.mjs chrome, config.site.repo); it holds no repo URL and app.js no longer patches repo links at runtime. The footer gains an optional repo link; the homepage brand still goes to #top. - app.js drops renderStarters and renderGuides: the build's prerendered rows are final. guideRowsHtml loses its unused repo parameter. Checked in a browser: header, footer, starter table, guide list and the request link all render, no console errors. Closes #253 Closes #258 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpkeXQPaUhxjgqdqnk6BrJ
1 parent 559ee92 commit e65ce4b

5 files changed

Lines changed: 36 additions & 75 deletions

File tree

‎site/build.mjs‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { execFileSync } from "node:child_process";
1414
import fs from "node:fs";
1515
import path from "node:path";
1616
import { fileURLToPath } from "node:url";
17-
import { baseHeadHtml, BROWSER_MODULES, isListed, commercialLabel, headAssetsHtml, esc, latestAllowedDate, OG_CARD_NAME, opensearchLinkHtml, opensearchXml, PAGE_MODULES, PREVIEW_CREDIT_LINE, sponsorButtonHtml } from "./lib/shared.mjs";
17+
import { baseHeadHtml, BROWSER_MODULES, isListed, commercialLabel, headAssetsHtml, esc, latestAllowedDate, OG_CARD_NAME, opensearchLinkHtml, opensearchXml, PAGE_MODULES, siteFooterHtml, siteHeaderHtml } from "./lib/shared.mjs";
1818
import { filmstripHtml, groupedEntriesHtml } from "./lib/cards.mjs";
1919
import { guidePageHtml } from "./lib/guide-page.mjs";
2020
import { renderGuide } from "./lib/guide-render.mjs";
@@ -194,7 +194,7 @@ function starterRowsHtml(featured) {
194194
.join("\n");
195195
}
196196

197-
function guideRowsHtml(guides, repo) {
197+
function guideRowsHtml(guides) {
198198
return (guides || [])
199199
.map(
200200
(g) =>
@@ -655,13 +655,14 @@ function main() {
655655
HERO_COUNT: String(visible.length),
656656
FILMSTRIP: filmstripHtml(filmstripPick(visible, { count: 9, cardCategories }), { root: "" }),
657657
CATEGORY_CHIPS: categoryChipsHtml(visible, config.categories),
658-
GUIDE_ROWS: guideRowsHtml(config.guides, repoUrl),
658+
GUIDE_ROWS: guideRowsHtml(config.guides),
659659
CATALOG_BLURB: `${visible.length} sources &middot; ${stats.active} active &middot; ${stats.commercialOk} commercial-ok &middot; ${stats.commercialVaries} per-file${stats.deprecated ? ` &middot; plus ${stats.deprecated} deprecated, hidden by default` : ""}`,
660660
// Deprecated entries are hidden until their switch is on, so they are not counted until then (app.js does the same).
661661
RESULT_COUNT: `${visible.length} of ${stats.listed} sources shown`,
662-
SPONSOR_BUTTON: sponsorButtonHtml(),
663-
PREVIEW_CREDIT: PREVIEW_CREDIT_LINE,
664-
FOOTER_STAMP: `Built ${esc(stamp)} from ${stats.listed} listed sources.`,
662+
// The chrome every page shares (shared.mjs), so the homepage cannot drift from it (#253).
663+
SITE_HEADER: siteHeaderHtml({ root: "", repo: repoUrl }),
664+
SITE_FOOTER: siteFooterHtml({ root: "", stamp, total: stats.listed, repo: repoUrl }),
665+
REPO_URL: esc(repoUrl),
665666
};
666667
let html = fs.readFileSync(path.join(PUBLIC, "index.html"), "utf8");
667668
const missingMarkers = Object.keys(substitutions).filter((key) => !html.includes(`<!--${key}-->`));

‎site/lib/lib.test.mjs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,23 @@ eq("search: q from the URL is capped", readState(`?q=${"a".repeat(5000)}`, { q:
22462246
eq("fresh: any keeps everything", pass(undefined, "any"), true);
22472247
}
22482248

2249+
/* homepage chrome from shared.mjs (#253) ---------------------------------- */
2250+
{
2251+
const fsm = (await import("node:fs")).default;
2252+
const { siteFooterHtml, siteHeaderHtml } = await import("./shared.mjs");
2253+
const tpl = fsm.readFileSync(new URL("../public/index.html", import.meta.url), "utf8");
2254+
for (const marker of ["<!--SITE_HEADER-->", "<!--SITE_FOOTER-->", "<!--REPO_URL-->"]) has(`homepage template uses ${marker}`, tpl, marker);
2255+
lacks("homepage template has no hand-written header", tpl, '<header class="topbar">');
2256+
lacks("homepage template has no hand-written footer", tpl, '<footer class="footer">');
2257+
lacks("homepage template has no repo URL", tpl, "github.com/");
2258+
const app = fsm.readFileSync(new URL("../public/app.js", import.meta.url), "utf8");
2259+
lacks("app.js does not patch repo links", app, "#repo-link");
2260+
has("home header brand goes to the top", siteHeaderHtml({ root: "", repo: "https://g.test/o/r" }), 'class="brand" href="#top"');
2261+
has("deep header brand goes to the root", siteHeaderHtml({ root: "../../", repo: "https://g.test/o/r" }), 'class="brand" href="../../"');
2262+
has("footer with repo links it", siteFooterHtml({ root: "", stamp: "s", total: 1, repo: "https://g.test/o/r" }), '<a href="https://g.test/o/r">Contribute on GitHub</a>');
2263+
lacks("footer without repo does not", siteFooterHtml({ root: "", stamp: "s", total: 1 }), "Contribute on GitHub");
2264+
}
2265+
22492266
/* report (keep last) ------------------------------------------------------ */
22502267
if (failures.length) {
22512268
console.error(`lib.test failed (${failures.length}):`);

‎site/lib/shared.mjs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ export const PREVIEW_CREDIT_LINE = "Preview images belong to their publishers an
243243
*/
244244
export function siteHeaderHtml({ root, repo }) {
245245
return `<header class="topbar">
246-
<a class="brand" href="${root}">Free Game Dev Assets</a>
246+
<a class="brand" href="${root || "#top"}">Free Game Dev Assets</a>
247247
<nav class="topnav" aria-label="Primary">
248248
<a href="${root}#catalog">Catalog</a>
249249
<a href="${root}#stacks">Stacks</a>
@@ -258,10 +258,11 @@ export function siteHeaderHtml({ root, repo }) {
258258
/**
259259
* The footer every generated page shares. `credit: false` drops the preview
260260
* credit on pages that show no previews; `current: "freshness"` drops the
261-
* link to the page the reader is on.
261+
* link to the page the reader is on. `repo` adds "Contribute on GitHub".
262262
*/
263-
export function siteFooterHtml({ root, stamp, total, credit = true, current = null }) {
263+
export function siteFooterHtml({ root, stamp, total, credit = true, current = null, repo = null }) {
264264
const links = [
265+
repo ? `<a href="${esc(repo)}">Contribute on GitHub</a>` : null,
265266
current === "freshness" ? null : `<a href="${root}freshness/">Licence freshness</a>`,
266267
`<a href="${root}data.json">data.json</a>`,
267268
`<a href="${root}catalog.csv">CSV</a>`,

‎site/public/app.js‎

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FILTER_DEFAULTS, FILTERS, gapIssueUrl, closestEntries, computeResults as computeResultsFor, passesFilters as passes, placementKey, queryTests as compileQuery, readState, scoreFields, searchFields, shouldGroup as shouldGroupFor, slugOf, sorterFor, SORTS, stateQuery, ENGINES } from "./search.js";
2-
import { CARD_LIMIT, LIST_LIMIT, commercialLabel, entryCardHtml, escapeHtml, groupHeadingHtml, groupMoreHtml, PERSPECTIVE_LABELS } from "./cards.mjs";
2+
import { CARD_LIMIT, LIST_LIMIT, entryCardHtml, escapeHtml, groupHeadingHtml, groupMoreHtml, PERSPECTIVE_LABELS } from "./cards.mjs";
33
import { installViewToggles } from "./views.js";
44
import { isListed, PERSPECTIVES } from "./shared.mjs";
55

@@ -40,7 +40,7 @@ import { isListed, PERSPECTIVES } from "./shared.mjs";
4040
const choicesOf = (f) => f.options || CHOICE_LABELS[f.field] || {};
4141
// Where a <select> option reads differently from the chip.
4242
const OPTION_TEXT = { perspective: Object.fromEntries(Object.entries(PERSPECTIVES).map(([k, p]) => [k, p.option])) };
43-
const repo = data.site?.repo || "https://github.com/TMHSDigital/Free-Game-Dev-Assets";
43+
const repo = data.site.repo;
4444
// No prototype: "#entry-constructor" must not look like an entry.
4545
const byId = Object.assign(Object.create(null), Object.fromEntries(data.entries.map((e) => [e.id, e])));
4646

@@ -549,29 +549,9 @@ import { isListed, PERSPECTIVES } from "./shared.mjs";
549549
writeUrl({ push });
550550
}
551551

552-
function renderStarters() {
553-
const tbody = $("#starter-table tbody");
554-
const featured = Array.isArray(data.featured) ? data.featured : [];
555-
tbody.innerHTML = featured
556-
.map((entry) => {
557-
if (!entry || !byId[entry.id]) return "";
558-
return `<tr>
559-
<td class="need">${escapeHtml(entry.need || "")}</td>
560-
<td><a href="entry/${escapeHtml(entry.id)}/">${escapeHtml(entry.name)}</a></td>
561-
<td class="license">${escapeHtml(entry.license)} &middot; ${escapeHtml(commercialLabel(entry.commercial))}</td>
562-
</tr>`;
563-
})
564-
.join("");
565-
}
552+
// The starter table and the guide list are prerendered by the build and
553+
// never change after it, so the page does not render them again (#258).
566554

567-
function renderGuides() {
568-
$("#guide-list").innerHTML = (data.guides || [])
569-
.map(
570-
(g) =>
571-
`<li><a href="guide/${escapeHtml(g.id)}/">${escapeHtml(g.title)}<span>${escapeHtml(g.path)}</span></a></li>`
572-
)
573-
.join("");
574-
}
575555

576556
/* ------------------------------------------------------ scroll memory */
577557

@@ -827,8 +807,6 @@ import { isListed, PERSPECTIVES } from "./shared.mjs";
827807
}
828808
});
829809

830-
$("#repo-link").href = repo;
831-
$("#footer-repo").href = repo;
832810
}
833811

834812
function syncControls() {
@@ -845,8 +823,6 @@ import { isListed, PERSPECTIVES } from "./shared.mjs";
845823
readUrl();
846824
adoptNodes();
847825
renderCategoryFilters();
848-
renderStarters();
849-
renderGuides();
850826
bindControls();
851827
syncControls();
852828
apply();

‎site/public/index.html‎

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,7 @@
1313
<body>
1414
<a class="skip-link" href="#catalog">Skip to catalog</a>
1515

16-
<header class="topbar">
17-
<a class="brand" href="#top">Free Game Dev Assets</a>
18-
<nav class="topnav" aria-label="Primary">
19-
<a href="#catalog">Catalog</a>
20-
<a href="#stacks">Stacks</a>
21-
<a href="#starters">Starters</a>
22-
<a href="#guides">Guides</a>
23-
<a id="repo-link" href="https://github.com/TMHSDigital/Free-Game-Dev-Assets" rel="noopener noreferrer">GitHub</a>
24-
<span class="nav-sponsor"><!--SPONSOR_BUTTON--></span>
25-
</nav>
26-
</header>
16+
<!--SITE_HEADER-->
2717

2818
<main id="top">
2919
<section class="hero" aria-labelledby="hero-title">
@@ -208,8 +198,8 @@ <h3 id="shortlist-title">Your shortlist (<span id="shortlist-count">0</span>)</h
208198
to see the whole catalog.
209199
<span class="empty-suggest" id="empty-suggest" hidden></span>
210200
<span class="empty-next">
211-
Can't find it? <a id="empty-request" href="https://github.com/TMHSDigital/Free-Game-Dev-Assets/issues/new?template=request-asset.yml" rel="noopener noreferrer">Request this asset</a>,
212-
or if you know a free source, <a id="empty-new-source" href="https://github.com/TMHSDigital/Free-Game-Dev-Assets/issues/new?template=new-source.yml" rel="noopener noreferrer">suggest it</a>.
201+
Can't find it? <a id="empty-request" href="<!--REPO_URL-->/issues/new?template=request-asset.yml" rel="noopener noreferrer">Request this asset</a>,
202+
or if you know a free source, <a id="empty-new-source" href="<!--REPO_URL-->/issues/new?template=new-source.yml" rel="noopener noreferrer">suggest it</a>.
213203
</span>
214204
</p>
215205
</section>
@@ -223,31 +213,7 @@ <h2 id="guides-title">Guides</h2>
223213
</section>
224214
</main>
225215

226-
<footer class="footer">
227-
<p>
228-
Catalog metadata is CC0. Linked assets keep their own licences. This is
229-
the catalog's reading of each licence, not legal advice: re-check the
230-
live source before shipping.
231-
</p>
232-
<p class="footer-credit"><!--PREVIEW_CREDIT--></p>
233-
<p class="footer-links">
234-
<a id="footer-repo" href="https://github.com/TMHSDigital/Free-Game-Dev-Assets">Contribute on GitHub</a>
235-
<span aria-hidden="true">·</span>
236-
add entries from <code>catalog/TEMPLATE.md</code>
237-
<span aria-hidden="true">·</span>
238-
<a href="freshness/">Licence freshness</a>
239-
<span aria-hidden="true">·</span>
240-
<a href="data.json">data.json</a>
241-
<span aria-hidden="true">·</span>
242-
<a href="catalog.csv">CSV</a>
243-
<span aria-hidden="true">·</span>
244-
<a href="feed.xml">feed</a>
245-
<span aria-hidden="true">·</span>
246-
<a href="guide/data/">Use the data</a>
247-
</p>
248-
<p class="footer-sponsor"><!--SPONSOR_BUTTON--></p>
249-
<p class="footer-stamp"><!--FOOTER_STAMP--></p>
250-
</footer>
216+
<!--SITE_FOOTER-->
251217

252218
<button type="button" class="to-top" id="to-top" hidden>
253219
<span aria-hidden="true">↑</span> Search

0 commit comments

Comments
 (0)