Ignore:
Timestamp:
07/19/2026 10:48:15 PM (7 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
ff3b8ce
Parents:
5190152
git-author:
Robin <roboburr@…> (07/19/2026 10:47:10 PM)
git-committer:
Robin <roboburr@…> (07/19/2026 10:48:15 PM)
Message:

Feature: mentions bar with conversation partners (klonkt-demo-u02)

Implicit mentions leave the text and become an editable "To:" bar above the
reply editor: the parent author plus the thread's ancestor authors as chips.
Removing a chip stops addressing that partner (no mention anchor, no Mention
tag, no inbox ping); explicit @mentions typed in the text keep working via the
existing resolveMentionsInText path.

  • getInteractions: each thread node gets "participants" (author + ancestor chain via the byId map, own nodes skipped, deduped, capped at 8) and carries actor_uri now.
  • reply-editor partial: the bar renders server-side with a hidden "mentions" JSON field carrying the full list, so the no-JS path addresses everyone; the JS removes chips and mirrors the remaining list into the field.
  • deliverReply({mentions}): undefined = legacy parent-only behavior; an array (possibly empty) = the kept list drives the mention prefix, the Mention tags (mentionTags reads the content anchors) and the per-actor inbox pings. to_actor/to_handle follow the kept list (parent when kept, else the first chip, else null -> the note addresses Public only).
  • deliverOutboxUpdate: an edit reuses the OLD content's leading mention anchors instead of rebuilding just to_actor, so co-mentions survive edits (legacy rows fall back as before).
  • Interact page passes the target author as the single chip. Full-screen mobile keeps the top bar above the mentions bar (flex order).

4 new tests (participant chains, multi-chip tags + to_actor, empty bar goes
Public-only, co-mentions survive edits); 97 green. Browser-verified: bar shows
@bob + @alice on a nested reply, removing @alice updates the hidden field, the
sent reply mentions and addresses only @bob; no console errors.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/partials/reply-editor.ejs

    r5190152 re9c9ae1  
    1919    initialText   plain-text prefill for the no-JS textarea (optional)
    2020    noAttach      true hides the media button (edits do not touch attachments)
     21    participants  [{uri, url, handle}] conversation partners → the mentions bar
     22                  (u02): implicit mentions live here as removable chips, not in
     23                  the text. Absent = no bar, legacy addressing.
    2124%>
    2225<% var _reInitHtml = (typeof initialHtml !== 'undefined' && initialHtml) || ''; %>
    2326<% var _reInitText = (typeof initialText !== 'undefined' && initialText) || ''; %>
    2427<% var _reNoAttach = (typeof noAttach !== 'undefined' && noAttach); %>
     28<% var _reParts = (typeof participants !== 'undefined' && participants && participants.length) ? participants : null; %>
    2529<% var _reLang = (typeof defaultLang !== 'undefined' && defaultLang) || (typeof lang !== 'undefined' ? lang : 'en'); %>
    2630<form method="post" action="<%= action %>" class="re-form" data-re
     
    3034  <% }); %>
    3135  <input type="hidden" name="content" value="">
     36  <%# Mentions bar (u02): the conversation partners as removable chips. The
     37      hidden field always carries the CURRENT kept list (server-rendered full,
     38      so the no-JS path addresses everyone). %>
     39  <% if (_reParts) { %>
     40    <input type="hidden" name="mentions" value="<%= JSON.stringify(_reParts) %>">
     41    <div class="re-mentions">
     42      <span class="re-mentions-label"><%= t('re.to') %></span>
     43      <% _reParts.forEach(function (p) { %>
     44        <span class="re-mention" data-uri="<%= p.uri %>"><%= p.handle && p.handle[0] === '@' ? p.handle : '@' + p.handle %><button type="button" class="re-mention-del" title="<%= t('re.mention_del') %>" aria-label="<%= t('re.mention_del') %>">×</button></span>
     45      <% }); %>
     46    </div>
     47  <% } %>
    3248  <%# Full-screen top bar (mobile compose). Hidden until JS + fullscreen. %>
    3349  <div class="re-head" hidden>
Note: See TracChangeset for help on using the changeset viewer.