Commit Graph

58 Commits

Author SHA1 Message Date
Ricardo
e236b4bf65 a11y: comprehensive WCAG 2.1 Level AA accessibility audit
- Add skip-to-main-content link and main content ID target
- Add prefers-reduced-motion media queries for all animations
- Enhance visible focus indicators (2px offset, high-contrast ring)
- Replace ~160 text-surface-500 instances with text-surface-600/dark:text-surface-400
  for 4.5:1+ contrast ratio compliance
- Add aria-hidden="true" to ~30+ decorative SVG icons across sidebars/widgets
- Convert facepile containers from div to semantic ul/li with role="list"
- Add aria-label to icon-only buttons (share, sort controls)
- Add sr-only labels to form inputs (webmention, search)
- Add aria-live="polite" to dynamically loaded webmentions
- Add aria-label with relative+absolute date to time-difference component
- Add keyboard handlers (Enter/Space) to custom interactive elements
- Add aria-label to nav landmarks (table of contents)
- Fix modal focus trap and dialog accessibility
- Fix lightbox keyboard navigation and screen reader announcements

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-07 18:58:08 +01:00
Ricardo
15b88b7087 feat: add skeleton loader to prevent FOUC during CSS load
Replace unstyled content flash with pulsing gray placeholder shapes
while the deferred Tailwind stylesheet loads. Uses a 'loading' class
on <html> that critical CSS uses to show skeleton / hide content,
removed by the stylesheet's onload handler.

Includes noscript fallback to bypass skeleton when JS is disabled.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-07 16:56:59 +01:00
Ricardo
596334ab38 feat: redesign navigation - curated header, updated footer, comprehensive /slashes/
Replace the 22-item "/" dropdown with a curated "Pages" dropdown (Blogroll,
Podroll, News, All Pages). Add /now to header nav. Move CV and Digest to
footer only. Add auth-gated Dashboard to footer Navigate column. Remove
Interactions from footer Content column.

Refactor /slashes/ into a comprehensive site map with three sections: Pages
(dynamic CMS pages), Activity Feeds (plugin pages), and Site Pages (theme
.njk pages like /graph, /changelog, /featured, /starred, etc.).

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-06 14:05:22 +01:00
Ricardo
2ca3e047a4 feat: UI overhaul — accent color, Inter font, widget icons, diversified colors
- Add teal accent color scale and activate Inter font via @font-face
- Neutralize nav/footer hovers from primary blue to surface neutrals
- Apply accent color to hero subtitle, FAB, CTA buttons, card hovers
- Fix reply post-type color from generic primary to distinctive sky blue
- Create centralized icon macro (icon.njk) with 24 reusable SVG icons
- Add per-widget-type icons and colored left-accent borders to all sidebars
- Update .p-category tags from blue to neutral surface with border
- Diversify color vocabulary: red (likes), amber (bookmarks/blogroll),
  green (reposts), purple (funkwhale), sky (replies), orange (subscribe)

Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
2026-03-04 11:21:39 +01:00
Ricardo
6cfb92818e feat: include share-post.js in base layout 2026-02-28 08:21:05 +01:00
Ricardo
4c8c44a49e feat: add save-for-later buttons to frontend pages
Add shared save-later.js module and per-item save buttons to
blogroll, podroll, listening, and news pages. Buttons are hidden
by default and only visible when logged in. Posts to the readlater
plugin API at /readlater/save.
2026-02-27 16:17:16 +01:00
Ricardo
e2c40468b6 feat: add fullscreen lightbox for article images
Alpine.js component that lets visitors click any image inside
article content to view it fullscreen with keyboard navigation
(arrow keys, Escape to close) and prev/next buttons.
2026-02-27 10:14:35 +01:00
Ricardo
581c585677 feat: add digest feed discovery link and navigation items 2026-02-26 08:27:57 +01:00
Ricardo
de043020ac feat: add RSS per-category feed template, discovery links, and WebSub notifications
- Create category-feed.njk (RSS 2.0 pagination template)
- Add conditional <link rel="alternate"> tags for category pages in base.njk
- Extend WebSub hub notifications to include per-category feed URLs
2026-02-24 22:45:14 +01:00
Ricardo
4c2828f6fe fix: remove contentImage from OG meta to prevent sidebar image leaking
The extractFirstImage filter picks up <img> tags from the full rendered
page content, including sidebar widgets (like recent post thumbnails).
This caused og:image to reference sidebar OG images from OTHER posts
instead of falling through to the __OG_IMAGE_PLACEHOLDER__ that the
og-fix transform resolves from outputPath.

