Commit Graph

41 Commits

Author SHA1 Message Date
svemagie
4cc002795f feat(been): cluster duplicate checkins with Leaflet.markercluster 2026-03-20 22:07:37 +01:00
svemagie
fa8bd8678d chore: vendor Leaflet 1.9.4 JS and CSS 2026-03-20 21:51:54 +01:00
svemagie
46d99170d4 fix(webmentions): rename h2 to Interactions and apply text-lg font-semibold style
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 01:04:45 +01:00
svemagie
571ecb6e40 fix(webmentions): filter out self-interactions from own Bluesky account
Exclude webmentions from svemagie.bsky.social / did:plc:g4utqyolpyb5zpwwodmm3hht
at both build-time (eleventy filter) and client-side (webmentions.js).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:59:40 +01:00
svemagie
a166af2306 chore: sync upstream — performance, webmentions v2, OG v3
- _data: switch to cachedFetch wrapper (10s timeout + 4h watch cache)
- js/webmentions.js: owner reply threading, platform provenance badges, DOM dedup, Micropub reply support
- js/comments.js: owner detection, reply system, Alpine.store integration
- _includes/components/webmentions.njk: data-wm-* attrs, provenance badge slots, reply buttons
- _includes/components/comments.njk: owner-aware comment form, threaded replies
- widgets/toc.njk: Alpine.js tocScanner upgrade (replaces is-land/inline-JS)
- lib/og.js + og-cli.js: OG card v3 (light theme, avatar, batched spawn, DESIGN_VERSION=3)
- eleventy.config.js: hasOgImage cache, memoized date filters, batched OG/unfurl, post-build GC, YouTube check opt
- base.njk: Inter font preloads + toc-scanner.js script
- critical.css: font-face declarations (font-display:optional)
- tailwind.css: font-display swap→optional
- tailwind.config.js: prose link colors -700→-600
- Color design system: accent-700/300 → accent-600/400 across components

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 23:56:56 +01:00
svemagie
ac4b62d43c chore: sync upstream — add toc-scanner.js and data-fetch.js
New files from rmdes/indiekit-eleventy-theme:
- js/toc-scanner.js: Alpine.js TOC scanner with IntersectionObserver scroll spy
- lib/data-fetch.js: shared fetch helper with 10s timeout and watch-mode cache extension

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 23:15:33 +01:00
svemagie
2e67156bfd fix: resolve AP object URL before authorize_interaction redirect
The "Also on fediverse" widget was passing the blog post URL directly
to authorize_interaction. If a static file server intercepts the request
before Node.js, the remote instance gets HTML instead of AP JSON and
shows "Could not connect to the given address".

Now fetches /activitypub/api/ap-url first to get the Fedify-served AP
object URL (/activitypub/objects/…), which is always routed to Node.js
and reliably returns AP JSON. Falls back to the original URL on error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 15:00:32 +01:00
svemagie
856792ebbe fix(a11y): sweep all remaining accent-600 contrast failures across all components, pages, CSS and JS
Bump all text-accent-600/dark:text-accent-400 to accent-700/300 for WCAG AA.
Bluesky brand blue fixed: #0085ff -> #0057c7 (light) / keep #0085ff (dark).
37 files changed across widgets, sections, layouts, pages, CSS and JS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 15:47:09 +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
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
0c6229088c feat: rework single post view for better content hierarchy
- Add post-type header (Reply/Like/Repost/Bookmark/Note) for titleless posts
- Add left accent border to user content on interaction posts
- Collapse AI Usage box into a compact <details> summary line
- Collapse comments section when empty, auto-open when comments exist
- Collapse webmention send form behind <details> toggle

Confab-Link: http://localhost:8080/sessions/648a550c-4f65-46be-b9a9-6b7e0fd90751
2026-03-05 13:22:32 +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
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
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
a7cc646881 feat: add share-post.js module for Post buttons 2026-02-28 08:20:55 +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
e3f81293d1 fix: align client-side webmention selectors with build-time HTML
- Change .avatar-row selector to .facepile to match build-time template
- Use facepile-avatar class for dynamically created avatar links
- Fix pluralization in updateCount (was only replacing the number,
  now rebuilds the full "N Like/Likes" text correctly)
