Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions website/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ website/
layout.ts root layout (head, OG/Twitter metadata,
header/footer chrome, Tailwind tokens)
page.ts / → the entire one-page landing site.
Hero, features grid, code samples, agent
badges, and footer all live here.
Hero, features grid, code samples, and agent
badges all live here. The header and footer
chrome are in layout.ts (shared by every page).
changelog/page.ts /changelog. Reads ../../../changelog/<pkg>/*.md
at SSR time and renders the unified release
feed. The deployment image must include the
Expand Down
2 changes: 1 addition & 1 deletion website/app/compare/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default async function Compare() {
<article class="border border-border rounded-xl bg-bg-elev p-5 sm:p-6 mb-5 shadow-sm transition-colors hover:border-border-strong">
<a href=${'/compare/' + c.slug} class="block no-underline text-fg">
<header class="flex flex-wrap items-baseline gap-x-3 gap-y-1 mb-2">
<span class="font-mono text-[11.5px] uppercase tracking-[0.12em] text-accent font-semibold">WebJs vs ${c.competitor}</span>
<span class="font-mono text-[11.5px] uppercase tracking-[0.12em] text-fg-subtle">WebJs vs ${c.competitor}</span>
</header>
<h2 class="font-serif text-[clamp(20px,3vw,26px)] leading-[1.15] tracking-tight text-fg m-0 mb-2">${c.tagline}</h2>
<p class="text-fg-muted text-[14.5px] leading-relaxed m-0">${c.description}</p>
Expand Down
5 changes: 4 additions & 1 deletion website/app/layout.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { html, cspNonce } from '@webjsdev/core';
import '#components/theme-toggle.ts';
import { DOCS_URL, UI_URL, EXAMPLE_BLOG_URL, GH_URL, NEW_TAB } from '#lib/links.ts';
import { siteFooter } from '#lib/site-footer.ts';

/**
* Root layout for the redesigned marketing site.
Expand Down Expand Up @@ -286,8 +287,10 @@ export default function RootLayout({ children }: { children: unknown }) {
</header>
</div>

<div class="relative z-[1]">
<div class="relative z-1">
${children}

${siteFooter()}
</div>
`;
}
3 changes: 0 additions & 3 deletions website/app/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import '#components/copy-cmd.ts';
import '#components/like-button.ts';
import { COMPONENT_SAMPLE, ACTION_SAMPLE, PAGE_SAMPLE } from '#lib/samples.ts';
import { DOCS_URL, GH_URL, NEW_TAB } from '#lib/links.ts';
import { siteFooter } from '#lib/site-footer.ts';
// highlight() runs only at SSR (codeWindow renders its output into the served
// HTML), but it does ship to the client as a small dead module: the page loads
// in the browser to register copy-cmd, and that pulls in its
Expand Down Expand Up @@ -400,7 +399,5 @@ middleware.ts</pre>
</section>

</main>

${siteFooter()}
`;
}
3 changes: 0 additions & 3 deletions website/app/why/page.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { html } from '@webjsdev/core';
import '#components/copy-cmd.ts';
import { DOCS_URL, GH_URL, EXAMPLE_BLOG_URL, NEW_TAB } from '#lib/links.ts';
import { siteFooter } from '#lib/site-footer.ts';

/**
* /why
Expand Down Expand Up @@ -212,7 +211,5 @@ Counter.register('counter');
</section>

</main>

${siteFooter()}
`;
}
9 changes: 5 additions & 4 deletions website/lib/site-footer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { html } from '@webjsdev/core';
import { DOCS_URL, UI_URL, EXAMPLE_BLOG_URL, GH_URL, DISCORD_URL, NEW_TAB } from '#lib/links.ts';

/**
* The site-wide footer, shared across marketing pages (the home page and /why).
* The site-wide footer, rendered once by the root layout (app/layout.ts) so it
* appears on every page, the same way the header/nav does.
*
* It lives here rather than inline in a page so every page renders the same
* chrome. Pure SSR-time helper: it returns an `html` fragment and touches no
* client globals, so importing it never ships a page to the browser.
* It lives here rather than inline in the layout so the chrome stays readable.
* Pure SSR-time helper: it returns an `html` fragment and touches no client
* globals, so importing it never ships a page to the browser.
*
* Anchor links point at `/#<id>` (not a bare `#<id>`) so a section anchor
* resolves from any page, not only the home page.
Expand Down
12 changes: 12 additions & 0 deletions website/test/ssr/layout-ssr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ test('every nav landmark carries a distinguishing aria-label', async () => {
assert.ok(labels.includes('Footer'), 'the footer nav is labeled Footer');
});

test('the root layout renders the site footer around a bare child (every page gets it)', async () => {
// The footer is layout chrome, not per-page markup, so a page that renders
// only its own <main> (blog, compare, changelog, articles) still gets exactly
// one footer. Compose the layout around a minimal child and assert the footer
// nav is present and appears once. Guards against the footer regressing back
// into individual pages (where blog/compare/changelog silently lost it).
const out = await renderToString(RootLayout({ children: html`<main>content</main>` }));
const footers = (out.match(/<footer\b/g) || []).length;
assert.equal(footers, 1, 'the layout renders exactly one footer around any page');
assert.ok(out.includes('aria-label="Footer"'), 'the layout-rendered footer nav is labeled Footer');
});

test('external new-tab links announce the context change and hide decorative glyphs', async () => {
const out = await renderToString(RootLayout({ children: LandingPage() }));
// Every target="_blank" link carries a visually-hidden new-tab cue.
Expand Down
Loading