379 Commits

Author SHA1 Message Date
Ricardo
8136640619 feat: add AI disclosure aside to page layout
Pages (slash pages like /about, /now, /ai) were missing the AI usage
disclosure that already displays on posts. Adds the same aside block
to page.njk so AI metadata renders consistently across all content types.

Confab-Link: http://localhost:8080/sessions/3bf0740c-86e8-4ed6-b7ce-f83d8462c682
2026-03-04 17:40:29 +01:00
Ricardo
b811b43bc2 feat: syndication webhook on incremental builds
Add an eleventy.after hook that triggers syndication immediately after
incremental rebuilds, cutting latency from ~2 min (poller) to ~5 sec.
Uses built-in crypto for HS256 JWT — no new dependencies.

Confab-Link: http://localhost:8080/sessions/d116ad5b-ef8a-424e-9ebe-76c06bef1df6
2026-03-04 17:33:18 +01:00
Ricardo
c766a981c1 fix: design system audit — font-mono dates, focus-visible states, domain color straggler, shadow standardization
P1: Global font-mono on all <time> elements via @layer base CSS rule (covers 43 dates).
P2: Focus-visible states for buttons, inputs, links via CSS (covers 177 elements, WCAG 2.4.7).
P3: listening.njk "All" tab accent-600 → purple-600 (Music domain).
P4: .post-type-dropdown custom box-shadow → shadow-sm equivalent.

Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
2026-03-04 17:29:50 +01:00
Ricardo
a7265bc7ce fix: project cards — per-project color cycling and collapsible grid stretch bug
Add items-start to grid container so expanding one project card no longer
stretches the adjacent card to fill the row height. Add per-project color
cycling (border-l + tech tags) using the 8-color palette, replacing uniform
amber accent colors.

Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
2026-03-04 16:48:05 +01:00
Ricardo
cb3c2115ae feat: implement design system — domain colors, date typography, interaction states, CV family colors
Apply the collaboratively-written design system from .interface-design/system.md:

- Domain color map: Social pages (rose), Code pages (emerald), Reading pages
  (orange), Music pages (purple) replace generic accent tokens
- Font-mono on all <time> elements via global CSS rule + wrap 7 non-<time> dates
- Shadow standardization: replace hover:shadow-lg with border-hover on news cards
- Active states: scale(0.97) press feedback on buttons and pagination links
- Gradient cleanup: remove to-white gradient on github featured project cards
- CV Skills & Interests: cycle through 8 distinct colors per family category
  (amber, emerald, sky, rose, purple, orange, teal, indigo) on both CV page
  and homepage
- Update system.md with refined palette documentation and domain color spec

Files: 19 changed across templates, CSS, and design documentation

Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
2026-03-04 15:13:34 +01:00
Ricardo
8e393e215d feat: warm palette overhaul — cold zinc/teal to warm stone/amber
Replace the entire color system with a design-driven warm palette:

