Commit Graph

343 Commits

Author SHA1 Message Date
Ricardo
ea7433852d perf: memoize aiPosts/aiStats filters and skip PostHTML for imageless pages
aiPosts/aiStats: cache filter results per build — 694 calls × 2,350 posts
= 1.6M iterations reduced to 1. Saves ~2.2s per incremental rebuild.

html-transformer: override default transform with content pre-check that
skips PostHTML parse/serialize (~3ms/page) for pages without <img> tags.
Both registered PostHTML plugins only target <img> elements.

Confab-Link: http://localhost:8080/sessions/0b241cd6-aff2-4fec-853c-2b5a61e61946
2026-03-10 16:13:54 +01:00
Ricardo
8a7e45cea7 perf: memoize hash filter and optimize transforms
- Cache hash filter results per build (55,332 → 16 file reads)
- Cache OG directory listing for og-fix transform (3,426 → 1 readdirSync)
- Early-exit youtube-link-to-embed on pages without YouTube links
- All caches clear on eleventy.before for correct incremental rebuilds

Confab-Link: http://localhost:8080/sessions/0b241cd6-aff2-4fec-853c-2b5a61e61946
2026-03-10 15:36:20 +01:00
Ricardo
129e0720af perf: batch unfurl pre-fetch to reduce peak memory
Replace unbounded Promise.all on 545 interaction URLs with batches
of 50. Add GC calls after the markdown walk and between batches to
free parsed content and resolved promise data before the render phase.

Logs RSS every 5th batch for memory monitoring.

Same pattern as the OG image batch spawning fix.

Confab-Link: http://localhost:8080/sessions/0b241cd6-aff2-4fec-853c-2b5a61e61946
2026-03-10 14:44:51 +01:00
Ricardo
48160a5b13 feat: client-side TOC widget with Alpine.js scroll spy
Replace the server-side toc.njk placeholder (which never rendered because
no code populated the `toc` variable) with a client-side Alpine.js component
that scans .e-content headings at page load, builds a dynamic table of
contents, and highlights the current section via IntersectionObserver.

- Only appears on articles/notes with 3+ headings (h2-h4)
- Excluded at build time for bookmarks, likes, and reposts
- Scroll spy activates heading in top 30% of viewport

Confab-Link: http://localhost:8080/sessions/cc343b15-8d10-43cd-a48f-ca912eb79b83
2026-03-10 13:01:53 +01:00
Ricardo
508ddf03ca docs: document OG batch spawning architecture in CLAUDE.md
Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-09 18:35:09 +01:00
Ricardo
db10d9cfbf fix(og): batch spawning to prevent OOM during watcher rebuilds
Full OG regeneration (2,350 images) OOM-kills when the Eleventy watcher
is running (~1.8 GB RSS), leaving only ~1.2 GB headroom in the 3 GB
container. WASM native memory from Satori/Resvg grows beyond what GC
can reclaim within a single process.

Solution: spawn og-cli in batches of 100 images. Each invocation exits
after its batch, fully releasing all WASM native memory. Exit code 2
signals "more work remains" and the spawner re-loops. Peak memory per
batch stays under ~500 MB regardless of total image count.

Also seed newManifest from existing manifest so unscanned entries survive
batch writes.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-09 17:37:17 +01:00
Ricardo
6dd8f03214 fix(og): aggressive GC to prevent OOM in constrained containers
Full OG regeneration (2,350 images) was OOM-killed because WASM native
memory from Satori/Resvg accumulated between GC cycles. The previous
GC interval of 50 images allowed ~2.5-5 GB of native allocations before
reclamation. Reduce to every 5 images to keep peak RSS under ~400 MB.

Also reduce --max-old-space-size from 768 to 512 MB (V8 heap only uses
~22 MB) and add peak RSS tracking to the completion log.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-09 17:25:05 +01:00
Ricardo
bfd885cbc9 perf: add periodic GC to og-cli to reclaim WASM native memory
Satori (Yoga WASM) and Resvg (Rust WASM) allocate native memory that
V8 doesn't track against the heap limit. Without periodic GC, the JS
wrappers accumulate and native RSS grows to ~2 GB during OG image
generation for 3400+ posts.

