diff --git a/.claude/skills/dispatches-design/SKILL.md b/.claude/skills/dispatches-design/SKILL.md new file mode 100644 index 0000000..247ab43 --- /dev/null +++ b/.claude/skills/dispatches-design/SKILL.md @@ -0,0 +1,67 @@ +--- +name: dispatches-design +description: Use this skill to generate well-branded interfaces and assets for Dispatches, Paul Berman's personal technical blog (plx.github.io) — either production code in this Astro repo or throwaway prototypes/mocks. Contains the brand's colors, type, fonts, assets, and component patterns (the "Twilight" design system). +user-invocable: true +--- + +# Dispatches Design Skill + +The site runs on the **Twilight** design system (a.k.a. "Twilight 3b Deeper"): +a single indigo-night-sky family for surfaces and text, with deep plum as the +**only** chromatic accent. Quiet, plain, serif-on-paper. + +## Start here + +- **`docs/DESIGN_SYSTEM.md`** — the repo-specific quick reference: the token + table, the token → Tailwind-utility mapping, dos & don'ts, where everything + lives, how dark mode works, and the opt-in/deferred patterns. **Read it first + for any visual change.** +- **`docs/design-system/README.md`** — the full brand narrative (voice, tone, + iconography, OG/favicon/wordmark specs, "what to avoid"). +- **`docs/design-system/colors_and_type.css`** — the canonical token *reference* + (CSS variables). The **live** wiring is `src/styles/tokens.css` (tokens + + `@font-face`) and `tailwind.config.mjs` (utilities). Edit those, not the + reference copy. + +## If you're working on production code (this repo) + +The live patterns to mirror: + +- **Tokens** are CSS variables in `src/styles/tokens.css`, exposed as Tailwind + utilities (`bg-bg`, `text-fg`, `text-fg-strong`, `text-muted`, `border-border`, + `bg-bg-hover`, `text-accent`, `decoration-accent`, `bg-accent-soft`, + `ring-accent`/`outline-accent`). They **auto-flip in dark mode** — do not add + `dark:` color variants; use the semantic token. +- **Type:** Inter (UI/headings, via `@fontsource/inter`) + Source Serif 4 (prose + body, local woff2 in `public/fonts/`, `font-serif`). Monospace = Expressive + Code default. Do **not** reintroduce Lora or add a third family. +- **Components:** `src/components/ExcerptEntry.astro` (the editorial listing), + `ContentCard.astro` (projects), `Link.astro`, `Header/Footer.astro`. Global + prose + editorial-feed + article-kind styles live in `src/styles/global.css`. +- **Don't change the type or color direction without checking** — the + low-contrast body / strong-heading hierarchy is load-bearing for the brand. + +## If you're making a throwaway visual artifact (slides, mocks, one-pagers) + +1. Copy `docs/design-system/colors_and_type.css` and any needed + `docs/design-system/assets/` into a single self-contained HTML file. +2. Stay on-brand: Inter + Source Serif 4, the Twilight palette (paper / night / + ink / moon + plum accent), **no shadows, no gradients, no second accent, + no emoji**, 300ms hover/focus transitions and **no entrance animation**. + See the "What to avoid" list in `docs/design-system/README.md`. + +## Hard rules (see docs/DESIGN_SYSTEM.md for the full list) + +- Plum is the only chroma. No green/red/second accent. +- No gradients, no shadows, no decorative SVG/mascots/sparkles. +- No emoji as iconography (and none in body copy). +- Layout caps: 640px (briefs/default), 540+280 gutter (Tufte blog), never >880px. +- **Motion is interaction feedback only** — 300ms hover/focus cross-fades; there + is **no** page-load fade-up. (The bundled `_ds_manifest.json`/`README` SKILL + text mentioning a "700ms fade-up" is stale; the README §Motion is authoritative.) + +## If invoked with no other guidance + +Ask what to build, ask a few clarifying questions (audience, format, length, +options vs. a single direction), then act as an expert designer producing either +an HTML artifact or production code as appropriate. diff --git a/.conductor/settings.toml b/.conductor/settings.toml new file mode 100644 index 0000000..3729a84 --- /dev/null +++ b/.conductor/settings.toml @@ -0,0 +1,18 @@ +"$schema" = "https://conductor.build/schemas/settings.repo.schema.json" + +[scripts] +setup = "npm ci && npx playwright install chromium firefox webkit" +run_mode = "concurrent" + +[scripts.run.dev] +command = "npm run dev -- --host 127.0.0.1 --port $CONDUCTOR_PORT" +default = true +icon = "play" + +[scripts.run.preview] +command = "npm run build && npm run preview -- --host 127.0.0.1 --port $CONDUCTOR_PORT" +icon = "globe" + +[scripts.run.unit] +command = "npm run test:unit" +icon = "test-tube" diff --git a/.gitignore b/.gitignore index a44363d..f57a402 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,8 @@ dist/ .astro/ # conductor build artifacts -.conductor/ +.conductor/* +!.conductor/settings.toml # dependencies node_modules/ @@ -32,3 +33,7 @@ pnpm-debug.log* /playwright-report/ /blob-report/ /playwright/.cache/ +.playwright-mcp/ + +# Design-system handoff archive (unpacked form lives in docs/design-system/) +Dispatches Design System-handoff.zip diff --git a/CLAUDE.md b/CLAUDE.md index 11a75e9..00f1f81 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,6 +35,29 @@ Some key commands are: Additionally, we aim to have *reasonable* accessibility support throughout the site. +## Design System + +The site's visual design is the **Twilight** design system: a single +indigo-night-sky surface/text family with deep **plum** as the only accent; +serif prose (Source Serif 4) on sans UI (Inter); flat-with-border, no shadows, +no gradients, no emoji. **Before making any visual change, read +[`docs/DESIGN_SYSTEM.md`](docs/DESIGN_SYSTEM.md)** (token table, the +token→Tailwind-utility mapping, dos & don'ts, dark-mode mechanics, and the +opt-in Tufte / deferred patterns). The `/dispatches-design` skill and the full +brand narrative in `docs/design-system/README.md` are also available. + +Key things to know: + +- **Tokens** are CSS variables in `src/styles/tokens.css`, exposed as Tailwind + utilities in `tailwind.config.mjs` (`bg-bg`, `text-fg`, `text-fg-strong`, + `text-muted`, `border-border`, `bg-bg-hover`, `text-accent`, `bg-accent-soft`, + `ring-accent`). They **auto-flip in dark mode** — use the semantic token, don't + add `dark:` color variants. +- **Served brand assets** (`public/favicon.svg`, `og-image*.png`, etc.) are + generated from `docs/design-system/` — don't hand-edit the PNGs. +- **Motion is interaction feedback only** (300ms hover/focus); there is no + page-load animation. + ## Content Structure The site's content is organized into three main collections: diff --git a/astro.config.mjs b/astro.config.mjs index 0ca0b10..2ff45b9 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -7,15 +7,22 @@ import react from "@astrojs/react"; import expressiveCode from "astro-expressive-code"; +import rehypeSidenotes from "./src/lib/rehype-sidenotes.mjs"; + export default defineConfig({ site: "https://plx.github.io", + markdown: { + // Tufte sidenotes for blog posts that opt in via `sidenotes: true`. + // No-ops on every other page (see src/lib/rehype-sidenotes.mjs). + rehypePlugins: [rehypeSidenotes], + }, integrations: [ - sitemap(), - tailwind(), - react(), + sitemap(), + tailwind(), + react(), expressiveCode({ themes: ["github-dark", "github-light"] - }), + }), mdx() ], }); diff --git a/cspell.json b/cspell.json index 3a250a4..57c3ce8 100644 --- a/cspell.json +++ b/cspell.json @@ -23,6 +23,7 @@ "devcontainer", "doesn", "expressibility", + "fnref", "frontmatter", "genericity", "HDXLXC", @@ -31,7 +32,9 @@ "instancetype", "justfile", "kindof", + "lede", "linter", + "marginalia", "MDX", "meso", "Meso", @@ -45,18 +48,25 @@ "nonnull", "NSURL", "objc", + "opengraph", "plx", "Playwright", "prb", "pretraining", "ripgrep", + "seeall", + "sidenote", + "sidenotes", "sitemap", "speedbump", + "stipple", "subclassing", "Tailgraph", "Tailwindcss", "textlint", "todolist", + "Tufte", + "Twilight", "Typesafe", "uncategorized", "Uncategorized", diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md new file mode 100644 index 0000000..62d343f --- /dev/null +++ b/docs/DESIGN_SYSTEM.md @@ -0,0 +1,184 @@ +# Dispatches Design System — Repo Reference + +The site's visual system is **Twilight** ("Twilight 3b Deeper"). The vibe: +quiet, plain, serif-on-paper — but the paper has cooled down. A single +indigo-night-sky family runs every surface and text color; deep **plum** is the +only chromatic accent. No illustrations, no gradients, no shadows. + +This file is the working reference for anyone (human or agent) making visual +changes. For the full brand narrative — voice, tone, iconography, OG/favicon +specs — read [`design-system/README.md`](./design-system/README.md). For +prototypes, invoke the `/dispatches-design` skill. + +--- + +## 1. How the system is wired in this repo + +| Concern | Lives in | +| --- | --- | +| Design tokens (CSS vars) + `@font-face` | `src/styles/tokens.css` | +| Tailwind utilities backed by tokens | `tailwind.config.mjs` | +| Global element/prose/editorial/article styles | `src/styles/global.css` | +| Fonts (served) | `public/fonts/source-serif-4-latin*.woff2` (Inter via `@fontsource/inter`) | +| Brand assets (served) | `public/favicon.svg`, `public/favicon-*.png`, `public/apple-touch-icon.png`, `public/android-chrome-192x192.png`, `public/og-image.png`, `public/og-image-dark.png` | +| Off-page brand assets (not served) | `docs/design-system/assets/` (dark favicons, OG `.svg` sources, OG bare motifs, wordmark lockups) + `docs/design-system/fonts/` (Source Serif 4 TTF sources) | +| Token reference (not built) | `docs/design-system/colors_and_type.css` | + +**Served assets are generated from the bundle — don't hand-edit the PNGs.** To +regenerate, work from the `.svg` sources in `docs/design-system/assets/`. The +woff2 fonts were latin-subset from the TTFs in `docs/design-system/fonts/` via +`pyftsubset` (keeping the `wght` + `opsz` axes). + +--- + +## 2. Tokens + +Defined in `src/styles/tokens.css` as CSS variables on `:root`, flipped under +`html.dark`. Body text is intentionally **low-contrast** (`--fg`); only +headings, `strong`, inline `code`, hovered links, and focus rings hit +`--fg-strong` / the accent. + +| Semantic token | Light | Dark | Role | +| --- | --- | --- | --- | +| `--bg` | `#f6f6fa` (paper) | `#0f1126` (night) | page surface | +| `--bg-elevated` | `rgba(22 24 48 / .04)` | `rgba(228 230 248 / .05)` | skip-link / subtle raised surface | +| `--bg-frost` | `rgba(246 246 250 / .75)` | `rgba(15 17 38 / .68)` | header frosted-glass veil (opaque-ish so backdrop colors don't bleed/flash) | +| `--bg-hover` | `rgba(22 24 48 / .09)` | `rgba(228 230 248 / .11)` | card/button hover | +| `--fg` | `rgba(22 24 48 / .62)` | `rgba(228 230 248 / .76)` | body text (soft) | +| `--fg-strong` | `#161830` (ink) | `#eff1fb` (moon) | headings, strong, code, focus | +| `--fg-muted` | `rgba(22 24 48 / .61)` | `rgba(228 230 248 / .48)` | meta, nav dividers, footer | +| `--border` | `rgba(22 24 48 / .13)` | `rgba(228 230 248 / .16)` | 1px outlines | +| `--border-hover` | `rgba(22 24 48 / .25)` | `rgba(228 230 248 / .40)` | | +| `--decoration` | `rgba(22 24 48 / .15)` | `rgba(228 230 248 / .22)` | prose link underline | +| `--decoration-hover` | `rgba(22 24 48 / .25)` | `rgba(228 230 248 / .45)` | | +| `--accent` / `--focus-ring` | `#762263` (plum-700) | `#d088b3` (plum-300) | the only chroma | +| `--accent-soft` | `rgba(118 34 99 / .09)` | `rgba(208 136 179 / .13)` | inline-code chip | + +Raw anchors: `--ink #161830`, `--night #0f1126`, `--paper #f6f6fa`, +`--moon #eff1fb`, `--plum-700 #762263`, `--plum-300 #d088b3`. The accent is also +published as channel triplets (`--accent-rgb`) so `accent` opacity modifiers work. + +**Type:** `--font-sans` Inter (UI/headings, 400/600); `--font-serif` Source +Serif 4 (prose `

