source: Klonkt/src/views/partials/msg-item.ejs@ 0448e34

main
Last change on this file since 0448e34 was 0448e34, checked in by Claude (agent) <aiclaude@…>, 5 weeks ago

Gesprekken verborg regels die geen draad werden

Robins melding: een draad die je zelf begonnen bent viel weg onder Gesprekken.
Oorzaak was een halve opruiming van mijn kant. De chips gingen van zes naar
vier, maar msg-item bleef 'sent' en 'msgs' als data-kind uitdelen aan regels die
om wat voor reden dan ook geen draad werden. Die twee chips bestaan niet meer,
dus zo'n regel matchte geen enkel filter en was alleen nog onder Alles te zien.

Geraakt werden: een verzonden bericht zonder post en zonder herkenbare
ontvanger, een mention zonder afzender, en een losse privé-reply. Alles wat een
gesprek is krijgt nu data-kind 'conv'; alleen Activiteit en Moderatie houden een
eigen emmer.

Daarnaast de oorzaak een stap eerder aangepakt: een direct bericht kan zonder
to_handle in ap_outbox staan, en dan vond threadKey geen tegenpartij. De eerste
uit to_actors telt nu ook, met to_handle als winnaar zodat dezelfde persoon niet
twee draden oplevert. Juist een gesprek dat JIJ begon heeft vaak niets anders om
aan te hangen, dus daar deed het ontbreken van die terugval het meeste pijn.

Getest tegen dev: de drie gevallen renderden aantoonbaar als data-kind sent/msgs
en doen dat nu als conv, terwijl like en report op act en mod blijven. Suite
410/410, met twee nieuwe tests op de to_actors-terugval.

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

  • Property mode set to 100644