- Add --expose-gc to og-cli spawn
- Call global.gc() every 50 images to reclaim native memory
- Log final RSS/heap for monitoring

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-09 17:03:44 +01:00
Ricardo
8753e73709 feat: add V8 heap space diagnostics to post-build GC hook
After GC, logs heap space breakdown (old_space, large_object_space, etc.)
to help identify memory consumers. Supports HEAP_SNAPSHOT=1 env var to
write a heap snapshot to /tmp for detailed analysis.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-09 16:44:33 +01:00
Ricardo
9f591ca2fb fix: update avatar dimensions in hero section (Tier 1) to match CSS
The previous commit fixed the Tier 2 default hero avatar (home.njk),
but production uses the homepage builder (Tier 1) which renders
hero.njk instead. Same issue: HTML width/height 96x96 but CSS sets
sm:w-32/h-32 (128px) on desktop, causing CLS on resize.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-09 00:31:48 +01:00
Ricardo
17c21b2b8f perf: fix desktop CLS (0.57) — grid match, font-display optional, avatar sizing
Three root causes identified via PageSpeed layout shift culprits:

1. Grid mismatch (CLS 0.495): Critical CSS used `2fr 1fr` but Tailwind
   compiles to `repeat(3, minmax(0, 1fr))` with `grid-column: span 2`.
   Updated critical CSS to match Tailwind's exact output.

2. Font swap FOUT (CLS 0.074): @font-face declarations were only in the
   deferred stylesheet. Moved to critical CSS with font-display:optional
   and added <link rel="preload"> for weights 400/600/700. Changed all
   font-display from swap to optional in tailwind.css source.

3. Avatar resize: HTML width/height was 96x96 but CSS sets sm:w-32/h-32
   (128px) on desktop. Updated attributes to 128x128.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-09 00:19:20 +01:00
Ricardo
9e8f0f139a perf: remove skeleton loader to fix CLS (0.916 mobile / 1.004 desktop)
The skeleton-to-content swap was the root cause of extreme CLS scores.
Critical CSS already provides correct first-paint layout, making the
skeleton unnecessary. Removes html.loading class, skeleton div,
page-content wrapper, and all skeleton CSS rules.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-08 15:23:27 +01:00
Ricardo
229f770cbb perf: force V8 garbage collection after Eleventy builds
Add global.gc() call in eleventy.after handler to release unused heap
pages back to the OS. Without this, V8 keeps ~2 GB of build-time
allocations resident in watch mode because there's no allocation
pressure to trigger GC naturally. Requires --expose-gc in NODE_OPTIONS
(set in start.sh for the watcher process).

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-08 12:52:42 +01:00
Ricardo
254d5069f7 fix: move focus-trap logic from inline attribute to JS method
The @keydown.tab handler in fediverse-modal.njk contained complex
inline JS with arrow functions, querySelector strings with escaped
quotes, and comparison operators — all of which confused
html-minifier-terser's HTML parser, causing parse errors on every
page that includes the modal (i.e., nearly every page).

Moved the focus-trap logic to a trapFocus() method on the Alpine
component where it belongs.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-07 20:35:32 +01:00
Ricardo
6ff40c8317 perf: address PageSpeed Insights issues (CLS, contrast, touch targets, JS minification)
- Reserve sidebar min-height on desktop to prevent CLS from Alpine.js hydration
- Defer lite-yt-embed.css with media="print" onload pattern
- Add terser JS minification in eleventy.after build hook
- Increase touch target sizing for category pills, facepile avatars, nav items
- Fix text-surface-400 contrast ratio (3.05:1 → 6.23:1) across 20 instances

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-07 20:13:45 +01:00
Ricardo
2c60bc2580 fix: restore horizontal layout for post categories
The accessibility change from <span> to <ul> caused categories to stack
vertically. Add flex utilities to maintain horizontal flow while keeping
the semantic list markup and ARIA attributes.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 20:11:20 +01:00
Ricardo
1026d728af a11y: fix all remaining WCAG 2.1 AA issues from audit round 2
- Focus traps for fediverse modal and lightbox dialogs (C3, C4)
- Search widget input label (C5)
- Blogroll widget tab ARIA semantics (C6)
- Footer social links "opens in new tab" warning (S5)
- Reply context aria-label on aside (S8)
- Photo alt text fallback includes post title (S10)
- Post categories use list markup (M3)
- Funkwhale now-playing bars aria-hidden (M7)
- TOC uses static Tailwind classes instead of dynamic (M9)
- Footer headings use proper aria heading roles (M15)
- Header anchor opacity increased to 1 for contrast (M18)
- Custom HTML widgets labeled as regions (M19)
- Empty collection placeholder role=status (M22)
- GitHub widget loading state announced (N5)
- Subscribe icon contrast improved (m1)
- All Permalink links have aria-label with post context (m3)
- Podroll audio element aria-label (m4)
- Obfuscated email link aria-label (m6)
- Fediverse follow button uses aria-label (M10)