`/`

  • `, variable 200–900 + italic); `--font-mono` system +mono (Expressive Code). Scale `--text-xs`…`--text-4xl` (12→36px), prose leading +`--leading-loose 1.75`. **Radii:** `sm .25rem` / `DEFAULT .375rem` / `lg .5rem` / +`full`. Layout: `--container 640px`, `--page-py 8rem`. Motion: `--dur-base 300ms`, +`--ease-in-out cubic-bezier(.65,0,.35,1)`. + +--- + +## 3. Token → Tailwind-utility mapping + +`tailwind.config.mjs` maps the semantic tokens to color utilities that **auto-flip +in dark mode**. Use the semantic utility; **do not add `dark:` color variants.** + +| Utility | Token | Notes | +| --- | --- | --- | +| `bg-bg`, `bg-bg-elevated`, `bg-bg-hover`, `bg-frost` | `--bg` / `--bg-elevated` / `--bg-hover` / `--bg-frost` | surfaces; `bg-frost` is the header glass veil | +| `text-fg`, `text-fg-strong`, `text-muted` | `--fg` / `--fg-strong` / `--fg-muted` | text | +| `border-border`, `hover:border-border-hover` | `--border` / `--border-hover` | bare `border` is also brand-colored | +| `decoration-decoration`, `hover:decoration-decoration-hover` | `--decoration` / `--decoration-hover` | link underlines | +| `text-accent`, `decoration-accent`, `ring-accent`, `outline-accent`, `bg-accent/NN` | `--accent` (channel-triplet) | supports opacity modifiers | +| `bg-accent-soft` | `--accent-soft` | inline-code chip (baked alpha) | +| `font-serif` | Source Serif 4 | prose body | + +> **Gotcha:** every token except `accent` bakes its own alpha, so opacity +> modifiers like `text-fg/50` **silently produce invalid CSS** — use the whole +> token. Only `accent` is channel-triplet form, so `bg-accent/10` etc. work. + +**Link hover behavior** (two distinct kinds): +- *Prose* links (inside `
    `): hover flips text **and** underline to the + **accent** (`global.css` `@layer utilities`). +- *UI* links (`Link.astro`): hover flips text to `fg-strong`, underline to accent. + +--- + +## 4. Dos & Don'ts + +**Do:** serif prose body + sans headings/UI; low-contrast body with strong +headings; flat-with-border cards; 300ms hover/focus cross-fades; static chevrons; +plum focus ring; honor `prefers-reduced-motion` (handled in `tokens.css`). + +**Don't:** +- ❌ Gradients (the flat indigo+plum pairing is the system; never blend them). +- ❌ A second accent — plum is the only chroma. No green/red/blue. +- ❌ Shadows / elevation (the frosted header backdrop is the only layering signal). +- ❌ Emoji as iconography (and none in body copy). +- ❌ Multi-column or content wider than **880px** (640 default/briefs; 540+280 + gutter for Tufte blog posts). +- ❌ Rounded cards with a colored left-border accent stripe; decorative SVGs, + mascots, "AI sparkle" gradients. +- ❌ Raw hex / px / non-DS fonts in styles — use tokens. (The bundle ships + `design-system/_adherence.oxlintrc.json` as the canonical rule statement; it is + reference-only, not wired into this repo's ESLint.) + +--- + +## 5. Dark mode + +Class-based (`darkMode: ["class"]`): the `` element gets `.dark`, which +flips every `--token`, so token-backed utilities re-theme automatically. The +toggle (light / dark / system, persisted to `localStorage`, transitions disabled +for one frame on flip) lives in the inline script in `src/components/Head.astro`; +the footer buttons drive it (`data-theme-button`, `aria-pressed`). + +--- + +## 6. Listings — the editorial feed + +Home, blog index, and briefs index use **`ExcerptEntry.astro`** (the editorial +feed): a `DATE · KIND · category` meta line, a large Source-Serif title, a 3-line +excerpt, and a "Continue reading →" tail. Styles are the `.ex-*` / `.feed-*` / +`.intro-lede` blocks in `global.css`. The whole entry is one link with an explicit +`aria-label`. The **Projects** list and brief-category pages keep +`ContentCard.astro` (bordered card — reads well for repo-link rows). The excerpt +is currently the entry's `description`; body-derived excerpts are a future option +(see §8). Helpers: `getBlogEntryProps` / `getBriefEntryProps` in +`src/lib/contentCardHelpers.ts`. + +--- + +## 7. Tufte sidenotes (opt-in per article) + +Blog posts can opt into a Tufte layout — a wider column (540 body + 280 gutter) +with numbered footnotes floated into the right margin as sidenotes (collapsing +inline below ~880px). **Existing posts keep the default** 640px column with +footnotes collected at the bottom (brand-styled). + +**To opt a post in:** set `sidenotes: true` in its frontmatter (blog collection +only — see `src/content/config.ts`). The author still writes standard markdown +footnotes (`[^1]`); the `src/lib/rehype-sidenotes.mjs` plugin relocates each +footnote inline next to its reference (as `` + `.sidenote`) and +removes the bottom section. The `.post-blog` / `.sidenote` / `.marginalia` styles +live in `global.css`. `.marginalia` (unanchored italic margin notes) is wired in +CSS but not yet emitted — a hook for future use. + +--- + +## 8. Deferred / future patterns + +- **Steel alternate palette** — a per-article aubergine-on-steel theme planned for + a forthcoming AI-and-artificial-light essay (whose color figures would fight the + plum). Not wired in. Activation: a `theme: "steel"` frontmatter field swapping a + class on the article root + a Steel token block. See `design-system/README.md` + §"Alternate theme". +- **Body-derived excerpts** — replace the `description` excerpt in `ExcerptEntry` + with the first rendered paragraph (via a remark step or `render()`); the helper + boundary in `contentCardHelpers.ts` is where this would change. +- **Per-post OG generator** — the static brand OG art is served sitewide; a + dynamic per-post card generator (on-brand stipple, not the old Tailgraph + gradient) could return later. Source art: `design-system/assets/og-image*.svg`. +- **`.marginalia`** — unanchored margin notes for Tufte posts (CSS ready). + +--- + +## 9. Resolved bundle contradiction (motion) + +The handoff's `README.md` §Motion is **authoritative**: the page-load fade-up +(700ms) and 150ms stagger are **removed** — content paints immediately; only +300ms hover/focus cross-fades remain and chevrons are static. The bundle's +`_ds_manifest.json` "motion" card and the original `SKILL.md` still describe the +old "700ms fade-up · 150ms stagger" — that text is **stale**. This repo follows +the README: no entrance animation. The legacy `.animate` / `.show` CSS, old +`Head.astro` `animate()` script, and existing `class="animate"` call sites were +removed during migration. diff --git a/docs/design-system/README.md b/docs/design-system/README.md new file mode 100644 index 0000000..10121c0 --- /dev/null +++ b/docs/design-system/README.md @@ -0,0 +1,490 @@ +# Dispatches — Design System + +The brand+visual system for **Dispatches**, the personal technical blog at +[plx.github.io](https://plx.github.io) by Paul Berman. + +The live site is an Astro Nano template, customized — what's captured here +is the *current* visual direction (carefully read out of the codebase) plus +the room to refine and explore alternatives the author wants. + +--- + +## 1. Brand Context + +| | | +| --- | --- | +| **Site name** | Dispatches | +| **Author** | Paul Berman | +| **Tagline** | *Technical writing on topics of personal interest.* | +| **URL** | https://plx.github.io | +| **Stack** | Astro 5 + MDX + Tailwind + React (theme: [Astro Nano](https://github.com/markhorn-dev/astro-nano)) | +| **Audience** | Working software engineers — heavy Swift, iOS, and recently-coding-agent communities | +| **Type** | Static personal blog (GitHub Pages) | + +### What it is + +A long-running, low-frequency technical journal. The site distinguishes +**three** kinds of content: + +| Section | What it's for | Length | Examples | +| --- | --- | --- | --- | +| **Blog** | Longer-form essays | 1.5k–10k+ words | "Generic Testing", "Meso-Optimization" | +| **Briefs** | Short notes filed under categories (Swift Warts, Claude Code, Objective-C, Testing) | 100–800 words | "Lazy Sequences Decay Easily", "Claude Code's Subscription Pricing vs GPT-5" | +| **Projects** | Long-lived write-ups of personal OSS tools | 500–4k words | `trop`, `hdxl-xctest-retrofit`, `agentic-navigation-guide` | + +There's also an **About** page in the nav. + +### Sources used + +- **Repo:** [`plx/plx.github.io`](https://github.com/plx/plx.github.io) — `main` branch. + Files read while building this system are listed in `SOURCES.md`. +- **Live site:** https://plx.github.io +- **Template lineage:** [Astro Nano](https://github.com/markhorn-dev/astro-nano) + (Tailwind, MIT). Several files (`BlockQuote`, `CallToAction`, `ExternalLink`) + are still leftover boilerplate from an earlier template (`accessible-astro-starter`) + and are *not* active on the live site — they're noted but not modeled. + +--- + +## 2. Index — what's in this folder + +``` +. +├── README.md ← you are here +├── SKILL.md ← Agent Skill entry point (Claude Code-compatible) +├── SOURCES.md ← exact files read from the upstream repo +├── colors_and_type.css ← CSS variables: colors, type, motion, shape +│ +├── assets/ ← logos, favicons, OG image +│ ├── logo.jpeg ← the brand "logo" (a photograph of icy water) +│ ├── logo-144.jpeg ← square crop @ 144px, used in OG image +│ ├── favicon-32.png +│ ├── favicon-48.png +│ ├── apple-touch-icon.png +│ └── android-chrome-192.png +│ +├── preview/ ← cards that populate the Design System tab +│ └── *.html +│ +└── ui_kits/ + └── blog/ ← clickable recreation of the live site + ├── README.md + ├── index.html ← runnable, scrollable, theme-toggleable + └── *.jsx ← Header, Footer, ContentCard, ArticleBody, … +``` + +--- + +## 3. Visual Foundations + +> **The vibe.** Quiet, plain, serif-on-paper — but the paper has cooled +> down. The system runs on a single indigo-night-sky family with deep +> plum as the only chromatic accent. No illustrations, no gradients, no +> wordmark on the live page itself (one was extracted as a standalone +> asset in `assets/wordmark*.svg` for off-site reuse); the only +> decoration on the page is the page-load fade-up and the +> arrow that draws itself on card hover. + +### Palette — Twilight 3b “Deeper” + +Four anchor colors plus a two-step plum accent. Everything else is one +of the anchors at an alpha. + +| Token | Hex | Role | +| --- | --- | --- | +| `--paper` | `#f6f6fa` | Light-mode background — cool desaturated near-white | +| `--night` | `#0f1126` | Dark-mode background — indigo, a step toward midnight | +| `--ink` | `#161830` | Light-mode strong text (and the source color for body text at 62% alpha) | +| `--moon` | `#eff1fb` | Dark-mode strong text (and the source color for body text at 76% alpha) | +| `--plum-700` | `#762263` | Accent — light mode. Focus ring, hovered prose link, code-chip tint, current-page underline. | +| `--plum-300` | `#d088b3` | Accent — dark mode. Same roles, lifted for contrast on `--night`. | + +**Why low-contrast body text?** Same as before: it pushes hierarchy. +Headings, hovered links, and `` are the only things that hit full +`--ink` / `--moon`, so the eye walks the page along those rails. The +narrow column (640 / 540 in the Tufte layout) and generous leading +(1.7–1.75 on prose) make this comfortable for long reads. + +**Where the accent shows up.** +- Focus ring (replaces the previous blue-600 / blue-400) +- Hovered prose link — text and underline color both flip to accent +- `` chip backdrop — `accent-soft` (the accent at ≈9% / 13% alpha) +- Current-page underline in the header nav +- Marker color in numbered footnotes / sidenotes (subtle, on hover) + +**Where the accent does *not* show up.** Filled buttons, banners, +gradients, illustrations. The system has none of those. + +### Alternate theme (planned, for one specific essay) + +A forthcoming essay draws an analogy between AI and artificial light +and will lean heavily on color-theory illustrations (spectrograms, +high-vs-low CRI samples, single-wavelength examples). The plum-on-indigo +Twilight palette would fight with those figures. The **Steel** palette +from `explorations/05-colors.html` is held as the per-article alternate: + +| Token | Steel light | Steel dark | +| --- | --- | --- | +| `--bg` | `#f1f2f4` | `#1c2026` | +| `--fg-strong` | `#1c2026` | `#eef0f3` | +| `--accent` | `#5a1e4a` (aubergine) | `#b78097` | + +Not wired into the live site yet. When the essay is closer, we'll add a +`theme: "steel"` frontmatter field that swaps a class on the article +root, leaving the rest of the site on Twilight. + +### Typography + +| Use | Family | Weight | +| --- | --- | --- | +| Headings, nav, UI | **Inter** | 600 (semibold) | +| Prose body (`

    `, `

  • ` inside `
    `) | **Source Serif 4** | 400 / 400 italic *(variable; whole range available)* | +| Code (inline + blocks) | Monospace (Expressive Code default) | 400/500 | + +Inter loads at 400 + 600. Source Serif 4 ships locally as two variable +font files (regular + italic) and is loaded via `@font-face` from +`fonts/`. **No third family** is used. JetBrains Mono is included here +as a reasonable code stand-in for static mocks. + +> **Heads up: this is a change from the live site.** The Astro template +> ships Lora as the prose serif; the uploaded font files replace it with +> Source Serif 4. The two have meaningfully different feels — Source +> Serif 4 is taller, more spacious, and slightly more "editorial / +> scholarly"; Lora is rounder and a bit more contemporary. If you want +> the live site to follow this design system, you'll need to update the +> Astro project to load Source Serif 4 instead of `@fontsource/lora`. + +The serif-for-prose / sans-for-everything-else split is the strongest +typographic move on the site. It's worth preserving in any new direction — +it makes long-form posts feel like a quiet book, not a SaaS landing page. + +### Spacing & shape + +- Container: **640px** (`max-w-screen-sm`). Single column, centered. +- Header: fixed top, `py-5`, frosted glass via `backdrop-blur-sm` over an + opaque-ish veil (`--bg-frost`: paper at 75% light / night at 68% dark). No + `saturate()` — an earlier `saturate-200` amplified saturated content scrolling + behind the bar (e.g. a list title mid-hover flipping to plum) into a flash. +- Main content: `py-32` — *very* generous top/bottom padding. +- Cards: `rounded-lg` (8px), thin border, no shadow. +- Buttons: `rounded` (6px) or `rounded-full` for icon buttons. +- **No shadow system** on the live site. None. Elevation is communicated + with the frosted header backdrop only. + +### Background, imagery & illustration + +The site has **no decorative illustrations, no full-bleed photography, no +gradients, no repeating patterns, no textures.** The body is a flat single +cool-paper or indigo-night-sky surface — *except* for one piece of brand +imagery, the OG image. + +**`assets/og-image.{svg,png}`** — the brand image and Open Graph card. +A monochrome ink drawing of a starry sky in the engraving tradition: +dense plum-ink stippling (Bold tier, ~21k dots on a 280×155 grid) on +the cool `--paper` surface, with stars left as **reserves** where the +paper shows through. Density falls off linearly from ~100% at the top +edge to ~0% at the horizon (78% of the way down), so the bottom of the +frame matches the rest of the brand's flat-paper feel. Wordmark sits +on the lower-left in Inter Semibold with the tagline in Source Serif 4 +italic — typography is *inside* the SVG, so it travels with any export. + +A bare variant without the wordmark (`assets/og-image-bare.svg/.png`) +is available for use as a recurring background motif on essay landings. + +A dark-mode OG variant lives at **`assets/og-image-dark.svg/.png`** +(and `-dark-bare.svg/.png`) — same plum-300 ink stippling on the +indigo `--night` surface, identical geometry. It ships as a brand +asset but isn't wired into the page metadata: `og:image:dark` is not +part of the Open Graph protocol and no major platform honors it, so +social cards use the single light `og-image.png` until a supported +mechanism exists. + +### Favicon + +Same engraving family, tuned for tiny rendering. `assets/favicon.svg` +is the canonical adaptive favicon — it embeds a `prefers-color-scheme` +media query inside the SVG, so a single file flips between modes. + +Specific PNG sizes are also shipped because (a) some browsers ignore +SVG color-scheme switching and (b) at small sizes a downsampled SVG +goes muddy. Each PNG is rendered **natively** at its target size with +disproportionately larger dots and added jaggedness — at 16px the dot +radius is **7×** the canonical 144 size, the grid is **1.5× denser**, +and the density floor is raised by **+0.45** so the image stays +saturated. Roughly **10% of dots in the top band flip to moon color** +(`#f0eafa` on dark, `#3a0e30` on light) as "bright stars" — these +break up the monotone field and survive aggressive downscaling. + +Files in `assets/`: +- `favicon.svg` — adaptive primary +- `favicon-light-{16,32,48,180,192}.png` and `favicon-dark-*` — raster fallbacks +- `apple-touch-icon.png` — light variant at 180px (iOS rarely honors dark) +- `android-chrome-192.png` — light variant at 192px + +The previous icy-water photo was retained for one revision; it has now +been removed. + +### Motion + +Interaction feedback only. No entrance animation, no decorative motion. + +- **Hover transitions.** Color, background, border, and text-decoration + changes are **300ms ease-in-out** (`--dur-base` / `--ease-in-out`). + Everything is on a transition; nothing snaps. +- **No page-load fade-up.** Content paints immediately. The legacy + `.animate` / `.show` pattern, its 700ms timing, and the 150ms index + stagger have all been removed. `` in the UI kit is now a + no-op passthrough kept only so old call sites compile. +- **No arrow-draw choreography.** The `ContentCard` right-chevron and + `BackToPrev` left-chevron are now static glyphs — visible at rest, + no transform on hover. The arrow still indicates affordance; it just + doesn't perform. +- **No bounces, no springs, no rotation, no scale-on-press.** +- **Reduced motion respected.** A `@media (prefers-reduced-motion: reduce)` + block collapses every transition/animation to ~one frame, so users who + ask their OS to reduce motion get instant state changes, not missing + feedback. Lives in `colors_and_type.css` (and mirrored in the blog kit's + `styles.css`). +- **Theme toggle disables all transitions** for one frame (a ` + + +
    +
    +
    +
    light · plum on paper
    +
    +
    +
    +
    dark · plum-300 on night
    +
    +
    +

    The one piece of brand imagery

    +

    A fading stipple-dot field — same engraving language as the favicon and OG card. Dense plum ink at the top thins to bare paper at the bottom. Light and dark variants share identical geometry on opposite surfaces.

    +
    + stippled · plum + fade-down · linear + square 1:1 +
    +
    +
    + + + + diff --git a/docs/design-system/preview/buttons-links.html b/docs/design-system/preview/buttons-links.html new file mode 100644 index 0000000..ff09a74 --- /dev/null +++ b/docs/design-system/preview/buttons-links.html @@ -0,0 +1,82 @@ + + + + + + +Buttons & links + + + +
    +
    BackToPrev
    + + + back to briefs + + no border · static chevron · color shift on hover +
    +
    +
    Prose link
    + +
    +
    +
    :focus-visible
    + 1px outline · plum @ 55% · offset-2 + keyboard-nav only — light but visible +
    + + diff --git a/docs/design-system/preview/code-block.html b/docs/design-system/preview/code-block.html new file mode 100644 index 0000000..8e79924 --- /dev/null +++ b/docs/design-system/preview/code-block.html @@ -0,0 +1,53 @@ + + + + + + +Code block + + + +
    +
    + + + + swift · github-light +
    +
    // lazy — flows through the entire chain
    +let badgeIDsToPrint = registrations
    +  .lazy
    +  .flatMap(\.attendees)
    +  .filter(\.isBadgeRequired)
    +  .map(\.badgeID)
    +
    +
    expressive-code · themes: github-dark · github-light · stays in the bg color of the page
    + + diff --git a/docs/design-system/preview/content-card.html b/docs/design-system/preview/content-card.html new file mode 100644 index 0000000..0434a38 --- /dev/null +++ b/docs/design-system/preview/content-card.html @@ -0,0 +1,40 @@ + + + + + + +ContentCard + + + +
    hover a card → background + text color cross-fade (300ms ease-in-out)
    + + + diff --git a/docs/design-system/preview/favicon.html b/docs/design-system/preview/favicon.html new file mode 100644 index 0000000..fb95375 --- /dev/null +++ b/docs/design-system/preview/favicon.html @@ -0,0 +1,43 @@ + + + + + + +Favicon + + + +
    +
    +
    Light mode · ink on paper
    +
    +
    16
    +
    32
    +
    48
    +
    180 (apple-touch)
    +
    +
    +
    +
    Dark mode · plum + moon-highlights on dusk
    +
    +
    16
    +
    32
    +
    48
    +
    180
    +
    +
    +
    + + diff --git a/docs/design-system/preview/header.html b/docs/design-system/preview/header.html new file mode 100644 index 0000000..1be3e9e --- /dev/null +++ b/docs/design-system/preview/header.html @@ -0,0 +1,55 @@ + + + + + + +Header + + + +
    +
    +
    +
    Dispatches
    + +
    +
    +
    fixed · backdrop-blur · paper / 75% veil
    +
    + + diff --git a/docs/design-system/preview/iconography.html b/docs/design-system/preview/iconography.html new file mode 100644 index 0000000..bfb8274 --- /dev/null +++ b/docs/design-system/preview/iconography.html @@ -0,0 +1,56 @@ + + + + + + +Iconography + + + +
    +
    +
    +
    sun
    +
    +
    +
    +
    moon
    +
    +
    +
    +
    monitor
    +
    +
    +
    +
    arrow-right
    +
    +
    +
    +
    arrow-left
    +
    +
    +
    +
    external
    +
    +
    +
    +
    chevron-up
    +
    +
    +
    Inline SVG only. 24×24 viewBox · stroke 1.5–2 · currentColor · round joins · no fills. Same family as lucide. The site ships only the first five glyphs; the rest are reasonable additions from the same family.
    + + diff --git a/docs/design-system/preview/layout-container.html b/docs/design-system/preview/layout-container.html new file mode 100644 index 0000000..5c44e8b --- /dev/null +++ b/docs/design-system/preview/layout-container.html @@ -0,0 +1,58 @@ + + + + + + +Layout & container + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Containermax-w-screen-sm
    640px · px-5
    +
    Mainpy-32 · single column
    +
    No gridsposts stack vertically
    +
    +
    + + diff --git a/docs/design-system/preview/motion.html b/docs/design-system/preview/motion.html new file mode 100644 index 0000000..88e1055 --- /dev/null +++ b/docs/design-system/preview/motion.html @@ -0,0 +1,116 @@ + + + + + + +Motion + + + +
    hover either element → 300ms ease-in-out cross-fade
    + +
    +
    + +
    + +
    + +
    +
    --dur-base300ms
    +
    --ease-in-outcubic-bezier(.65, 0, .35, 1)
    +
    propertiescolor · background · border · text-decoration
    +
    scopehover & focus state changes only
    +
    + +
    + Removed from this system + Page-load fade-up (.animate / .show, 700ms + 150ms stagger)
    + ContentCard arrow draw-in (shaft scaleX 0→1, head translate)
    + BackToPrev mirrored arrow draw-in +
    + + diff --git a/docs/design-system/preview/og-image.html b/docs/design-system/preview/og-image.html new file mode 100644 index 0000000..09a507b --- /dev/null +++ b/docs/design-system/preview/og-image.html @@ -0,0 +1,26 @@ + + + + + + +OG image + + + +
    + Dispatches — OG image: deep plum stippled night sky fading to cool paper, with stars left as reserves +
    +
    + 1200 × 630 + Bold tier · linear falloff · 280 × 155 dot grid + plum-700 ink on paper · stars as reserves +
    + + diff --git a/docs/design-system/preview/palette.html b/docs/design-system/preview/palette.html new file mode 100644 index 0000000..2db7ab9 --- /dev/null +++ b/docs/design-system/preview/palette.html @@ -0,0 +1,32 @@ + + + + + + +Twilight palette + + + +
    +
    paper
    #f6f6fa
    +
    night
    #0f1126
    +
    ink
    #161830
    +
    moon
    #eff1fb
    +
    plum-700
    #762263
    +
    plum-300
    #d088b3
    +
    +
    + Twilight 3b · Deeper. Indigo night-sky shading toward cool desaturated paper; deep plum is the only chromatic accent. paper / night are the surfaces; ink / moon are the high-contrast text colors; plum-700 / plum-300 carries focus rings, code-chip tints, hovered links. +
    + + diff --git a/docs/design-system/preview/prose-composition.html b/docs/design-system/preview/prose-composition.html new file mode 100644 index 0000000..4e2508b --- /dev/null +++ b/docs/design-system/preview/prose-composition.html @@ -0,0 +1,41 @@ + + + + + + +Prose composition + + + +
    +

    Why Meso-Optimization Matters

    +

    An elegant-looking corner of the Swift standard library is its lazy-functional APIs — if you want to convert a chain into its lazy equivalent, all you need to do is prepend it with lazy.

    +

    Looks nice, but there's a catch: the implementation is making clever use of an unusually-tricky aspect of Swift's overload-resolution rules1.

    +
    + + diff --git a/docs/design-system/preview/radii-and-shape.html b/docs/design-system/preview/radii-and-shape.html new file mode 100644 index 0000000..b8a68ea --- /dev/null +++ b/docs/design-system/preview/radii-and-shape.html @@ -0,0 +1,55 @@ + + + + + + +Radii & shape + + + +
    +
    +
    +
    sm · 4px
    +
    code chips
    +
    +
    +
    +
    default · 6px
    +
    buttons
    BackToPrev
    +
    +
    +
    +
    lg · 8px
    +
    ContentCard
    article images
    +
    +
    +
    +
    full
    +
    icon buttons
    theme toggle
    +
    +
    +
    No shadow system. Cards are flat, with a 1px border at 15% (light) or 20% (dark) alpha. The only depth signal in the brand is the fixed header's backdrop-blur-sm over the frost veil.
    + + diff --git a/docs/design-system/preview/theme-toggle.html b/docs/design-system/preview/theme-toggle.html new file mode 100644 index 0000000..491abf8 --- /dev/null +++ b/docs/design-system/preview/theme-toggle.html @@ -0,0 +1,66 @@ + + + + + + +Theme toggle + + + +
    +
    +
    +
    © 2024 | Dispatches
    +
    + + + +
    +
    +
    light · paper · #f6f6fa
    +
    +
    +
    +
    © 2024 | Dispatches
    +
    + + + +
    +
    +
    dark · night · #0f1126
    +
    +
    + + diff --git a/docs/design-system/preview/tokens-dark.html b/docs/design-system/preview/tokens-dark.html new file mode 100644 index 0000000..d47e30c --- /dev/null +++ b/docs/design-system/preview/tokens-dark.html @@ -0,0 +1,34 @@ + + + + + + +Dark semantic tokens + + + +
    +
    --bgnight · #0f1126
    +
    --bg-hovermoon / 11%
    +
    --fgmoon / 76% (body)
    +
    --fg-strongmoon · headings · code
    +
    --fg-mutedmeta · dividers
    +
    --bordermoon / 16%
    +
    --accentplum-300 · focus + link hover
    +
    --accent-softcode chip backdrop
    +
    + + diff --git a/docs/design-system/preview/tokens-light.html b/docs/design-system/preview/tokens-light.html new file mode 100644 index 0000000..efd41b5 --- /dev/null +++ b/docs/design-system/preview/tokens-light.html @@ -0,0 +1,34 @@ + + + + + + +Light semantic tokens + + + +
    +
    --bgpaper · #f6f6fa
    +
    --bg-hoverink / 9%
    +
    --fgink / 62% (body)
    +
    --fg-strongink · headings · code
    +
    --fg-mutedmeta · dividers
    +
    --borderink / 13%
    +
    --accentplum-700 · focus + link hover
    +
    --accent-softcode chip backdrop
    +
    + + diff --git a/docs/design-system/preview/type-families.html b/docs/design-system/preview/type-families.html new file mode 100644 index 0000000..6cf5413 --- /dev/null +++ b/docs/design-system/preview/type-families.html @@ -0,0 +1,33 @@ + + + + + + +Type families + + + +
    +
    Inter400 / 600
    headings · UI
    +
    The quiet rails of hierarchy.
    +
    +
    +
    Source Serif 4variable · italic
    prose body
    +
    Long-form posts feel like a quiet book — not a SaaS landing page.
    +
    +
    +
    Monosystem / JetBrains
    code only
    +
    LazySequenceProtocol<Element>
    +
    + + diff --git a/docs/design-system/preview/type-scale.html b/docs/design-system/preview/type-scale.html new file mode 100644 index 0000000..c171da6 --- /dev/null +++ b/docs/design-system/preview/type-scale.html @@ -0,0 +1,28 @@ + + + + + + +Type scale + + + +
    +
    text-4xl
    Page title
    36 / 2.25rem
    +
    text-3xl
    Section header
    30 / 1.875rem
    +
    text-2xl
    Article h2
    24 / 1.5rem
    +
    text-xl
    Article h3
    20 / 1.25rem
    +
    text-base
    Body · card title
    16 / 1rem
    +
    text-sm
    Card subtitle · BackToPrev
    14 / 0.875rem
    +
    text-xs
    Footer · meta
    12 / 0.75rem
    +
    + + diff --git a/docs/design-system/preview/wordmark.html b/docs/design-system/preview/wordmark.html new file mode 100644 index 0000000..93df28d --- /dev/null +++ b/docs/design-system/preview/wordmark.html @@ -0,0 +1,62 @@ + + + + + + +Wordmark + + + +
    +
    Light · ink on paperassets/wordmark{,-bare}.svg
    +
    + Dispatches — Technical writing on topics of personal interest. + Dispatches +
    +
    + +
    +
    Dark · moon on nightassets/wordmark-dark{,-bare-dark}.svg
    +
    + Dispatches — Technical writing on topics of personal interest. + Dispatches +
    +
    + + diff --git a/justfile b/justfile index 72bcba0..a420d78 100644 --- a/justfile +++ b/justfile @@ -101,6 +101,10 @@ spellcheck-all: lint: npm run lint +# Test: runs unit tests +test: + npm run test:unit + # Lint-fix: auto-fixes ESLint issues where possible lint-fix: npm run lint:fix @@ -109,7 +113,7 @@ lint-fix: lint-markdown: npm run lint:markdown -# Validate: runs all validation checks (lint + spellcheck + build + links + feed) +# Validate: runs all validation checks (lint + unit tests + spellcheck + build + links + feed) validate: npm run validate:all @@ -140,4 +144,4 @@ qa-report: # QA-codegen: opens Playwright code generator qa-codegen: - npm run qa:codegen \ No newline at end of file + npm run qa:codegen diff --git a/package-lock.json b/package-lock.json index 4edcae1..9fc98c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "@astrojs/tailwind": "^5.1.5", "@eslint/js": "^10.0.1", "@fontsource/inter": "^5.2.8", - "@fontsource/lora": "^5.2.8", "@tailwindcss/typography": "^0.5.19", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", @@ -1900,15 +1899,6 @@ "url": "https://github.com/sponsors/ayuhito" } }, - "node_modules/@fontsource/lora": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/lora/-/lora-5.2.8.tgz", - "integrity": "sha512-AQlfsHw4TP1x/eb2IZ6VjQ70ctKa39m9JN9A4zlvDOeKYLrCs+GaYIEQ86Y6YfSPGHn01bErXkRcyktOW0LOPQ==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", diff --git a/package.json b/package.json index b57d513..9c00817 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "spellcheck:all": "npm run spellcheck && npm run build && npm run spellcheck:html", "validate:links": "node scripts/validate-links.js", "validate:feed": "node scripts/validate-feed.js", - "validate:all": "npm run lint && npm run spellcheck && npm run build && npm run spellcheck:html && npm run validate:links && npm run validate:feed", + "validate:all": "npm run lint && npm run test:unit && npm run spellcheck && npm run build && npm run spellcheck:html && npm run validate:links && npm run validate:feed", "test:unit": "vitest run", "test:ci": "npm run lint && npm run test:unit && npm run spellcheck && npm run build && npm run spellcheck:html && npm run validate:links && npm run validate:feed", "test:ci:verbose": "echo '🔍 Running CI validation locally...' && npm run lint && echo '✓ Linting passed' && npm run test:unit && echo '✓ Unit tests passed' && npm run spellcheck && echo '✓ Source spell check passed' && npm run build && echo '✓ Build succeeded' && npm run spellcheck:html && echo '✓ HTML spell check passed' && npm run validate:links && echo '✓ Link validation passed' && npm run validate:feed && echo '✓ Feed validation passed' && echo '✅ All CI checks passed!'", @@ -43,7 +43,6 @@ "@astrojs/tailwind": "^5.1.5", "@eslint/js": "^10.0.1", "@fontsource/inter": "^5.2.8", - "@fontsource/lora": "^5.2.8", "@tailwindcss/typography": "^0.5.19", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", diff --git a/public/Logo-144.jpeg b/public/Logo-144.jpeg deleted file mode 100644 index aba9e59..0000000 Binary files a/public/Logo-144.jpeg and /dev/null differ diff --git a/public/Logo.jpeg b/public/Logo.jpeg deleted file mode 100644 index b16a87e..0000000 Binary files a/public/Logo.jpeg and /dev/null differ diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png index 75407a6..a1a80bc 100644 Binary files a/public/android-chrome-192x192.png and b/public/android-chrome-192x192.png differ diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png deleted file mode 100644 index 3a610a8..0000000 Binary files a/public/android-chrome-512x512.png and /dev/null differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index fe77295..aada28c 100644 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/public/default-og-image.jpg b/public/default-og-image.jpg deleted file mode 100644 index 4251ce9..0000000 Binary files a/public/default-og-image.jpg and /dev/null differ diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png index f9bf9e7..82a1fbd 100644 Binary files a/public/favicon-16x16.png and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png index 080e056..ce7234b 100644 Binary files a/public/favicon-32x32.png and b/public/favicon-32x32.png differ diff --git a/public/favicon-48x48.png b/public/favicon-48x48.png index 97d64c8..1e29b8b 100644 Binary files a/public/favicon-48x48.png and b/public/favicon-48x48.png differ diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..d967b7b --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1,1143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/MonaSans-Light.woff2 b/public/fonts/MonaSans-Light.woff2 deleted file mode 100644 index b7eab48..0000000 Binary files a/public/fonts/MonaSans-Light.woff2 and /dev/null differ diff --git a/public/fonts/MonaSans-Regular.woff2 b/public/fonts/MonaSans-Regular.woff2 deleted file mode 100644 index f3ab5d9..0000000 Binary files a/public/fonts/MonaSans-Regular.woff2 and /dev/null differ diff --git a/public/fonts/MonaSans-SemiBold.woff2 b/public/fonts/MonaSans-SemiBold.woff2 deleted file mode 100644 index 2b85d65..0000000 Binary files a/public/fonts/MonaSans-SemiBold.woff2 and /dev/null differ diff --git a/public/fonts/atkinson-bold.woff b/public/fonts/atkinson-bold.woff deleted file mode 100644 index e7f8977..0000000 Binary files a/public/fonts/atkinson-bold.woff and /dev/null differ diff --git a/public/fonts/atkinson-regular.woff b/public/fonts/atkinson-regular.woff deleted file mode 100644 index bbe09c5..0000000 Binary files a/public/fonts/atkinson-regular.woff and /dev/null differ diff --git a/public/fonts/source-serif-4-latin-italic.woff2 b/public/fonts/source-serif-4-latin-italic.woff2 new file mode 100644 index 0000000..559f86e Binary files /dev/null and b/public/fonts/source-serif-4-latin-italic.woff2 differ diff --git a/public/fonts/source-serif-4-latin.woff2 b/public/fonts/source-serif-4-latin.woff2 new file mode 100644 index 0000000..8f187e0 Binary files /dev/null and b/public/fonts/source-serif-4-latin.woff2 differ diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png deleted file mode 100644 index 7e728ce..0000000 Binary files a/public/mstile-150x150.png and /dev/null differ diff --git a/public/og-image-dark.png b/public/og-image-dark.png new file mode 100644 index 0000000..666ebf0 Binary files /dev/null and b/public/og-image-dark.png differ diff --git a/public/og-image.png b/public/og-image.png new file mode 100644 index 0000000..006e495 Binary files /dev/null and b/public/og-image.png differ diff --git a/public/rss-image.jpg b/public/rss-image.jpg deleted file mode 100644 index 04cd144..0000000 Binary files a/public/rss-image.jpg and /dev/null differ diff --git a/public/rss-image.png b/public/rss-image.png new file mode 100644 index 0000000..443422e Binary files /dev/null and b/public/rss-image.png differ diff --git a/public/site.webmanifest b/public/site.webmanifest index e8671c5..2edb3bc 100644 --- a/public/site.webmanifest +++ b/public/site.webmanifest @@ -4,18 +4,18 @@ "description": "Technical writing on topics of personal interest.", "icons": [ { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" + "src": "/favicon.svg", + "type": "image/svg+xml", + "sizes": "any" }, { - "src": "/android-chrome-512x512.png", - "sizes": "512x512", + "src": "/android-chrome-192x192.png", + "sizes": "192x192", "type": "image/png" } ], - "theme_color": "#ffffff", - "background_color": "#ffffff", + "theme_color": "#f6f6fa", + "background_color": "#f6f6fa", "display": "standalone", "start_url": "/" } diff --git a/src/components/BackToPrev.astro b/src/components/BackToPrev.astro index aca2c07..4de0992 100644 --- a/src/components/BackToPrev.astro +++ b/src/components/BackToPrev.astro @@ -6,15 +6,15 @@ type Props = { const { href } = Astro.props; --- - +
    diff --git a/src/components/BackToTop.astro b/src/components/BackToTop.astro index f3d9b42..013d2c3 100644 --- a/src/components/BackToTop.astro +++ b/src/components/BackToTop.astro @@ -1,12 +1,12 @@ -