From ae4b72011057c96bc6bf7cf954b87c9fd6b67ce7 Mon Sep 17 00:00:00 2001 From: Dominic Serrano Date: Tue, 8 Sep 2026 15:21:19 -0600 Subject: [PATCH] feat: styling/theme pass based on Astro Wanderer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports the design system (tokens, typography, header/nav, footer, post cards, prose, dark mode) from igagansingh/astro-wanderer (MIT licensed), trimmed to what this site's content model actually uses — no work timeline, travel gallery, or lightbox carousel, since we only have posts/pages, not those collections. - Design tokens + base reset + component styles in src/styles/global.css, imported from BaseLayout instead of the old public/styles/site.css. - Self-hosted variable fonts (Inter, JetBrains Mono) via @fontsource-* packages — no external runtime font request. - Dark/light mode: respects prefers-color-scheme by default, manual override remembered via localStorage, set pre-paint to avoid a flash. This is the one genuine use of client-side JS (ThemeToggle.astro) per the "no client JS unless a feature needs it" rule — manual override can't be done in pure CSS. - Header/Footer components with real site data (src/lib/site.ts): GitHub, LinkedIn, email, RSS. - Simple hero on the homepage (avatar optional, currently unset) — no typing-animation JS, since that's decorative rather than functional. - PostCard component used by both the homepage and tag pages. - BaseLayout gained canonical URL, Open Graph, and Twitter card meta tags. Bug caught during local verification: Intl.DateTimeFormat without an explicit timeZone renders a UTC-midnight date as the prior day in negative-UTC-offset timezones, and would make build output depend on the build machine's timezone (breaking the reproducible-build goal across local vs CI). Fixed by pinning timeZone: 'UTC' in both date-formatting call sites (PostCard, PostLayout). Verified: typecheck clean, 15/15 tests pass, build succeeds, and the built output was checked structurally via a local preview server (no browser tool available this session — worth a manual look before/after merge). --- .github/aw/logs/.gitignore | 5 + package-lock.json | 20 ++ package.json | 2 + src/components/Footer.astro | 20 ++ src/components/Header.astro | 34 +++ src/components/Hero.astro | 29 ++ src/components/Icon.astro | 49 +++ src/components/PostCard.astro | 26 ++ src/components/ThemeToggle.astro | 27 ++ src/layouts/BaseLayout.astro | 43 ++- src/layouts/PageLayout.astro | 6 +- src/layouts/PostLayout.astro | 19 +- src/lib/site.ts | 13 + src/pages/index.astro | 20 +- src/pages/tags/[tag].astro | 19 +- src/styles/global.css | 499 +++++++++++++++++++++++++++++++ 16 files changed, 786 insertions(+), 45 deletions(-) create mode 100644 .github/aw/logs/.gitignore create mode 100644 src/components/Footer.astro create mode 100644 src/components/Header.astro create mode 100644 src/components/Hero.astro create mode 100644 src/components/Icon.astro create mode 100644 src/components/PostCard.astro create mode 100644 src/components/ThemeToggle.astro create mode 100644 src/styles/global.css diff --git a/.github/aw/logs/.gitignore b/.github/aw/logs/.gitignore new file mode 100644 index 0000000..986a321 --- /dev/null +++ b/.github/aw/logs/.gitignore @@ -0,0 +1,5 @@ +# Ignore all downloaded workflow logs +* + +# But keep the .gitignore file itself +!.gitignore diff --git a/package-lock.json b/package-lock.json index b0fc0c2..990ea56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@astrojs/rss": "^4.0.19", "@astrojs/sitemap": "^3.7.4", + "@fontsource-variable/inter": "^5.3.0", + "@fontsource-variable/jetbrains-mono": "^5.3.0", "astro": "^7.3.2", "zod": "^4.5.4" }, @@ -1132,6 +1134,24 @@ "node": ">=18" } }, + "node_modules/@fontsource-variable/inter": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.3.0.tgz", + "integrity": "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource-variable/jetbrains-mono": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource-variable/jetbrains-mono/-/jetbrains-mono-5.3.0.tgz", + "integrity": "sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", diff --git a/package.json b/package.json index 11d966e..4d6904d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "dependencies": { "@astrojs/rss": "^4.0.19", "@astrojs/sitemap": "^3.7.4", + "@fontsource-variable/inter": "^5.3.0", + "@fontsource-variable/jetbrains-mono": "^5.3.0", "astro": "^7.3.2", "zod": "^4.5.4" }, diff --git a/src/components/Footer.astro b/src/components/Footer.astro new file mode 100644 index 0000000..f329158 --- /dev/null +++ b/src/components/Footer.astro @@ -0,0 +1,20 @@ +--- +import { siteConfig } from '../lib/site'; +--- + + diff --git a/src/components/Header.astro b/src/components/Header.astro new file mode 100644 index 0000000..314e32a --- /dev/null +++ b/src/components/Header.astro @@ -0,0 +1,34 @@ +--- +import ThemeToggle from './ThemeToggle.astro'; +import { siteConfig } from '../lib/site'; + +const navLinks = [ + { href: '/', label: 'Home' }, + { href: '/about/', label: 'About' }, +]; +--- + + diff --git a/src/components/Hero.astro b/src/components/Hero.astro new file mode 100644 index 0000000..10c70fb --- /dev/null +++ b/src/components/Hero.astro @@ -0,0 +1,29 @@ +--- +import Icon from './Icon.astro'; +import { siteConfig } from '../lib/site'; + +interface Props { + avatar?: string; +} + +const { avatar } = Astro.props; +--- + +
+
+
+

