✨ What's new
Cover images in post cards
Post and gallery cards now optionally display a cover image at the top (showCoverImages in SITE config, default true).
- Blog posts — resolves from frontmatter
ogImage; falls back to the dynamically generated/posts/<slug>/index.pngproduced at build time (same behavior as Pagefind: requires a priorpnpm buildin dev mode) - Galleries — resolves from frontmatter
coverImage; falls back to the first image found in the gallery folder (alphabetical order), matching the behavior of the/gallerieslisting page - The cover image is wrapped in a navigable
<a>link (aria-hidden,tabindex="-1") so it's clickable without duplicating the accessible title link
Configurable grid layout on the home page
A new indexPostsGrid flag (default false) renders the Recent Posts section on the home page as a responsive 3-column grid — identical to the /posts listing page. The Featured section is unaffected and keeps its fixed 2-column layout.
Per-tag OG images
Each tag page now generates a dedicated branded OG image at build time (/tags/<tag>/og.png) using a new Satori template. Tag pages also receive a proper og:type, og:site_name, og:image dimensions, and twitter:creator meta tags.
Enriched JSON-LD structured data
BlogPosting schema now includes mainEntityOfPage, description, url, and publisher fields for better Google Rich Results coverage. Canonical URLs are always derived from SITE.website (never localhost) with consistent trailing-slash normalization.
Reading time on cards and post headers
A getReadingTime() utility strips markdown/MDX syntax before counting words at ~200 wpm. Reading time is shown inline with the publication date on every card and in the post header metadata row.
Configurable tag pills on cards
Tags are now rendered as context-aware colored pills on each card (accent / amber for featured / purple for galleries), capped at 4 tags. Controlled by the showTagsInCards flag in SITE config.
🔧 Improvements & chores
Privacy-first social links (breaking for forks)
Personal social URLs and the edit-post URL have been moved out of source code and into environment variables (PUBLIC_SOCIAL_GITHUB, PUBLIC_SOCIAL_X, PUBLIC_SOCIAL_LINKEDIN, PUBLIC_SOCIAL_EMAIL, PUBLIC_EDIT_POST_URL). Unset variables are automatically filtered — no broken UI, no errors.
Forkers: copy
.env.example→.envand fill in your own values. For production, set the variables in your platform's environment settings (Vercel, Netlify, etc.).
Font: Cartograph CF → Fira Code
Cartograph CF requires a commercial license for distribution, making it unsuitable for an open-source project. It has been replaced with Fira Code (SIL Open Font License 1.1). All --font-cartograph / font-cartograph references have been renamed to --font-firacode across components, layouts, and stylesheets.
Dependency updates
Enabled native builds for esbuild and sharp in the pnpm workspace configuration. Updated project dependencies.
File naming
Renamed internal demo content files from Spanish to English for consistency.
GitHub Sponsors
Added FUNDING.yml to enable GitHub Sponsors on the repository.
🐛 Bug fixes
- RSS feed: Updated accessibility label and removed redundant screen reader text from the RSS icon link in the header.
📋 Full changelog
ba10876 feat(cards): add configurable cover images and home grid layout
d2815ae chore(privacy): move personal data to env vars to prevent fork spam
2e56ab6 fix: update RSS feed accessibility label and remove redundant screen reader text
e5a0e29 feat(seo): enrich JSON-LD, normalize canonicals, and add per-tag OG images
2139f97 feat(blog): add reading time and configurable tag pills to posts
3daac52 chore(fonts): replace Cartograph CF with Fira Code due to license requirements
cddfa56 feat: enable builds for esbuild and sharp in pnpm workspace configuration and update of dependencies
41507ae Change the names of the files from spanish to english
8aa345e Create FUNDING.yml
Full diff: v1.2.0...v1.3.0