File size: 12.2 KB
Line 
1<% if (n.type === 'thread') { %>
2<%
3 var _tseen = (typeof seen !== 'undefined' && seen) ? seen : 0;
4 // Een draad is nieuw zodra EEN bericht erin nieuw is.
5 var _tnew = !!_tseen && (n.messages || []).some(function (m) {
6 return m.created_at && Date.parse(m.created_at) > _tseen;
7 });
8 var _tpeople = (n.people || []).map(function (p) { return p.name || p.handle || '?'; });
9 // Alleen jij aan het woord: dan is de tegenpartij het adres waaraan
10 // je schreef, niet een lege naam.
11 var _tto = ((n.messages || []).find(function (m) { return m.to_handle; }) || {}).to_handle;
12 var _tlabel = _tpeople.length ? _tpeople.join(', ') : (_tto || t('msg.you'));
13 %>
14 <li class="msg-item msg-thread<%= _tnew ? ' is-new' : '' %>" data-kind="conv" data-who="<%= (_tpeople.join(' ') + ' ' + (_tto || '')).toLowerCase() %>">
15 <div class="msg-thread-head">
16 <span class="msg-thread-who"><%= _tlabel %></span>
17 <% if (n.count > 1) { %><span class="msg-thread-count"><%= n.count %></span><% } %>
18 <% if (_tnew) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
19 <%# De context bij de draad: waar gaat dit gesprek over? Zonder deze
20 link is een antwoord in een lijst niet te plaatsen. %>
21 <% if (n.post) { %>
22 <a class="msg-thread-post" href="/<%= n.post.slug %>">
23 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
24 <%= n.post.title || n.post.slug %>
25 </a>
26 <% } %>
27 </div>
28 <ul class="msg-thread-msgs">
29 <% (n.messages || []).forEach(function (m) { %><%- include('msg-item', { n: m, seen: _tseen, inThread: true }) %><% }); %>
30 </ul>
31 </li>
32<% } else { %>
33<%
34 var _seen = (typeof seen !== 'undefined' && seen) ? seen : 0;
35 var _t = n.type === 'announce' ? 'boost' : n.type; // reply|mention|report|like|boost|follow|sent
36 var _new = _seen && n.created_at ? (Date.parse(n.created_at) > _seen) : false;
37 var _who = n.name || n.handle || '';
38 var _priv0 = (n.visibility === 'followers' || n.visibility === 'direct');
39 // Emmers: Activiteit = likes/boosts/follows/polls, Moderatie =
40 // reports, en al het overige is gesprek. De oude emmers 'msgs' en
41 // 'sent' bestaan niet meer sinds Berichten, Gesprekken en Verzonden
42 // samenvielen -- en dat is geen cosmetische hernoeming: een
43 // gespreksregel die om wat voor reden dan ook geen draad werd (geen
44 // post, geen herkenbare tegenpartij) hield anders een data-kind
45 // waarvoor geen chip meer bestond, en was daarmee onder ELKE chip
46 // behalve Alles onzichtbaar.
47 var _kind = (_t === 'like' || _t === 'boost' || _t === 'follow' || _t === 'poll_done') ? 'act'
48 : _t === 'report' ? 'mod'
49 : 'conv';
50 // Binnen een draad is dit geen zelfstandige regel: de chip filtert op
51 // de draad, niet op de losse zinnen erin.
52 var _sub = (typeof inThread !== 'undefined' && inThread);
53 var _init = String(_who || '?').replace(/^@/, '').charAt(0).toUpperCase();
54 var _priv = (n.visibility === 'followers' || n.visibility === 'direct');
55 %>
56 <li class="<%= _sub ? 'msg-sub' : 'msg-item' %> msg-<%= _t %><%= _new ? ' is-new' : '' %>"<% if (!_sub) { %> data-kind="<%= _kind %>"<% } %> data-who="<%= String(_who).toLowerCase() %>">
57 <span class="msg-av<%= _t === 'sent' ? ' msg-av-sent' : '' %>" aria-hidden="true">
58 <% if (_t === 'sent') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
59 <% } else if (_t === 'poll_done') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
60 <% } else if (n.icon) { %><img src="<%= avatar(n.icon, 96) %>" alt="" loading="lazy">
61 <% } else { %><%= _init %><% } %>
62 <span class="msg-dot msg-dot-<%= _t %>">
63 <% if (_t === 'like') { %><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.6l2.9 5.88 6.49.95-4.7 4.58 1.11 6.46L12 17.96l-5.8 3.06 1.1-6.46-4.69-4.58 6.49-.95z"/></svg>
64 <% } else if (_t === 'boost') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
65 <% } else if (_t === 'follow') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>
66 <% } else if (_t === 'report') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>
67 <% } else if (_t === 'mention') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"/></svg>
68 <% } else if (_t === 'sent') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>
69 <% } else if (_t === 'poll_done') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
70 <% } else { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg><% } %>
71 </span>
72 </span>
73
74 <div class="msg-body">
75 <div class="msg-line">
76 <% if (_t === 'sent') { %>
77 <span class="msg-who"><%= t('msg.you') %></span>
78 <% if (n.to_handle) { %><span class="msg-handle">→ <%= n.to_handle %></span><% } %>
79 <% } else { %>
80 <a class="msg-who" href="<%= n.url %>" target="_blank" rel="nofollow noopener"><%- emojiName(_who, n.actor_emoji_json) %></a>
81 <% if (n.handle && n.name) { %><span class="msg-handle"><%= n.handle %></span><% } %>
82 <% } %>
83 <% if (_new) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
84 <% /* When the post was written, like de Krant and de Guardian PWA
85 show it. created_at (when it reached us) stays the sort key
86 and drives the "new since your last visit" dot above. */ %>
87 <% if (n.published || n.created_at) { %><span class="msg-time"><%= formatDateTime(n.published || n.created_at) %></span><% } %>
88 </div>
89
90 <div class="msg-what">
91 <% if (n.count && n.count > 1) { %>
92 <strong><%= t('msg.and_more', { n: n.count - 1 }) %></strong>
93 <%= _t === 'like' ? t('msg.liked_many') : t('msg.boosted_many') %>
94 <% } else if (_t === 'follow') { %><%= t('notif.followed') %>
95 <% } else if (_t === 'like') { %><%= t('notif.liked') %>
96 <% } else if (_t === 'boost') { %><%= t('notif.boosted') %>
97 <% } else if (_t === 'report') { %><%= t('notif.reported') %>
98 <% } else if (_t === 'mention' && n.help_request) { %>🛟 <%= t('msg.help_request') %>
99 <% } else if (_t === 'mention' && n.wave) { %>👋 <%= t('msg.waved_at_you') %>
100 <% } else if (_t === 'mention') { %><%= t('notif.mentioned') %>
101 <% } else if (_t === 'sent') { %><%= t('msg.sent_reply') %>
102 <% } else if (_t === 'poll_done') { %><strong><%= t('msg.poll_done') %></strong>
103 <% } else { %><%= t('notif.replied') %><% } %>
104 <% if (_priv) { %><span class="msg-priv" title="<%= t('msg.private_hint') %>">🔒 <%= t('msg.private') %></span><% } %>
105 <% if (n.post_slug && !_sub) { %><a class="msg-post" href="/<%= n.post_slug %>"><%= n.post_title || n.post_slug %></a><% } %>
106 <% if (_t === 'mention' && n.note_url) { %><a class="msg-post" href="<%= n.note_url %>" target="_blank" rel="nofollow noopener"><%= t('tl.view_original') %></a><% } %>
107 <% if (_t === 'sent' && n.in_reply_to) { %><a class="msg-post" href="<%= n.in_reply_to %>" target="_blank" rel="nofollow noopener"><%= t('tl.view_original') %></a><% } %>
108 </div>
109
110 <% if (_t === 'report' && n.content) { %><div class="msg-content"><%= n.content %></div>
111 <% } else if ((_t === 'reply' || _t === 'mention' || _t === 'sent') && n.content) { %><div class="msg-content msg-note"><%- include('../partials/note-body', { nb: n }) %></div>
112 <% if (_t === 'mention' && n.wave && n.actorUri && canMutate) { %>
113 <form class="msg-quickreply" method="post" action="<%= (typeof siteUrlBase !== 'undefined' ? siteUrlBase : '') %>/messages/quick-reply" style="display:flex;gap:6px;flex-wrap:wrap;margin-top:6px">
114 <input type="hidden" name="to" value="<%= n.actorUri %>">
115 <button class="btn small" name="text" value="<%= t('msg.wave_r1') %>"><%= t('msg.wave_r1') %></button>
116 <button class="btn small" name="text" value="<%= t('msg.wave_r2') %>"><%= t('msg.wave_r2') %></button>
117 <button class="btn small" name="text" value="👋"><%= t('msg.wave_back') %></button>
118 </form>
119 <% } %>
120 <% } else if (_t === 'poll_done' && n.poll) { %>
121 <div class="msg-poll" role="group">
122 <% n.poll.options.forEach(function (o) { %>
123 <div class="msg-poll-opt">
124 <div class="msg-poll-top"><span class="msg-poll-name"><%= o.name %></span><span class="msg-poll-pct"><%= o.pct %>%</span></div>
125 <div class="msg-poll-bar"><span style="width:<%= o.pct %>%"></span></div>
126 </div>
127 <% }); %>
128 <div class="msg-poll-total"><%= t('msg.poll_total', { n: n.poll.voters }) %></div>
129 </div>
130 <% } %>
131
132 <% if (_t === 'sent' && n.outboxId) { %>
133 <div class="msg-actions">
134 <details class="msg-edit">
135 <summary><%= t('fedi.edit') %></summary>
136 <div class="msg-edit-form">
137 <%- include('../partials/reply-editor', {
138 action: '/fediverse/' + n.outboxId + '/edit',
139 placeholder: t('fedi.reply_ph'),
140 submitLabel: t('fedi.save_edit'),
141 rows: 2,
142 initialHtml: n.content,
143 initialText: n.editable,
144 defaultLang: n.language,
145 noAttach: true,
146 }) %>
147 </div>
148 </details>
149 <form method="post" action="/fediverse/<%= n.outboxId %>/delete" data-confirm="<%= t('fedi.delete_confirm') %>">
150 <button type="submit" class="msg-del"><%= t('comments.delete') %></button>
151 </form>
152 </div>
153 <% } %>
154 </div>
155 </li>
156<% } %>
Note: See TracBrowser for help on using the repository browser.