Skip OG image generation, Pagefind indexing, and WebSub notification
during incremental rebuilds. These expensive operations only run on
full builds (container restart), not on every content change.
The webmentions sidebar widget uses Alpine.js + fetch API but was
missing the is-land on:visible wrapper that all other JS-dependent
sidebar widgets have. This defers its initialization until scrolled
into view, consistent with social-activity, github-repos, funkwhale,
blogroll, and feedland widgets.
The @zachleat/table-saw component requires tables to be wrapped in
<table-saw> elements. Added an Eleventy transform to do this
automatically for all HTML output.
Each collection page (articles, notes, photos, bookmarks, likes,
replies, reposts) now shows its own sparkline next to the heading,
showing that specific post type's frequency over the last 12 months.
- Add time-difference web component for relative dates
- Add @zachleat/table-saw for responsive tables
- Add webmention facepile styling with bookmarks support
- Add OG image thumbnails to post navigation
- Add @11ty/is-land for lazy widget hydration
- Wrap sidebar widgets in is-land for deferred loading
- Lazy-load webmention avatars with is-land
- Add @zachleat/filter-container for blog archive filtering
- Add posting frequency sparkline to blog header
- Inline critical CSS and defer full stylesheet loading
Malformed HTML (e.g. unescaped quotes in iframe title attributes) caused
html-minifier-terser to throw a fatal parse error, killing the entire
Eleventy build. Now catches the error, logs a warning, and returns the
unminified content so the build completes.
Eleventy v3 parses YYYY-MM-DD- from filenames and removes it from
page.fileSlug. The OG generator was using the full filename (with
date prefix) causing a slug mismatch — hasOgImage filter checked
for 'slug.png' while the file was 'YYYY-MM-DD-slug.png'.
Also removes debug logging from hasOgImage filter.
Two fixes:
- extractFirstImage filter now skips <img> tags with the hidden attribute,
preventing the author avatar microformat from being used as og:image
- Clear NODE_OPTIONS in the OG subprocess env and pass --max-old-space-size
as a direct CLI flag to avoid conflict with parent process settings
The OG generation in the eleventy.before hook consumed too much memory
alongside Eleventy's data cascade, causing the Eleventy process to be
OOM-killed on Cloudron. Fix by running OG generation in a separate
child process with its own 768MB heap limit. Also write the manifest
incrementally (every 10 images) to preserve progress if interrupted.
- Add _textcasting extension to JSON feed with support/monetization config
- Add feedAttachments filter for photo/audio/video media in feed items
- Add content_text and date_modified fields to feed items
- Add protocol badges (ATmosphere, Fediverse, Web) on reply posts
- Add support configuration via environment variables in site data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses Satori + @resvg/resvg-js to create branded 1200x630 social
preview cards at build time. Cards show post title, type badge,
date, and site name on a dark background with blue accent.
Generated images are cached in .cache/og/ (persistent on Cloudron)
and passthrough-copied to the output. Posts with photos continue
using their own images. Untitled posts (notes) use body text.
Uses markdown-it-anchor to generate linkable IDs on h2-h4 headings.
Headings become clickable links with a subtle # indicator on hover.
Includes scroll-margin-top so anchored headings don't hide behind
the sticky header.
Add row selection and expand/collapse behavior matching Dave Winer's
blogroll.js: first click selects, second click (or caret click) expands
to show up to 5 recent items fetched from blogroll API. Items cached
after first fetch. Added dark mode styles for expanded items.
Replicates Dave Winer's blogroll.js visual rendering (240px bordered
container, Ubuntu/Rancho fonts, Title/When sort, caret wedges, truncated
titles, relative timestamps, "Powered by FeedLand" footer) using Alpine.js
and the blogroll API instead of jQuery + external scripts.
Registered in all three sidebar types (homepage, blog listing, blog post)
and in the fallback sidebar.
Sidebar widget now fetches blogs sorted by recently updated and groups
them into tabs by source type (Microsub/FeedLand). Tabs only appear
when multiple source types exist. Each tab shows up to 8 blogs.
When viewing a post that has mpUrl in its frontmatter, the FAB menu
shows an "Edit this post" link at the top that redirects to the
Indiekit admin edit form via /posts/edit?url=<mpUrl>.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- cv-projects-personal.njk: filters projects with projectType=personal (or unset)
- cv-projects-work.njk: filters projects with projectType=work
- CV page now only shows work projects
- Homepage section dispatcher routes both new types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The defer + DOMContentLoaded queue approach failed silently when
pagefind-ui.js couldn't load. Moving the script to end of body
ensures all DOM elements exist and processes the queue immediately
after the script loads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pagefind CSS/JS is now loaded once in base.njk <head> with defer.
A tiny initPagefind() helper queues widget inits until DOMContentLoaded
when PagefindUI is available. Removes duplicate <link>/<script> tags
from all sidebar widgets, search page, and 404 page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces the per-post webmentions sidebar widget (which was redundant
with the main content webmentions section) with a site-wide widget
showing recent inbound webmentions (via API) and outbound interactions
(from Eleventy collections). Available in all sidebars.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Post navigation (prev/next) now renders below the syndication block
in the main content flow, matching how listing pages work. Removed
from sidebar widget system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Post navigation now uses previousInCollection/nextInCollection filters
to find adjacent posts (avoids Nunjucks loop scoping bug). Webmentions
sidebar widget now uses webmentionsForUrl and webmentionsByType filters
instead of non-existent filter function.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix recentPosts collection glob (content/posts/ → content/) so the
widget actually finds posts. Extract blog-sidebar widgets into reusable
partials. Make both sidebar.njk (listing pages) and blog-sidebar.njk
(post pages) configurable via homepageConfig.blogListingSidebar and
homepageConfig.blogPostSidebar, with fallback to current hardcoded
widgets for backward compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New /changelog/ page with Alpine.js tabbed interface showing commits
across all indiekit repos, categorized into 7 groups with load-more
- Footer refactored from minimal feed links to responsive 4-zone grid:
Navigate, Content, Connect (social links), Meta (feeds + changelog)
- Footer uses grid-cols-2 on mobile, grid-cols-4 on desktop
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents all layout shift by locking the content area to h-[340px]
with overflow-y-auto for scrolling if content exceeds the area.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add min-h-[320px] to prevent layout shift when switching tabs
- Show 5 items per tab for consistent content height
- Simplify tab buttons to text-only at text-xs for compact layout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tab order: Commits (default), Repos, Featured, PRs.
Repos tab fetches full repo list from GitHub public API.
Featured tab shows curated projects from /githubapi.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses Alpine.js client-side fetching from /githubapi/api/* for live data.
Three tabs: Projects (featured repos), Commits (recent activity), PRs.
Follows the blogroll widget pattern for dynamic data loading.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Integrates @11ty/eleventy-plugin-syntaxhighlight (PrismJS) for
build-time syntax highlighting of fenced code blocks. Includes
a custom GitHub-inspired theme with dark mode support (.dark class).
All existing articles with triple-backtick code blocks will
automatically get highlighting on next Eleventy rebuild.
Also fixes overflow-x: hidden on .prose/.e-content that was
clipping scrollable code blocks — changed to overflow-x: clip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Recent Posts widget and Previous/Next navigation now show colored
icons and descriptive labels for likes, bookmarks, reposts, and
replies instead of "Untitled".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port the blog page's rich post-type rendering into both the homepage
recent-posts section and the sidebar widget. Likes, bookmarks, reposts,
replies, and photos now show colored icons, target URLs, and content
previews instead of generic "Untitled" cards.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
/now is already in the /slashes submenu dropdown, so having it
top-level was redundant. /cv gets promoted to main navbar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move CV content to a standalone /cv page that reuses the section partials
from the homepage builder. Simplify home.njk from a 3-tier to 2-tier
fallback (plugin config OR recent posts + explore links). Add /cv to
the slash pages navigation dropdown.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change all webmention fetch URLs from /webmentions-api/api/mentions
to /webmentions/api/mentions to match the new @rmdes/indiekit-endpoint-webmention-io
plugin which replaces both the upstream viewer and the proxy plugin.
Build-time feed now fetches from local Indiekit API instead of
webmention.io directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>