Score: 53.6% → 92.9% (26/28 WCAG criteria passing)

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 19:34:25 +01:00
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
db75bd05ea fix: give each post type a unique domain color
Articles, notes, and bookmarks were all sharing amber, which
defeats the purpose of per-type color identity.

New complete color map (7 unique colors):
- Articles: indigo (long-form writing)
- Notes: teal (short posts)
- Bookmarks: amber (saved links)
- Likes: red (heart)
- Replies: sky (conversation)
- Reposts: green (sharing)
- Photos: purple (visual)

Updated across collection pages, blog.njk mixed view,
recent-posts widget (now shows type-specific icons and colors
for all 7 types), and design system documentation.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 18:03:06 +01:00
Ricardo
7d8b039ba7 fix: harmonize domain colors across all collection templates
Each post type now has a unique, consistent color applied across
sparkline, card border, icon, label, hover state, and permalink:
- Articles/Notes/Bookmarks: amber
- Likes: red (was rose)
- Replies: sky (was rose)
- Reposts: green (was rose)
- Photos: purple

Replaces generic accent/rose colors with type-specific colors in
blog.njk mixed-type view and all individual collection pages.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 17:48:49 +01:00
Ricardo
333d972e40 fix: align sparkline colors with per-type domain colors
Match sparkline wrapper colors to the post type icon colors used in the
recent posts widget: replies=sky, reposts=green, likes=red, photos=purple.
Articles, notes, bookmarks, and blog keep amber (writing domain).

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 17:40:36 +01:00
Ricardo
95a532b8c1 fix: add explicit width/height attributes to sparkline SVG
SVGs with only a viewBox and no width/height attributes use intrinsic
sizing that can override CSS width:100%. Adding width="100%" height="100%"
and preserveAspectRatio="none" on the SVG element itself ensures the
sparkline fills its container div.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 17:28:29 +01:00
Ricardo
9a9cd2d251 perf: enable lite-yt-embed, optimize avatar, add cache headers
- YouTube embeds now use lite-youtube facade (loads iframe on click,
  ~800 KiB savings per page with embedded videos)
- Avatar resized from 1000x1000 to 400x400 (152 KiB → 39 KiB)
- lite-yt-embed.css max-width changed to 100% for responsive layout
- Removed unused Tailwind primary color palette from CSS bundle

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-07 17:26:40 +01:00
Ricardo
0da3780c77 fix: sparkline sizing — use div wrapper instead of span in flex context
The sparkline SVG containers were using <span> elements as flex items.
While a span's outer display is blockified in flex context, its inner
display remains inline, causing SVG width:100% to resolve against the
inline content width (~22px) instead of the flex-allocated width (~670px).
Switching to <div> provides block inner display, allowing the SVG to
fill the available space correctly.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 17:05:52 +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
f5e6dfbc8a fix: sparkline width regression, dark mode pill contrast, interaction icons
- Sparkline: change from fixed 120/180px to fluid width (flex-1 min-w-0)
  filling the content area next to page titles across all 8 post type pages
