Error / {page.status}
+This path went quiet.
++ {page.error?.message ?? 'The page could not be found.'} +
+ Return home → +From e9a935536e057f7b955e2897a70321f1dcdccbd7 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Sat, 29 Aug 2026 18:54:04 -0400 Subject: [PATCH] Add theme system, error page, and sitemap to SvelteKit site template Adds a persisted light/dark theme with a no-flash inline script and CSS custom property tokens, an error page, a sitemap endpoint, and a favicon. Playwright gains a mobile viewport and visual regression snapshots, which are skipped when CI is set. The accessibility audit now runs in both themes with reduced motion. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> --- javascript/site-sveltekit/README.md.jinja | 3 ++ .../site-sveltekit/playwright.config.ts.jinja | 12 ++++--- javascript/site-sveltekit/src/app.css.jinja | 28 ++++++++++++++-- javascript/site-sveltekit/src/app.html.jinja | 20 ++++++++++++ .../src/routes/+error.svelte.jinja | 18 +++++++++++ .../src/routes/+layout.svelte.jinja | 32 +++++++++++++++++++ .../src/routes/+layout.ts.jinja | 3 ++ .../src/routes/sitemap.xml/+server.ts.jinja | 18 +++++++++++ .../site-sveltekit/static/favicon.svg.jinja | 13 ++++++++ .../tests/a11y/audit.spec.ts.jinja | 23 +++++++++---- .../tests/behavior/theme.spec.ts.jinja | 15 +++++++++ .../tests/visual/pages.spec.ts.jinja | 13 ++++++++ 12 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 javascript/site-sveltekit/src/routes/+error.svelte.jinja create mode 100644 javascript/site-sveltekit/src/routes/sitemap.xml/+server.ts.jinja create mode 100644 javascript/site-sveltekit/static/favicon.svg.jinja create mode 100644 javascript/site-sveltekit/tests/behavior/theme.spec.ts.jinja create mode 100644 javascript/site-sveltekit/tests/visual/pages.spec.ts.jinja diff --git a/javascript/site-sveltekit/README.md.jinja b/javascript/site-sveltekit/README.md.jinja index 35b8677..c9e2052 100644 --- a/javascript/site-sveltekit/README.md.jinja +++ b/javascript/site-sveltekit/README.md.jinja @@ -18,4 +18,7 @@ pnpm test pnpm build ``` +Visual regression snapshots live beside `tests/visual/` and are skipped when `CI` is set. Record or +refresh them locally with `pnpm test:e2e:update`. + This site uses SvelteKit's `adapter-{{ site_adapter }}` deployment adapter. diff --git a/javascript/site-sveltekit/playwright.config.ts.jinja b/javascript/site-sveltekit/playwright.config.ts.jinja index 8165435..d3dfc15 100644 --- a/javascript/site-sveltekit/playwright.config.ts.jinja +++ b/javascript/site-sveltekit/playwright.config.ts.jinja @@ -2,10 +2,16 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: 'tests', + testMatch: ['**/*.spec.ts'], + testIgnore: process.env.CI ? ['**/visual/**'] : [], + snapshotPathTemplate: '{testDir}/{testFilePath}-snapshots/{arg}-{projectName}{ext}', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, reporter: process.env.CI ? 'github' : 'list', + expect: { + toHaveScreenshot: { maxDiffPixelRatio: 0.01, threshold: 0.2, animations: 'disabled', caret: 'hide' } + }, use: { baseURL: 'http://127.0.0.1:4177', trace: 'retain-on-failure', @@ -18,9 +24,7 @@ export default defineConfig({ timeout: 120_000 }, projects: [ - { - name: 'desktop', - use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 800 } } - } + { name: 'desktop', use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 800 } } }, + { name: 'mobile', use: { ...devices['Desktop Chrome'], viewport: { width: 390, height: 844 } } } ] }); diff --git a/javascript/site-sveltekit/src/app.css.jinja b/javascript/site-sveltekit/src/app.css.jinja index 3169048..751a8af 100644 --- a/javascript/site-sveltekit/src/app.css.jinja +++ b/javascript/site-sveltekit/src/app.css.jinja @@ -1,13 +1,35 @@ @import 'tailwindcss'; :root { - color: #171717; - background: #ffffff; - font-family: system-ui, sans-serif; + --paper: #ffffff; + --ink: #171717; + --muted: #5c5c5c; + --line: #e4e4e4; + + color-scheme: light; +} + +:root[data-theme='dark'] { + --paper: #0b0b0b; + --ink: #f2f2f2; + --muted: #a1a1a1; + --line: #262626; + + color-scheme: dark; +} + +@theme inline { + --color-paper: var(--paper); + --color-ink: var(--ink); + --color-muted: var(--muted); + --color-line: var(--line); } body { margin: 0; + color: var(--ink); + background: var(--paper); + font-family: system-ui, sans-serif; } a { diff --git a/javascript/site-sveltekit/src/app.html.jinja b/javascript/site-sveltekit/src/app.html.jinja index a15015b..0e31c8a 100644 --- a/javascript/site-sveltekit/src/app.html.jinja +++ b/javascript/site-sveltekit/src/app.html.jinja @@ -4,6 +4,26 @@ + + %sveltekit.head%
diff --git a/javascript/site-sveltekit/src/routes/+error.svelte.jinja b/javascript/site-sveltekit/src/routes/+error.svelte.jinja new file mode 100644 index 0000000..1938772 --- /dev/null +++ b/javascript/site-sveltekit/src/routes/+error.svelte.jinja @@ -0,0 +1,18 @@ + + +Error / {page.status}
++ {page.error?.message ?? 'The page could not be found.'} +
+ Return home → +