Problem
The full marketing footer (the five-column nav plus the MIT-License / "Built with webjs" bar) lived inline only in website/app/page.ts, so every other marketing page rendered without it. Most visibly, /why (website/app/why/page.ts) ended at </main> with no footer, so the site did not read as one system.
Design / approach
Extract the footer into a shared SSR-time helper and render it on both pages instead of duplicating the markup. Keep it a pure html-returning function so importing it never ships a page to the browser (it touches no client globals). Section anchors move from a bare #id to /#id so they resolve from any page, not only home.
Implementation notes (for the implementing agent)
Already implemented on branch feature/why-page-footer:
- New
website/lib/site-footer.ts exports siteFooter() returning the footer html fragment; imports link config from #lib/links.ts.
website/app/page.ts: inline <footer> replaced with ${siteFooter()}; trimmed now-unused UI_URL / EXAMPLE_BLOG_URL / DISCORD_URL from its #lib/links.ts import.
website/app/why/page.ts: added ${siteFooter()} after </main> + the import.
- Landmine: the small in-content
<footer> blocks on app/{articles,compare,blog}/[slug]/page.ts are page-nav breadcrumbs, NOT the site footer; leave them alone.
website/AGENTS.md notes "footer all live here" (in page.ts); no longer accurate but low-stakes.
Acceptance criteria
Problem
The full marketing footer (the five-column nav plus the MIT-License / "Built with webjs" bar) lived inline only in
website/app/page.ts, so every other marketing page rendered without it. Most visibly,/why(website/app/why/page.ts) ended at</main>with no footer, so the site did not read as one system.Design / approach
Extract the footer into a shared SSR-time helper and render it on both pages instead of duplicating the markup. Keep it a pure
html-returning function so importing it never ships a page to the browser (it touches no client globals). Section anchors move from a bare#idto/#idso they resolve from any page, not only home.Implementation notes (for the implementing agent)
Already implemented on branch
feature/why-page-footer:website/lib/site-footer.tsexportssiteFooter()returning the footerhtmlfragment; imports link config from#lib/links.ts.website/app/page.ts: inline<footer>replaced with${siteFooter()}; trimmed now-unusedUI_URL/EXAMPLE_BLOG_URL/DISCORD_URLfrom its#lib/links.tsimport.website/app/why/page.ts: added${siteFooter()}after</main>+ the import.<footer>blocks onapp/{articles,compare,blog}/[slug]/page.tsare page-nav breadcrumbs, NOT the site footer; leave them alone.website/AGENTS.mdnotes "footer all live here" (inpage.ts); no longer accurate but low-stakes.Acceptance criteria
/whyrenders the same site footer as/lib/site-footer.ts)webjs checkandtsc --noEmitpass/and/whyserve the footer