- Surface tokens: cold zinc grays → warm stone (#faf8f5 to #0f0e0d)
- Accent tokens: cold teal → warm amber (#fffbeb to #451a03)
- All bg-white → bg-surface-50 across templates (warm cream instead of pure white)
- Critical CSS: all hardcoded hex values updated to warm palette
- Prism code blocks: cold gray backgrounds → warm stone
- Pagefind search UI: blue buttons/links → amber interactive colors
- Dark mode: warm dark surfaces with amber accents throughout

Design system documented in .interface-design/system.md

Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
2026-03-04 14:02:59 +01:00
Ricardo
155816a0bc feat: replace all primary (blue) with contextual colors across entire theme
Eliminate monotonous blue by replacing ~290 primary- references in 60 files
with semantically appropriate colors:

- accent (teal): links, CTAs, buttons, tabs, focus rings, spinners
- purple: Funkwhale/music, photos, Mastodon/fediverse
- surface (neutral): GitHub, dates/metadata, info boxes
- amber: bookmarks, blogroll categories
- red: likes
- green: reposts
- sky: replies
- orange: RSS/feeds, podcasts
- #0085ff: Bluesky brand
- #a730b8: Mastodon brand

Also updates prose link colors in tailwind.config.js, pagefind UI
primary color to teal, and client-side JS color references.

Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
2026-03-04 12:50:19 +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
212e62c0f8 feat: add AI usage metadata to JSON-LD structured data
Add usageInfo (link to /ai transparency page) and creativeWorkStatus
(human-readable AI disclosure) to the Article JSON-LD when AI metadata
properties are present. Valid Schema.org, no impact on ActivityPub.

Confab-Link: http://localhost:8080/sessions/83d68915-7921-4cc4-a838-c331fd1c4d6e
2026-03-03 18:01:42 +01:00
Ricardo
91e4ccf029 fix: only show AI badge on blog listing when level > 0
Posts with default ai-text-level=0 no longer show a redundant badge
in the blog listing. The individual post aside still shows "Text: None"
as a transparency declaration.

Confab-Link: http://localhost:8080/sessions/3bf0740c-86e8-4ed6-b7ce-f83d8462c682
2026-03-03 15:45:30 +01:00
Ricardo
49c9d5ffe6 feat: display AI usage disclosure on posts and blog listing
Show AI transparency metadata (text level, code level, tools) as a
subtle aside on individual posts and compact badges in blog listing.
Supports both camelCase and underscore property names.

Confab-Link: http://localhost:8080/sessions/83d68915-7921-4cc4-a838-c331fd1c4d6e
2026-03-03 14:39:44 +01:00
Ricardo
99c9d7e73d fix: make remote image processing optional via PROCESS_REMOTE_IMAGES
Default "false" — adds eleventy:ignore to remote <img> tags via a
posthtml plugin (priority 1) that runs before eleventy-img (priority -1).
Sharp only processes local images, avoiding OOM from downloading and
decoding hundreds of external images.

Set PROCESS_REMOTE_IMAGES=true to restore previous behavior.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-03 12:23:51 +01:00
Ricardo
d8d1dbfcec fix: prevent watcher OOM by tuning eleventy-img plugin
- transformOnRequest: process images on-demand in watch mode instead
  of all at once during rebuild (same pattern as zachleat.com)
- cacheOptions: cache remote image fetches to disk (1d build, 30d watch)
- concurrency: 4 (down from default ~10 based on CPU count) to limit
  Sharp's native memory usage from parallel image decodes

Root cause: Sharp processes remote images outside V8 heap, so
--max-old-space-size doesn't cap total memory. Large remote images
(e.g. 3072px-wide) at concurrency 10 spike native memory enough
to exceed the 3GB cgroup limit.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-03 12:06:46 +01:00
Ricardo
760058d0e4 feat: multi-domain fediverse support and share-to-mastodon upgrade
- Replace single localStorage string with versioned multi-domain store
  (fediverse_domains_v1) with usage tracking, inspired by Mastodon's
  share.joinmastodon.org project
- Add domain validation via URL constructor before redirecting
- Add mode param to fediverseInteract component: "interact" for
  authorize_interaction, "share" for /share?text=...
- Migrate old fediverse_instance key automatically on first load
- Extract shared modal partial (fediverse-modal.njk) used by post
  interaction, follow widget, and share widget
- Share widget now prompts visitors for their own instance instead of
  hardcoding site owner's Mastodon instance

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-03 11:09:29 +01:00
Ricardo
9b5fe6014d feat: redesign starred page with GitHub Lists tabs, sort, and filters
- Add tab bar for GitHub Lists (All, per-list tabs, Uncategorized)
- Add sort controls (stars, recently starred, recently updated, name)
- Add filter controls (language, star count range, archived toggle)
- Add language color dots, formatted star/fork counts, topic overflow
- Fix starred count on GitHub activity page (fetch totalCount from API)
- All rendering remains client-side via Alpine.js (no build OOM risk)

Confab-Link: http://localhost:8080/sessions/b130e9e5-4723-435d-8d5a-fc38113381c9
2026-03-03 11:01:05 +01:00
Ricardo
4fb7e2e92e fix: sync new OG images to output during incremental builds
During watcher/incremental builds, .cache/og is in watchIgnores so
Eleventy's passthrough copy doesn't pick up newly generated OG images.
After OG generation, manually copy any new .png files from .cache/og/
to _site/og/ so they're immediately available to serve.

Confab-Link: http://localhost:8080/sessions/956f4251-b4a9-4bc9-b214-53402ad1fe63
2026-03-02 16:04:31 +01:00
Ricardo
a39b20375d fix: make starred page client-side rendered to avoid OOM
5,137 starred repos in Nunjucks template + Pagefind indexing exceeded
the 2048MB Eleventy heap limit during build. Switched to Alpine.js
client-side rendering:

- _data/githubStarred.js: returns only buildDate (no API fetch)
- starred.njk: fetches /githubapi/api/starred/all via Alpine.js
- Added client-side text search (replaces separate Pagefind index)
- Removed pagefind-starred build step and --exclude-selectors flag

Confab-Link: http://localhost:8080/sessions/b130e9e5-4723-435d-8d5a-fc38113381c9
2026-03-02 13:40:33 +01:00
Ricardo
9d29f24d93 feat: add /github/starred/ page with Pagefind search and live updates
- New starred.njk page rendering all ~5k starred repos as searchable cards
- Separate Pagefind index (pagefind-starred) for starred-only search
- Alpine.js live updates section for stars added since last build
- Load More pagination (50 at a time, all in DOM)
- githubStarred.js data file fetching from plugin API (1d cache)
- Link from /github/ to /github/starred/
- Exclude starred cards from main site Pagefind index

Confab-Link: http://localhost:8080/sessions/b130e9e5-4723-435d-8d5a-fc38113381c9
2026-03-02 13:15:12 +01:00
Ricardo
c3d64afa23 fix: add watcher debounce for rapid successive file changes
When Micropub creates a post, the markdown file is written twice in quick
succession — first the initial content, then ~2s later a syndication update
adds syndication URLs. Without debouncing, the watcher rebuilds from the
first write and misses the second, causing "Also on" links to not appear.

- awaitWriteFinish (2s stability threshold): delays watcher events until
  the file hasn't been written to for 2 seconds
- setWatchThrottleWaitTime (3s): groups all file changes within 3 seconds
  into a single build

Confab-Link: http://localhost:8080/sessions/956f4251-b4a9-4bc9-b214-53402ad1fe63
2026-03-01 21:27:54 +01:00
Ricardo
00b436f76f feat: add public reading list page at /readlater/
Alpine.js frontend that fetches from the readlater public API.
Includes source filtering, search, sort toggle, and Post button
for each saved item.
2026-02-28 18:17:12 +01:00
Ricardo
ab302cbe9c feat: add Post button with type dropdown to listening page
Add share-post-btn to all 4 listening sections: Funkwhale listenings,
Last.fm scrobbles, Loved tracks, and Funkwhale favorites. Uses plain
data attributes for Nunjucks server-rendered values.
2026-02-28 12:37:24 +01:00
Ricardo
fb19a68f9e feat: replace Post button with post-type dropdown menu
Clicking Post now shows a dropdown with Note, Bookmark, Reply, Like,
Repost, and Article options. Each opens /posts/create with the
selected type and pre-filled URL/title in a popup window.
2026-02-28 11:12:07 +01:00
Ricardo
b254faf16d feat: add Post buttons to news page (all three view modes) 2026-02-28 08:22:20 +01:00
Ricardo
426b8bad24 feat: add Post button to podroll episode cards 2026-02-28 08:21:44 +01:00
Ricardo
6739b5e31a feat: add Post button to blogroll category items 2026-02-28 08:21:32 +01:00
Ricardo
58dcf648a7 feat: add share-post button styles 2026-02-28 08:21:19 +01:00
Ricardo
6cfb92818e feat: include share-post.js in base layout 2026-02-28 08:21:05 +01:00
Ricardo
a7cc646881 feat: add share-post.js module for Post buttons 2026-02-28 08:20:55 +01:00
Ricardo
82db66c258 chore: remove dev plans from published repo
Plans moved to central /home/rick/code/indiekit-dev/docs/plans/
2026-02-27 17:31:30 +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
1e900fab16 fix: include photo gallery images in lightbox selector 2026-02-27 11:54:01 +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
dbd2f72019 fix: handle absolute URLs in JSON-LD image field
When markdown images use full https:// URLs, the template was prepending
site.url again, causing double-domain in structured data
(e.g., https://rmendes.net/https://rmendes.net/media/...).

Now checks if postImage starts with 'http' and skips the prefix.
2026-02-26 14:56:13 +01:00
Ricardo
1895584870 docs: add weekly digest implementation plan 2026-02-26 08:29:13 +01:00
Ricardo
581c585677 feat: add digest feed discovery link and navigation items 2026-02-26 08:27:57 +01:00
Ricardo
5c8c1343c2 feat: add digest templates and digestToHtml filter
- digest.njk: individual digest pages at /digest/YYYY/WNN/
- digest-index.njk: paginated index at /digest/
- digest-feed.njk: RSS feed at /digest/feed.xml
- digestToHtml filter for RSS feed item descriptions
2026-02-25 17:36:37 +01:00
Ricardo
99ae0853ff fix: ignore interactive/ directory from Nunjucks processing
The interactive/ directory contains self-contained HTML files with
JavaScript that Nunjucks incorrectly parses as template syntax. Add
to ignores so Eleventy only passthrough-copies without processing.
2026-02-25 17:34:09 +01:00
Ricardo
cd4967f939 feat: add weeklyDigests collection for digest feature
- Added weeklyDigests collection after recentPosts collection
- Groups published posts (excluding replies) by ISO 8601 week
- Supports both camelCase and underscore property names
- Includes byType grouping (articles, notes, photos, etc.)
- Calculates week start/end dates for display
- Excludes interactive directory from builds via .eleventyignore
2026-02-25 17:31:43 +01:00
Ricardo
abc0404816 feat: add fullwidth layout and interactive architecture page
Add a reusable fullwidth layout (layouts/fullwidth.njk) for rich HTML
content that needs the full container width without sidebar or prose
constraints. Add the interactive architecture explorer as a static
asset served via passthrough copy at /interactive/architecture.html.

- layouts/fullwidth.njk: site header + footer only, no sidebar
- interactive/architecture.html: tabbed architecture guide
- eleventy.config.js: passthrough copy for interactive/ directory
2026-02-25 16:48:06 +01:00
Ricardo
cd7083eb9a feat: preserve custom order for skills and interests sections
Remove dictsort from for-loops so categories render in the order
set by the admin UI drag-drop reorder, instead of alphabetically.
2026-02-25 15:57:42 +01:00
Ricardo
ab31e080bb feat: update interests templates for category-based data model
Interests are now grouped by category (matching skills pattern).
Updated cv-interests.njk to iterate categories, cv.js fallback to {},
and cv.njk hasCvData check to include interests.
2026-02-25 14:56:11 +01:00
Ricardo
116ac63f5f fix: CV page hero issues — avatar 404, collapsible description, interest filter, contact info
- Add eleventy:ignore to avatar img to prevent image transform rewriting URL to broken relative path
- Wrap authorDescription in details/summary for collapsible "More about me" toggle
- Fix interest filter logic: untyped interests no longer bypass work/personal filter
- Display location, org, website, email, PGP key from CV identity in hero section
2026-02-25 12:26:03 +01:00
Ricardo
2558e9fe57 feat: CV hero uses plugin identity with site.author fallback
CV page hero now checks cvPageConfig.identity before falling back to
site.author, matching the homepage hero pattern. Social links use the
shared socialIcon macro.
2026-02-25 11:07:47 +01:00
Ricardo
cd2efb0fab docs: weekly digest feature design
Aggregates posts by ISO week into summary pages and an RSS feed.
Approved design — ready for implementation planning.
2026-02-25 10:59:15 +01:00
Ricardo
703cfbc438 feat: shared social icon macro with 33 brand icons
Replace duplicated inline SVGs in h-card.njk and hero.njk with a shared
Nunjucks macro. Adds proper icons for ActivityPub, Forgejo, Codeberg,
PixelFed, and 25+ more platforms via Simple Icons (CC0).
2026-02-25 09:59:36 +01:00
Ricardo
b317148cd1 feat: prefer identity data over env vars in hero and h-card
Hero and h-card templates now resolve homepageConfig.identity.*
fields first, falling back to site.author.* env vars. Includes
design doc and implementation plan for the identity editor.
2026-02-25 08:55:16 +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
6bc90b038c feat: add JSON Feed 1.1 per-category feed template 2026-02-24 22:41:01 +01:00
Ricardo
22c151bb02 feat: add categoryFeeds collection for per-category RSS/JSON feeds 2026-02-24 22:39:49 +01:00
Ricardo
3a9b0d5dd2 docs: add per-category feeds implementation plan 2026-02-24 22:37:00 +01:00