Only ogPhoto and image (from frontmatter) are now used as explicit
image sources. All other cases use the placeholder resolved by the
og-fix transform.
2026-02-24 20:52:07 +01:00
Ricardo
e56e2c67a5 fix: use Eleventy transform to resolve OG images from outputPath
The Eleventy 3.x parallel rendering race condition (#3183) makes
page.url unreliable in templates — it changes between lines during
concurrent processing. All previous approaches (eleventyComputed,
capturing page.url early with {% set %}) failed because the page
object is shared and mutated by parallel renders.

The transform approach works because outputPath is passed as a
function parameter (not read from a shared object) and IS correct
since files are written to the right location. The transform:

- Derives the OG slug from outputPath pattern matching
- Replaces __OG_IMAGE_PLACEHOLDER__ with the correct OG image URL
- Replaces __TWITTER_CARD_PLACEHOLDER__ with the correct card type
- Fixes og:url and canonical URL from outputPath
2026-02-24 20:31:24 +01:00
Ricardo
ee068c7e5c fix: use _pageUrl for homepage check (consistency with race condition fix) 2026-02-24 20:25:46 +01:00
Ricardo
42a5c67896 feat: add Markdown for Agents — serve clean Markdown to AI agents
Generate index.md alongside index.html for /articles/ at build time.
Agents can access clean Markdown via .md URL extension or Accept:
text/markdown content negotiation. Includes configurable content-signal
policy (ai-train, search, ai-input) and a master on/off toggle via
MARKDOWN_AGENTS_ENABLED env var.
2026-02-24 20:24:06 +01:00
Ricardo
0d439966f7 fix: guard page.url for falsy values in ogSlug computation
Pages with permalink:false (like about.njk) have page.url as false,
which crashes inline string operations. Use the ogSlug filter with
(page.url or "") guard to handle falsy values safely. Also removes
debug comment from previous debugging session.
2026-02-24 19:57:10 +01:00
Ricardo
520bc5f582 debug: inline ogSlug computation + debug comment to diagnose race condition
Computes ogSlug using inline Nunjucks string ops instead of filter call.
Adds HTML debug comment showing page.url, permalink, and computed ogSlug
to diagnose Eleventy 3.x parallel rendering race condition.
2026-02-24 19:39:59 +01:00
Ricardo
ad8af6f027 fix: use page.url instead of permalink for ogSlug in templates
permalink is set by eleventyComputed which cross-contaminates return
values across pages during Eleventy 3.x parallel rendering. page.url
is set by Eleventy's internal pipeline and is correct in templates
(verified via og:url meta tag which always shows the right URL).
2026-02-24 18:54:39 +01:00
Ricardo
7110ba3879 fix: compute ogSlug from permalink in template to avoid Eleventy 3.x race condition
Both page.url AND page.inputPath are unreliable in eleventyComputed due to
Eleventy 3.x parallel rendering (issue #3183). They return values from OTHER
pages being processed concurrently, causing og:image meta tags to reference
wrong OG images.

Fix: compute ogSlug directly in base.njk from the permalink data value using
existing Nunjucks filters (ogSlug, hasOgImage). permalink comes from frontmatter
(per-file data) and is immune to cross-page contamination.
2026-02-24 18:33:46 +01:00
Ricardo
910889cde8 fix: remove trailing slash from site.url to prevent double-slash URLs
site.url had a trailing slash (added for Mastodon rel=me verification),
which caused double slashes in all URL constructions like
{{ site.url }}/auth → https://rmendes.net//auth

This broke IndieAuth login — indielogin.com read the authorization_endpoint
link tag with //auth and redirected users there, which 404'd in nginx.

Split into site.url (no slash, for URL construction) and site.me /
site.author.url (with slash, for Mastodon rel=me strict matching).

Also fixed twitter:image meta tags to use smart slash logic matching
the og:image pattern (check if path starts with / before prepending one).
2026-02-24 16:18:52 +01:00
Ricardo
5d8222e5ae fix: vendor Alpine.js and lite-youtube-embed locally instead of CDN
jsdelivr CDN outages (503) break Alpine.js loading, making all
interactive components non-functional. Bundle vendor JS/CSS locally
to eliminate external CDN dependency.
2026-02-22 16:24:43 +01:00
Ricardo
8597856589 feat: add fediverse remote interaction button and syndication platform buttons
Add a Fediverse button to the "Also on" footer for posts syndicated via
self-hosted ActivityPub. Clicking it redirects users to their own instance
via authorize_interaction so they can like/boost/reply natively. Instance
is stored in localStorage for repeat visits, with a modal for first-time
entry and Shift+click to change.

Also adds branded syndication buttons for LinkedIn and IndieNews, and
replaces the heuristic Mastodon URL detection with exact matching against
the configured MASTODON_INSTANCE.
2026-02-22 15:56:01 +01:00
Ricardo
f3268ed3f9 fix: load comments.js before Alpine in head (correct defer order)
Alpine CDN uses queueMicrotask to auto-start, which fires between
defer scripts. comments.js must execute before Alpine so its
alpine:init listener is registered before Alpine.start() runs.

This is the Alpine-documented pattern: "Include [component scripts]
before Alpine's core JS file."
2026-02-21 22:46:43 +01:00
rmdes
fa7bfb26ea feat: add comment system components and recent comments widget
- Comment area on post pages (IndieAuth sign-in, submit, display)
- Alpine.js client-side component for auth flow and comment CRUD
- Recent comments sidebar widget with build-time data fetching
- Include comments.js in base layout, comments.njk before webmentions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 21:56:15 +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
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
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
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
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
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
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
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
523f538d1b fix: restore sidebar on blog and post type pages
The homepage builder's sidebar bypass was using homepageConfig (a global
Eleventy data file) to suppress the sidebar on ALL pages, not just the
homepage. Now only bypasses when page.url == "/" so blog, post type, and
plugin pages keep their normal sidebar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 10:12:46 +01:00
Ricardo
b4bc2f6f07 feat: wire homepage builder layout system and sidebar control
- base.njk: skip hardcoded sidebar when homepage builder is active
- homepage-builder.njk: implement 3 layouts (single-column, two-column,
  full-width-hero) with CSS grid and sidebar rendering
- homepage-section.njk: section type dispatcher (extracted for reuse)
- homepage-sidebar.njk: maps widget types to existing widget partials

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 19:08:27 +01:00
rmdes
32aea5ace9 feat: neutralize theme for fresh deployments
Strip personal data from templates so the theme ships clean for any
deployer. Collection pages now use generatePageOnEmptyData so empty
post types show encouraging placeholders instead of 404s. Navigation
is conditional on enabled post types and installed plugins. Sidebar
widgets split into individual components with plugin-aware visibility.
Slashes page explains required plugins for root-level page creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 15:16:29 +01:00
rmdes
2077a6bce9 Add Eleventy generator meta tag for leaderboard eligibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 19:27:55 +01:00
Ricardo
1470e0fbc2 fix: add self link for WebSub discovery compliance
WebSub spec requires both rel="hub" and rel="self" for
discovery. websub.rocks conformance test failed without self.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:25:36 +01:00
Ricardo
c17ca030c8 feat: add WebSub support for real-time feed updates
Advertise WebSub hub (websubhub.com) in three discovery layers:
- HTML <link rel="hub"> in page head
- <atom:link rel="hub"> in RSS feed
- "hubs" array in JSON Feed 1.1

Notify hub after each Eleventy build so subscribers receive
push updates when new content is published.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 16:34:37 +01:00
Ricardo
8229dfe3c7 feat: add admin UI for logged-in users (dashboard link + FAB)
Auth detection via /session/login probe with sessionStorage cache.
Dashboard link appears in desktop and mobile nav when authenticated.
Floating action button with quick-create menu for Note, Article,
Photo, Bookmark, and Page post types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 12:12:33 +01:00
Ricardo
73eb019f70 fix: add cache-busting hash to webmentions.js script tag
Prevents browsers from serving stale JS when the file changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 10:49:17 +01:00
Ricardo
d9c84cad80 feat: add Pagefind client-side search
Add Pagefind indexing after each Eleventy build with a search page at
/search/. Indexes main content only (sidebars excluded), supports dark
mode theming and URL query parameters (?q=).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 10:49:05 +01:00
Ricardo
e30200067c feat: add /podroll to nav menu, sort links alphabetically
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 08:09:19 +01:00
Ricardo
ed2044dd8b feat: add theme toggle to mobile navigation
- Add theme toggle button at bottom of mobile nav
- Share toggleTheme function between desktop and mobile
- Style mobile toggle to match nav item appearance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 15:01:24 +01:00
Ricardo
ba94a6e5c8 feat: merge Activity into single "/" dropdown menu
- All slash pages now under one "/" dropdown
- Dynamic pages (from Indiekit) appear first
- Activity feeds (github, listening, funkwhale, youtube, news) below divider
- Remove standalone Activity dropdown and /news link
- Add divider styles for desktop and mobile nav

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 14:50:44 +01:00
Ricardo
54ddaaa5d4 feat: make slash pages a dynamic dropdown menu
- Desktop: "/" becomes dropdown showing all pages from collections.pages
- Mobile: "/" becomes collapsible section with all dynamic pages
- New pages created via Indiekit automatically appear in nav

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 14:29:49 +01:00
Ricardo
c01bdd331f feat: add slashes index to navigation
- Add "/" link to desktop and mobile nav pointing to /slashes/
- Update pages collection to find content/*.md (root-level pages)
- Keeps About and Now as featured nav items, with / for all pages

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 13:58:59 +01:00
Ricardo
690b5f09f5 feat: add Now page to navigation
Add /now/ link to both desktop and mobile navigation menus,
placing it after About as a standard slash page.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 13:36:26 +01:00