diff --git a/CLAUDE.md b/CLAUDE.md index e8de46c..95ea1db 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -158,7 +158,7 @@ Most plugin-dependent data files: | `blog-sidebar.njk` | Sidebar for blog/post pages (recent posts, categories) | | `h-card.njk` | Microformat2 h-card for author identity | | `reply-context.njk` | Displays reply-to/like-of/repost-of/bookmark-of context with h-cite | -| `webmentions.njk` | Renders likes, reposts, replies from webmention.io + send form | +| `webmentions.njk` | Renders likes, reposts, replies from webmention.io + conversations API, with threaded owner replies | | `empty-collection.njk` | Fallback message when a post type collection is empty | #### Sections (_includes/components/sections/) @@ -315,14 +315,27 @@ Generates OpenGraph images for posts without photos using Satori (Yoga WASM → - **h-feed** (feed markup): Machine-readable post lists - **h-cite** (reply context): Cites external content in replies/likes/reposts -#### Webmentions +#### Webmentions & Interactions - Build-time caching via `@chrisburnell/eleventy-cache-webmentions` -- Client-side real-time fetching via `/js/webmentions.js` -- Displays likes, reposts, replies with avatars +- Client-side real-time fetching via `/js/webmentions.js` from three APIs: + - `/webmentions/api/mentions` — IndieWeb webmentions (webmention.io) + - `/conversations/api/mentions` — Mastodon/Bluesky/AP interactions (conversations plugin) + - `/comments/api/comments` — Native authenticated comments (comments plugin) +- Displays likes, reposts, replies with avatars and platform badges +- **Owner reply threading** — owner replies appear nested under parent interactions with amber Author badge - Send webmention form on every post - Legacy URL support via `urlAliases` (for micro.blog and old blog URLs) +#### Reply-to-Interactions Architecture + +The conversations API enriches its response with owner replies (`is_owner: true`, `parent_url`). The frontend's `threadOwnerReplies()` function matches `parent_url` to reply `
  • ` elements via `data-wm-url` attributes and inserts threaded reply cards into `wm-owner-reply-slot` divs. + +Reply routing is provenance-aware: +- **Mastodon/Bluesky replies** — `POST /micropub` with `mp-syndicate-to` for platform threading +- **IndieWeb webmention replies** — `POST /micropub` without syndication (webmention sent automatically) +- **Native comment replies** — `POST /comments/api/reply` (stored in comments collection) + #### IndieAuth - `rel="me"` links in `` for identity verification diff --git a/README.md b/README.md index b20af20..b68cce7 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Integrates with custom Indiekit endpoint plugins: | `@rmdes/indiekit-endpoint-podroll` | Podcast episode aggregator | | `@rmdes/indiekit-endpoint-rss` | RSS feed reader with MongoDB caching | | `@rmdes/indiekit-endpoint-microsub` | Social reader with channels and timeline | +| `@rmdes/indiekit-endpoint-conversations` | Multi-platform interaction aggregation + owner reply threading | +| `@rmdes/indiekit-endpoint-comments` | IndieAuth visitor comments with owner replies | ### Modern Tech Stack @@ -428,6 +430,72 @@ See `indiekit-deploy` repository for Docker Compose deployment with this theme a - [IndieAuth](https://indieauth.com/) — Authentication protocol - [Bridgy](https://brid.gy/) — Backfeed social interactions +## Reply-to-Interactions + +The theme supports threaded owner replies on all interaction types: IndieWeb webmentions, Mastodon/Bluesky backfills, and native authenticated comments. + +### How It Works + +``` +Visitor interaction (Mastodon reply, Bluesky like, webmention, native comment) + │ + v +Conversations API (/conversations/api/mentions) + │ Enriches response with owner replies from posts collection + │ Adds is_owner: true + parent_url for threading + v +webmentions.js (client-side) + │ processWebmentions() separates owner replies from regular interactions + │ Renders regular interactions (likes, reposts, replies) + │ threadOwnerReplies() inserts owner reply cards under parent interactions + v +Threaded display: + ┌─────────────────────────────────┐ + │ Jane Doe [Mastodon] Mar 11 │ + │ Great post! │ + │ [Reply] │ + │ ┌─────────────────────────────┐ │ + │ │ Ricardo Mendes [Author] │ │ + │ │ Thanks! │ │ + │ └─────────────────────────────┘ │ + └─────────────────────────────────┘ +``` + +### Key Files + +| File | Role | +|------|------| +| `js/webmentions.js` | Fetches interactions from 3 APIs (webmentions, conversations, comments), deduplicates, renders, and threads owner replies | +| `js/comments.js` | Alpine.js component for native comment form, IndieAuth flow, and inline reply UI | +| `_includes/components/webmentions.njk` | Server-side template with `data-wm-url` attributes and `wm-owner-reply-slot` divs for threading | + +### Threading Mechanism + +1. **`processWebmentions(allChildren)`** separates items with `is_owner: true` and `parent_url` from regular interactions +2. Regular interactions render normally (likes, reposts, reply cards) +3. Each reply `
  • ` gets a `data-wm-url` attribute matching the interaction's source URL +4. Each reply `
  • ` includes an empty `
    ` for threading +5. **`threadOwnerReplies(ownerReplies)`** matches each owner reply's `parent_url` to a reply `
  • `'s `data-wm-url`, then inserts an amber-bordered reply card into the slot + +### Reply Routing + +When the site owner clicks "Reply" on an interaction, the routing depends on the interaction's source: + +| Source | Route | Syndication | +|--------|-------|-------------| +| Mastodon reply | `POST /micropub` with `in-reply-to` | `mp-syndicate-to: mastodon` | +| Bluesky reply | `POST /micropub` with `in-reply-to` | `mp-syndicate-to: bluesky` | +| IndieWeb webmention | `POST /micropub` with `in-reply-to` | No syndication (webmention sent) | +| Native comment | `POST /comments/api/reply` | Stored in comments collection | + +### Plugin Dependencies + +| Plugin | Role | +|--------|------| +| [`@rmdes/indiekit-endpoint-conversations`](https://github.com/rmdes/indiekit-endpoint-conversations) | Serves interactions with owner reply enrichment (`is_owner`, `parent_url`) | +| [`@rmdes/indiekit-endpoint-comments`](https://github.com/rmdes/indiekit-endpoint-comments) | Handles native comment replies and owner detection (`/api/is-owner`) | +| `@rmdes/indiekit-endpoint-webmention-io` | Serves webmention.io data (likes, reposts, replies from IndieWeb) | + ## Troubleshooting ### Webmentions not appearing