200 Commits

Author SHA1 Message Date
Ricardo
36f17d1a1f feat: add unfurl cards to blog page and homepage recent posts
Use two-strategy approach to work around async shortcode limitation
in deeply nested Nunjucks includes:

- blog.njk: async {% unfurl %} shortcode (top-level, works fine)
- recent-posts.njk: sync {{ url | unfurlCard | safe }} filter
  (reads from pre-populated disk cache)

eleventy.before hook scans content files and pre-fetches all
interaction URLs before templates render, ensuring the sync filter
always has data — even on first build.
2026-02-20 16:10:25 +01:00
Ricardo
ec02afb611 fix: split education and languages into separate sections
cv-education.njk no longer renders languages — use the standalone
cv-languages section instead.
2026-02-20 16:10:15 +01:00
Ricardo
66e55af7ee feat: add configurable CV page layout with builder support
CV page now reads layout config from cv-page.json when available,
supporting single-column, two-column, and full-width hero layouts with
configurable sections, sidebar widgets, and footer columns. Falls back
to the previous hardcoded layout when no config exists.
2026-02-20 15:17:32 +01:00
Ricardo
a54600b003 fix: show untyped CV items in both work and personal views
Items without a type field (existing data before type feature was added)
were only appearing in "personal" filtered views. Since the /cv/ page uses
work-only variants, all existing untyped data was hidden. Changed filtering
so untyped items appear in both work and personal views.

Also guard cv.skills dictsort in cv.njk against undefined.
2026-02-20 13:55:52 +01:00
Ricardo
3bf0e78f74 feat: add filtered section templates for work/personal type distinction
Add thin-wrapper templates for work/personal filtering of CV sections:
- 8 new templates: cv-{experience,education,skills,interests}-{personal,work}.njk
- cv-languages.njk: standalone languages section (split from education)
- homepage-section.njk: 9 new routes for filtered variants
- cv.njk: uses work-only variants for the /cv/ page
- Base templates: filterType support in experience, education, skills, interests
- _data/cv.js: skillTypes and interestTypes fallback fields
2026-02-20 13:11:37 +01:00
Ricardo
334b8fdcf5 fix: revert unfurl from recent-posts section
Async shortcodes inside deeply nested Nunjucks includes
(homepage-builder → homepage-section → recent-posts) cause silent
template failures. Keep unfurl in top-level collection pages only.
2026-02-20 12:53:42 +01:00
Ricardo
0f496d624f feat: add unfurl cards to collection views and homepage
Show rich link preview cards in bookmarks, likes, replies, reposts
collection pages and the homepage recent posts section. URLs are
fetched once and cached — the same cache serves all templates.
2026-02-20 12:39:11 +01:00
Ricardo
9ab4ebb84a feat: add unfurl cards to reply context (likes, bookmarks, replies, reposts)
The target URL in likes, bookmarks, replies, and reposts now renders
as a rich OpenGraph card via the unfurl shortcode instead of a bare
link. The raw URL remains below the card for h-cite microformat
compatibility. Results are cached in .cache/unfurl/ for 1 week.
2026-02-20 12:01:55 +01:00
Ricardo
656a70eb0e feat: graceful no-JS fallback and noscript handling
- Add <noscript><style> in base.njk that unhides x-cloak/x-show content,
  hides FAB and tab buttons when JS is disabled (content stacks instead)
- Add noscript message on search page with links to blog/categories
- Add noscript banner on interactions page explaining inbound tab needs JS
2026-02-19 17:35:21 +01:00
Ricardo
03ace58be5 feat: add ActivityPub badge and platform detection for interactions
- Add ActivityPub/Fediverse platform badge (purple, network icon) to
  interactions page alongside existing Mastodon and Bluesky badges
- Detect platform from Bridgy source URLs and author URLs for
  webmention.io items that lack a platform field
- Filter self-referencing syndication URLs from "Also on" footer so
  self-hosted AP posts don't show a redundant link back to the site
