Changeset 7d932ce in Klonkt for src/views/pages/post.ejs


Ignore:
Timestamp:
06/24/2026 01:24:23 PM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
a885afc
Parents:
cc24fa1
Message:

feat(activitypub): nested threading + delete your own replies

Inbox now stores replies-to-comments nested (findThreadTarget resolves the post
via the parent comment); getInteractions builds a thread tree shown on the post
(fedi-node partial). deliverReply also cc's the post author's inbox so their
Klonkt threads it. Owners can delete their outbound replies (Delete+Tombstone)
inline + via /fediverse manage list. Schema: ap_interactions.parent_uri.

Co-Authored-By: Claude <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/post.ejs

    rcc24fa1 r7d932ce  
    7272  <% } %>
    7373
    74   <!-- Fediverse interactions (inbound replies / likes / boosts via ActivityPub) -->
    75   <!-- Mirrors the native comment markup/classes so it looks identical. -->
     74  <!-- Fediverse interactions (threaded: inbound replies/likes/boosts + our replies) -->
    7675  <% if (typeof fediverse !== 'undefined' && fediverse && fediverse.total > 0) { %>
    7776    <section class="post-fediverse post-comments" id="fediverse">
     
    8079        <span title="<%= t('fedi.likes') %>">⭐ <%= fediverse.likeCount %></span>
    8180        <span title="<%= t('fedi.boosts') %>">🔁 <%= fediverse.announceCount %></span>
    82         <span title="<%= t('fedi.replies') %>">💬 <%= fediverse.replies.length %></span>
     81        <span title="<%= t('fedi.replies') %>">💬 <%= (fediverse.thread || []).length %></span>
    8382      </p>
    84       <% if (fediverse.replies.length) { %>
     83      <% if (fediverse.thread && fediverse.thread.length) { %>
    8584        <ol class="comments-list">
    86           <% fediverse.replies.forEach(function(r) { %>
    87             <li class="comment">
    88               <div class="comment-avatar">
    89                 <% if (r.actor_icon) { %><img src="<%= r.actor_icon %>" alt="" loading="lazy">
    90                 <% } else { %><span><%= (r.actor_name || '?').charAt(0).toUpperCase() %></span><% } %>
    91               </div>
    92               <div class="comment-body">
    93                 <div class="comment-meta">
    94                   <a class="comment-author" href="<%= r.actor_url %>" rel="nofollow noopener" target="_blank"><%= r.actor_name %></a>
    95                   <span class="fedi-handle"><%= r.actor_handle %></span>
    96                   <% if (r.published || r.created_at) { %><span class="comment-time"><%= formatDateTime(r.published || r.created_at) %></span><% } %>
    97                 </div>
    98                 <div class="comment-content"><%- r.content %></div>
    99 
    100                 <% if (typeof canManageSite !== 'undefined' && canManageSite) { %>
    101                   <details class="fedi-replybox">
    102                     <summary class="comment-reply-btn fedi-reply-toggle"><%= t('fedi.reply') %></summary>
    103                     <form method="post" action="<%= _base %>/posts/<%= post.slug %>/fedi-reply" class="comment-reply-form">
    104                       <input type="hidden" name="interaction_id" value="<%= r.id %>">
    105                       <textarea name="text" rows="3" required placeholder="<%= t('fedi.reply_ph') %>"></textarea>
    106                       <div class="comment-reply-form-actions">
    107                         <button type="submit" class="btn btn-primary"><%= t('fedi.send') %></button>
    108                       </div>
    109                     </form>
    110                   </details>
    111                 <% } else if (r.object_uri) { %>
    112                   <div class="comment-actions">
    113                     <button type="button" class="comment-reply-btn fedi-remote-reply-btn" data-fedi-uri="<%= r.object_uri %>" data-fedi-prompt="<%= t('fedi.remote_prompt') %>">
    114                       <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>
    115                       <%= t('fedi.remote_reply_short') %>
    116                     </button>
    117                   </div>
    118                 <% } %>
    119 
    120                 <% var mine = (typeof fediverse.outReplies !== 'undefined' ? fediverse.outReplies : []).filter(function(o){ return o.in_reply_to && o.in_reply_to === r.object_uri; }); %>
    121                 <% if (mine.length) { %>
    122                   <ol class="comment-replies">
    123                     <% mine.forEach(function(o){ %>
    124                       <li class="comment comment-reply">
    125                         <div class="comment-avatar">
    126                           <% if (typeof siteAvatar !== 'undefined' && siteAvatar) { %><img src="<%= siteAvatar %>" alt="">
    127                           <% } else { %><span><%= t('fedi.you').charAt(0).toUpperCase() %></span><% } %>
    128                         </div>
    129                         <div class="comment-body">
    130                           <div class="comment-meta"><span class="comment-author"><%= t('fedi.you') %></span></div>
    131                           <div class="comment-content"><%- o.content %></div>
    132                         </div>
    133                       </li>
    134                     <% }); %>
    135                   </ol>
    136                 <% } %>
    137               </div>
    138             </li>
     85          <% fediverse.thread.forEach(function(n){ %>
     86            <li class="comment"><%- include('../partials/fedi-node', { n: n }) %></li>
    13987          <% }); %>
    14088        </ol>
Note: See TracChangeset for help on using the changeset viewer.