feat: add about page, sitemap, social links component, Apple sign-in

prompt on win screen, and layout/theme improvements

  ## New features

  - **About page** (`src/routes/about/`): New static about page rendered
    from `static/about.md` using the `marked` library (added as a
    dependency). Includes the project backstory content.

  - **XML sitemap** (`src/routes/sitemap.xml/`): Dynamic sitemap
    endpoint for SEO, registered in `static/robots.txt` via `Sitemap:`
    directive.

  - **Apple Sign In prompt on win screen** (`WinScreen.svelte`): When
    the game is won and the user is not logged in, a "Sign in to save
    your streak & see your stats" prompt with an Apple Sign In button is
    shown below the share card. Passes `anonymousId` so stats migrate on
    sign-up. Driven by new `isLoggedIn` and `anonymousId` props, passed
    from `+page.svelte`.

  ## Refactoring

  - **`SocialLinks` component**
    (`src/lib/components/SocialLinks.svelte`): Extracted the Bluesky,
    Twitter/X, and email social link icons from `Credits.svelte` into a
    reusable component. `Credits.svelte` now imports and renders
    `<SocialLinks />`.

  - **`ThemeToggle` component**
    (`src/lib/components/ThemeToggle.svelte`): New component for
    toggling light/dark mode, persisted to `localStorage`. Currently
    rendered but hidden (`hidden` class) in `+page.svelte` —
    infrastructure is in place for future use.

  ## Layout changes

  - **`+layout.svelte`**: Moved the page title/header (`<h1>` with
    `TitleAnimation`) and the gradient background wrapper from
    `+page.svelte` into the root layout, so it applies across all
    routes. Also removed the `browser` guard around the analytics script
    injection (it's
    already inside `onMount` which is client-only). Added `<meta
    name="description">`.

  - **`+page.svelte`**: Removed the title/header and gradient wrapper
    (now in layout). Minor formatting cleanup (reformatted `SearchInput`
    props, moved `currentDate` derived state earlier). `ThemeToggle`
    import swapped in place of `TitleAnimation` (which moved to layout).

  ## Styling

  - **`layout.css`**: Added `@custom-variant dark` for class-based dark
    mode toggling (supports `.dark` class on `<html>`). Added explicit
    `html.dark` / `html.light` rules alongside the existing
    `prefers-color-scheme` media query, so the `ThemeToggle` component
    can
    override the system preference. Added background transition
    animation.
This commit is contained in:
George Powell
2026-03-12 18:22:59 -04:00
parent 3de55ba216
commit 884bbe65c7
16 changed files with 444 additions and 94 deletions

View File

@@ -0,0 +1,48 @@
<svelte:head>
<title>About — Bibdle</title>
</svelte:head>
<script lang="ts">
import SocialLinks from "$lib/components/SocialLinks.svelte";
let { data } = $props();
const SOCIAL_PLACEHOLDER = "<!-- social -->";
const aboutParts = $derived(
data.about.includes(SOCIAL_PLACEHOLDER)
? data.about.split(SOCIAL_PLACEHOLDER)
: null
);
</script>
<div class="min-h-dvh py-10 px-4">
<div class="w-full max-w-xl mx-auto">
<div class="mb-8">
<a
href="/"
class="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-100 transition-colors"
>
← Back to Game
</a>
</div>
<div class="prose dark:prose-invert text-justify max-w-none">
{#if aboutParts}
{@html aboutParts[0]}
<div class="my-8 not-prose">
<SocialLinks />
</div>
{@html aboutParts[1]}
{:else}
{@html data.about}
{/if}
</div>
<div class="prose dark:prose-invert text-justify max-w-none mt-10">
{@html data.howToPlay}
</div>
</div>
</div>