- Blog filter: fix dark mode active pill contrast (dark:bg-accent-700)
- Interactions: replace wrong share icon with correct ActivityPub logo
- Interactions: add IndieWeb webmention provenance badge (globe icon)
- Interactions: improve platform detection (Bridgy Fed, more Fediverse instances)

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 16:31:30 +01:00
Ricardo
c5cdbc2100 docs: update design system and add compliance plan
- Rewrite .interface-design/system.md with comprehensive patterns
- Add implementation plan for design system compliance fixes

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:59:54 +01:00
Ricardo
e3d5a46e11 fix(depth): add shadow-lg to avatars/album art, font-mono to stat numbers
System: avatars/album art get shadow-lg for presence.
Stat numbers get font-mono like dates/timestamps.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:59:42 +01:00
Ricardo
c6a3b090df fix(dark-mode): correct dark mode token pairs
- bg-white -> bg-surface-50 (token compliance)
- Add missing dark:text-surface-100 on inputs
- Fix dark:border-surface-600 -> dark:border-surface-700
- Fix badge bg opacity (dark:bg-accent-900/30)

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:59:36 +01:00
Ricardo
9832c671c6 fix(radius): correct border-radius to match system
- rounded -> rounded-full for badges/pills
- rounded-xl -> rounded-lg for standard cards (xl reserved for hero/featured)

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:59:29 +01:00
Ricardo
931c784dec fix(hover): correct card hover borders to domain colors
Replace hover:border-surface-400 with domain-colored borders.
Add hover:underline to text links missing it.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:59:23 +01:00
Ricardo
dacf819b99 fix(dates): add font-mono text-sm to all <time> elements
System convention: every rendered date gets font-mono class.
CSS base layer handles font-family, but classes ensure consistency
and proper text-sm sizing across all templates.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:59:17 +01:00
Ricardo
4945a6f1e6 fix(dates): add font-mono to Alpine.js-rendered date spans
CSS base layer covers <time> elements automatically, but dates
rendered via x-text into <span> elements need explicit font-mono.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:59:10 +01:00
Ricardo
d8032ccfd2 fix(domain-colors): correct domain color assignments across 8 files
- starred.njk: accent -> emerald (Code domain)
- photos.njk: purple -> amber (Writing domain)
- reposts.njk: emerald -> rose (Social domain)
- blog.njk: red/green/sky -> rose (Social domain unified)
- featured.njk: red/green/sky -> rose (Social domain unified)
- digest.njk: accent -> amber (Writing domain)
- digest-index.njk: orange -> amber (Writing domain)
- search widget: primary -> accent (stale token)

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:58:55 +01:00
Ricardo
0f843e7ce1 fix(cards): add shadow-sm to all card elements across 24 files
Design system requires shadow-sm + border on all cards.
Also fixes bg-white -> bg-surface-50 and bg-surface-100 -> bg-surface-50
where card backgrounds used wrong tokens.

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:58:48 +01:00
Ricardo
2f442862af fix(css): fix 10 design system violations in component classes
- .widget-title: font-bold -> font-semibold
- .repo-card: add shadow-sm
- .fab-menu-item: rounded-xl -> rounded-lg, shadow-md -> shadow-sm
- .p-category: hover border surface -> accent
- .widget: remove mb-4 (conflicts with space-y containers)
- Remove duplicate focus-visible system (outline vs ring)
- Remove duplicate time monospace rule
- .post-type-dropdown: prefers-color-scheme -> .dark class
- .save-later-btn/.share-post-btn: add dark mode variants

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-07 15:58:38 +01:00
Ricardo
c71a7f38a8 fix: prevent FOUC for images and SVG icons on first paint
Add critical CSS rules to constrain images (max-width:100%) and inline
SVGs (default 1.25rem) before Tailwind loads. Add width/height HTML
attributes to avatar images in hero sections and h-card sidebar widget.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-07 15:46:43 +01:00
Ricardo
2077b8d866 fix: audit /podroll/ page for design system compliance
- Replace broken SVG icon (mixed checkmark + radio paths) with proper
  microphone icon matching the empty state icon
- Add font-mono to date elements: last synced span, episode <time>
- Add font-mono to stat numbers: podcast count (header + sidebar)
- Add shadow-sm to episode article cards (card depth pattern)
- Add focus:ring-2 to all buttons: refresh, try again, load more
- Focus rings use domain color (orange-500) consistently

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-06 19:53:12 +01:00
Ricardo
12710820f9 fix: audit /news/ page for design system compliance
- Add font-mono text-sm to all <time> elements (4 dates across 3 views)
- Add font-mono to stat numbers (feeds count, items count, pagination)
- Add shadow-sm to list view and expanded view article cards
- Add border + shadow-sm to stats bar (card depth pattern)
- Add focus:outline-none focus:ring-2 focus:ring-accent-500 to all buttons
  (view mode toggles, pagination prev/next, refresh)