Hi, I'm

+

{siteConfig.author}

+

{siteConfig.description}

+ +
+ {avatar && {siteConfig.author}} +
+
diff --git a/src/components/Icon.astro b/src/components/Icon.astro new file mode 100644 index 0000000..9203e30 --- /dev/null +++ b/src/components/Icon.astro @@ -0,0 +1,49 @@ +--- +export interface Props { + name: 'github' | 'linkedin' | 'email' | 'rss' | 'sun' | 'moon'; + size?: number; + class?: string; +} + +const { name, size = 20, class: className } = Astro.props; +--- + +{name === 'github' && ( + +)} +{name === 'linkedin' && ( + +)} +{name === 'email' && ( + +)} +{name === 'rss' && ( + +)} +{name === 'sun' && ( + +)} +{name === 'moon' && ( + +)} diff --git a/src/components/PostCard.astro b/src/components/PostCard.astro new file mode 100644 index 0000000..79734f6 --- /dev/null +++ b/src/components/PostCard.astro @@ -0,0 +1,26 @@ +--- +import type { CollectionEntry } from 'astro:content'; +import { entrySlug } from '../lib/slugify'; + +interface Props { + post: CollectionEntry<'posts'>; +} + +const { post } = Astro.props; +const dateFmt = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: 'numeric', timeZone: 'UTC' }); +--- + +
+ + +

{post.data.title}

+

{post.data.description}

+ {post.data.tags.length > 0 && ( +
+ {post.data.tags.map((t) => {t})} +
+ )} +
+
diff --git a/src/components/ThemeToggle.astro b/src/components/ThemeToggle.astro new file mode 100644 index 0000000..6df0171 --- /dev/null +++ b/src/components/ThemeToggle.astro @@ -0,0 +1,27 @@ +--- +import Icon from './Icon.astro'; +--- + + + + + + diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 48008b7..4ac9b1e 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -1,4 +1,9 @@ --- +import '@fontsource-variable/inter'; +import '@fontsource-variable/jetbrains-mono'; +import '../styles/global.css'; +import Header from '../components/Header.astro'; +import Footer from '../components/Footer.astro'; import { siteConfig } from '../lib/site'; interface Props { @@ -7,30 +12,44 @@ interface Props { } const { title, description } = Astro.props; +const canonical = new URL(Astro.url.pathname, siteConfig.url).toString(); --- - + - {title} · Dominic Serrano + {title} · {siteConfig.author} + + - - + + + + + + + + + + + + + + + -
- -
+
-
-

© {siteConfig.author}

-
+