2026-02-19 16:52:44 +01:00
Ricardo
cb68b7be00 fix: add rel=nofollow to FAB admin links
AI crawlers (GPTBot) were following edit/create links in the static
HTML, flooding the server with /posts/edit and /session/login requests.
Adding nofollow tells well-behaved crawlers to skip these admin-only links.
2026-02-18 22:17:38 +01:00
Ricardo
2ebe63ffff fix: use eleventyComputed for OG slug to avoid Nunjucks race condition
Eleventy 3.x renders Nunjucks templates in parallel, causing page.url
to return wrong values in {% set %} tags. This caused OG images to be
mismatched between pages (e.g., bookmark showed note's OG image).

Move ogSlug and hasOgImage computation to eleventyComputed, which runs
during the sequential data cascade phase before parallel rendering.
The computed values are then available as plain template variables.

Refs: https://github.com/11ty/eleventy/issues/3183
2026-02-18 17:17:30 +01:00
Ricardo
8d800e2c28 fix: derive OG slug from page.url to avoid Nunjucks race condition
page.fileSlug suffers from a race condition in Eleventy 3.x parallel
rendering where Nunjucks shares state across template compilations,
causing slugs to get mixed up between pages. page.url is always
correct, so derive the OG slug from it instead.
2026-02-18 16:48:11 +01:00
Ricardo
daf813e192 fix: wrap webmentions widget in is-land for lazy loading
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.
2026-02-18 12:20:38 +01:00
Ricardo
c3eb04570c feat: add zachleat.com-inspired theme enhancements
- 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
2026-02-18 11:16:33 +01:00
Ricardo
fe06fe3f4f feat: auto-generate OpenGraph images for posts without photos
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.
2026-02-18 08:37:50 +01:00
Ricardo
ed24ac47bd feat: add 3-dot menu to feedland widget
Links to blogroll page, OPML export, and FeedLand source.
Matches Dave Winer's blogroll.js menu pattern.
2026-02-17 18:35:01 +01:00
Ricardo
69e0032891 feat: use lastItemAt for feed freshness in feedland widget
Shows when a feed last published new content instead of when it was
last checked. Falls back to lastFetchAt for blogs not yet re-synced.
2026-02-17 17:43:53 +01:00
Ricardo
9963578bab refactor: rewrite feedland widget with pure divs, no table element
Eliminates persistent horizontal scrollbar caused by <table> layout.
Uses flexbox divs exclusively for predictable overflow behavior.
2026-02-17 17:18:06 +01:00
Ricardo
5a3fb29d85 fix: eliminate horizontal scrollbar in feedland widget 2026-02-17 17:08:20 +01:00
Ricardo
8aeef55ed0 fix: ensure feed timestamp stays visible after title in feedland widget 2026-02-17 16:59:25 +01:00
Ricardo
1865ff130d fix: move feed timestamp to right of title in feedland widget 2026-02-17 16:54:00 +01:00
Ricardo
c2a6d9b280 fix: use flexbox for feed title row to keep 'when' timestamp visible 2026-02-17 16:41:38 +01:00
Ricardo
a25cc140ee fix: restore 'when' timestamp visibility in FeedLand widget 2026-02-17 16:24:31 +01:00
Ricardo
3da40ce3b0 fix: remove horizontal scrollbar from FeedLand widget 2026-02-17 16:09:36 +01:00
Ricardo
4662f2e911 fix: make FeedLand widget responsive to fill sidebar width 2026-02-17 16:03:32 +01:00
Ricardo
fec999793d fix: FeedLand widget click-to-expand and dark mode for expanded items
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.
2026-02-17 15:54:31 +01:00
Ricardo
690a10ecf8 feat: add FeedLand sidebar widget
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.
2026-02-17 15:26:26 +01:00
Ricardo
e2d35b541e feat: add source tabs and recent sort to blogroll widget
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.
2026-02-17 14:20:19 +01:00
Ricardo
29a014506d feat: add "Edit this post" button to FAB menu
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>
2026-02-15 04:11:20 +01:00
Ricardo
dcccf29713 feat: add personal/work project section templates
- 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>
2026-02-13 11:24:34 +01:00
Ricardo
28bc7a6c1b fix: load pagefind at end of body instead of deferred in head
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>
2026-02-13 11:03:02 +01:00
Ricardo
7cb0203adc fix: load pagefind once in base layout, eliminate duplicate scripts
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>
2026-02-13 10:50:32 +01:00
Ricardo
60b59949ef feat: site-wide webmentions widget with inbound/outbound tabs
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>
2026-02-13 09:51:18 +01:00
Ricardo
8eb5239906 fix: move post navigation from sidebar to main content area
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>
2026-02-13 09:04:19 +01:00
Ricardo
a4c121d203 fix: make post-navigation and webmentions sidebar widgets functional
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>
2026-02-13 08:53:35 +01:00
Ricardo
cf3586eadd feat: data-driven blog sidebars and fix recentPosts glob
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>
2026-02-13 00:13:25 +01:00
Ricardo
a92fa93780 feat: add changelog page and refactor footer to 4-zone grid
- 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>
2026-02-12 09:16:51 +01:00
Ricardo
7d1cd64af9 fix: increase GitHub widget content height to 420px
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:10:06 +01:00
Ricardo
ce21729408 fix: use fixed height instead of min-height for GitHub widget tabs
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>
2026-02-11 19:29:17 +01:00
Ricardo
eedcee70cb fix: stable height GitHub widget and consistent tab sizing
- 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>
2026-02-11 17:58:38 +01:00
Ricardo
6b7bc3644d fix: reorder GitHub widget tabs and add Repos tab
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>
2026-02-11 17:51:02 +01:00
Ricardo
06d0c93804 feat: replace static GitHub widget with dynamic tabbed widget
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>
2026-02-11 17:42:40 +01:00
Ricardo
ddbc983505 feat: add syntax highlighting for code blocks
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>
2026-02-11 10:21:31 +01:00
Ricardo
2b3e51042c feat: type-aware rendering in blog sidebar
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>
2026-02-11 09:44:12 +01:00
Ricardo
0c79da8d95 feat: type-aware rendering for recent posts section and sidebar widget
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>
2026-02-11 09:21:38 +01:00
Ricardo
37b323842b nav: promote /cv to top-level, remove /now from header
/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>
2026-02-11 08:38:29 +01:00
Ricardo
757db6a327 feat: add dedicated /cv page and simplify homepage fallback
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>
2026-02-11 04:10:45 +01:00
Ricardo
dd454bf4ce feat: render footer as responsive 3-column grid
Wraps footer items in a CSS grid that's 1 column on mobile, 2 on tablet,
3 on desktop. Each custom-html block fills one column.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:12:31 +01:00
Ricardo
b8ad6dbb25 style: show experience highlights as tags instead of bullet list
Matches the tag/pill style used by interests and skills sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 14:31:23 +01:00