- Align ring color classes with build-time template
2026-02-23 11:02:32 +01:00
Ricardo
f898837b25 fix: remove platform exception in client-side webmention filter
Conversations items are now included in build-time rendering via
conversationMentions data, so they no longer need a special exception
to bypass the timestamp filter. All items (webmention.io and
conversations) are now filtered equally by build timestamp.
2026-02-23 10:58:48 +01:00
Ricardo
1bc6aaa0a5 fix: add author-based dedup to client-side webmentions
The client-side webmentions.js was deduplicating by wm-id and source
URL, but conversations API and webmention.io use different ID formats
(string vs numeric). Add author URL + action type dedup to catch
cross-source duplicates (e.g., same Bluesky like reported by both).
2026-02-23 10:40:14 +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
0962e054d1 fix: remove fediverse node autocomplete (CORS blocked)
nodes.fediverse.party doesn't send CORS headers, so the fetch fails
from the browser. Remove autocomplete entirely — users type their
instance once and localStorage remembers it.
2026-02-22 16:08:20 +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
c327221352 fix: use Alpine.data() for comments component registration
Convert commentsSection from a global function to Alpine.data()
registration via the alpine:init event. This is the proper Alpine.js
pattern for reusable components — the component is registered in
Alpine's internal registry before DOM processing begins, eliminating
script loading order issues.

Reverts the hacky approach of moving the script tag to <head>.
2026-02-21 22:40:34 +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
c1e9983c66 fix: show conversations reactions on individual post pages
Conversations items (from Mastodon/Bluesky/ActivityPub) were filtered
out by the client-side timestamp check that prevents duplicating
build-time webmentions. Since conversations data is never in the
build-time cache, bypass the filter for items with a platform field.
2026-02-20 17:52:07 +01:00
rmdes
fc9f5968da feat: dual-fetch from conversations API for enriched interaction data
Fetch from both /webmentions/api/mentions and /conversations/api/mentions,
merge results with conversations items taking priority (richer metadata),
and display platform badges (Mastodon/Bluesky icons) on interaction cards.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 21:28:01 +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
c5cd3c2c75 fix: update webmention API URLs for new moderation plugin
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>
2026-02-10 21:24:28 +01:00
Ricardo
e79f23309d fix: dispatch auth event on window for Alpine.js compatibility
Alpine's .window modifier listens on window, not document.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 13:23:30 +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
a8b44329d8 fix: cache webmention API responses in sessionStorage to persist across refreshes
The old sessionStorage rate limiter prevented re-fetching on page refresh,
causing webmentions to disappear since they weren't in the build-time HTML.
Now caches the actual API response data with a 5-minute TTL so webmentions
render instantly from cache on refresh, while still fetching fresh data in
the background.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 10:39:47 +01:00
Ricardo
f58198c021 fix: fetch webmentions for both trailing slash URL variants
Bridgy sends webmentions with inconsistent target URLs — articles
get trailing slashes but likes/bookmarks/reposts don't. The
client-side JS now queries both variants and deduplicates, matching
the build-time filter's behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 10:06:40 +01:00
Ricardo
24f790c4cb fix: properly create webmentions section before appending type sections
When no build-time webmentions exist, the first type to be processed
was silently dropped because createWebmentionsSection() only creates
the wrapper, not the type-specific section. After calling it, the code
tried to find the selector which still didn't exist.

Fixed by: create wrapper if needed, then always append the section
to the wrapper and get the row/list from the newly created section.
2026-01-28 17:24:00 +01:00
Ricardo
924a21b9f8 fix: correct variable name in updateTotalCount call
Changed newMentions.length to mentionsToShow.length to fix
JavaScript error that was breaking webmention display.
2026-01-28 16:53:23 +01:00
Ricardo
44e8983da8 fix: show all webmentions when no build-time data exists
When build-time webmentions section doesn't exist, show ALL webmentions
from the API instead of filtering to only new ones.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 16:33:19 +01:00
Ricardo
b20f371647 fix: use webmentions proxy in client-side fetcher
Prevents direct calls to webmention.io API which may fail without token

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 15:12:08 +01:00
Ricardo
1f3fe00ce8 fix: multiple frontend issues
- Add Alpine.js Collapse plugin for x-collapse directive
- Create favicon.svg and favicon.ico with proper linking
- Fix default-avatar references (use existing .svg instead of .png)
- Add favicon.ico to passthrough copy

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 15:08:01 +01:00
Ricardo
922ae40460 feat: add client-side webmention fetcher for real-time updates
- Add js/webmentions.js to fetch new webmentions from webmention.io API
- Supplements build-time cached webmentions with real-time data
- Shows new webmentions with 'NEW' badge and visual ring highlight
- Uses safe DOM methods to prevent XSS vulnerabilities
- Data attributes on webmentions container provide target URL and build time

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 10:11:48 +01:00