- Fix card view hover to use domain color (accent-400) instead of surface-400
- Fix pagination bug: loadPage() now passes feedId when filter is active,
  preventing feed filter from resetting on page change

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-06 19:41:32 +01:00
Ricardo
ee7fa5de7f fix: hide month labels and improve dark mode contrast in AI post-graph
Widget: add noLabels to prevent month abbreviations from squishing
together in the narrow sidebar. Both widget and section: use lighter
boxColorDark (#44403c / surface-700) so empty grid cells are visible
against the surface-800 sidebar/section backgrounds in dark mode.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-06 15:45:43 +01:00
Ricardo
dc8762b427 fix: register ai-usage widget in sidebar.njk and add zap icon
The ai-usage widget was empty on blog listing pages (/notes/, /photos/)
because sidebar.njk (the third sidebar dispatcher) was missing the
widget registration. Also adds the "zap" lightning bolt icon to icon.njk
which was referenced but never defined.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-06 15:07:15 +01:00
Ricardo
53c570a176 fix: audit fixes for /slashes/ — font-mono dates, depth, h-entry, section borders
1. Add font-mono to <time> elements (design system typography rule)
2. Add shadow-sm to inspiration box and empty-state box (depth rule)
3. Add h-entry + p-name/u-url microformats to all cards (RSS-ready)
4. Add border-l-4 visual differentiation: amber for Pages, emerald
   for Activity Feeds, surface for Site Pages

Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-06 14:41:39 +01:00
Ricardo
80c4b55faa fix: correct starred repos URL to /github/starred/
Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
2026-03-06 14:21:10 +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
81ea22ac34 feat: add AI usage homepage section with stats and contribution graph
Full-width section for homepage builder showing 4-column stats grid,
level breakdown pills, AI-involved post-graph, and link to /ai/ page.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-06 12:35:40 +01:00
Ricardo
d1a8ee7ec2 feat: add AI usage sidebar widget for homepage and blog sidebars
Compact widget showing AI transparency stats (total, AI-involved,
human-only, ratio), level breakdown pills, and a 1-year post-graph
highlighting AI-involved posts. Links to /ai/ for full report.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-06 12:28:49 +01:00
Ricardo
8baec25b2c feat: blog filter nav, interactions pagination, note unfurl, pagefind improvements
- Replace broken client-side type filter on /blog/ with navigation
  pill links to dedicated collection pages (with post counts)
- Replace Load More with proper prev/next/page-number pagination
  on Interactions inbound tab (20 per page, filter resets page)
- Add auto-unfurl transform for standalone external links in notes
- Exclude Digest and Categories pages from Pagefind search index
- Add Pagefind search filters for post type, year, and category
- Add Pagefind filter metadata to page.njk layout

Confab-Link: http://localhost:8080/sessions/956f4251-b4a9-4bc9-b214-53402ad1fe63
2026-03-06 10:45:55 +01:00
Ricardo
e7aaf73fba feat: consistent AP logo, Mastodon syndication detection
- Replace network-diagram SVG with official ActivityPub logo in post footer
- Replace person-plus SVG with AP logo in fediverse follow widget
- Replace Mastodon icon with AP logo in share widget, use #a730b8 purple
- AP icon brand color: #f1027e → #a730b8 in social-icon macro
- Detect Mastodon syndication URLs (/@username pattern) for proper logo pill

Confab-Link: http://localhost:8080/sessions/c5b1471e-b046-44d9-b94f-ab5e68fae7cc
2026-03-06 10:42:39 +01:00
Ricardo
b5d0b684d9 feat: add link to /ai/ page in AI usage disclosure
The "Learn more about AI usage on this site" link appears when
the AI usage label is clicked/tapped on posts, providing context
about the site's AI transparency policy.

Confab-Link: http://localhost:8080/sessions/956f4251-b4a9-4bc9-b214-53402ad1fe63
2026-03-06 09:23:38 +01:00
Ricardo
b9a42b3a73 feat: configurable post-graph section and dedicated /graph page
- Add posting-activity.njk section template with configurable years/limit
- Register posting-activity in homepage-section.njk dispatcher
- Move hardcoded post-graph into Tier 2 block (homepage builder controls its own)
- Add "View full history" link to /graph/ on both Tier 2 and section template
- Create /graph/ page showing all years with no limit

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-05 15:42:00 +01:00