source: Klonkt/src/views/partials/msg-item.ejs@ 39111c0

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

Binnen een draad staat de tegenpartij nog maar een keer

Robins melding: de tegenpartij stond er drie keer -- in de uitsparing, en dan
per bubbel nog eens als "You -> @handle". Daaronder herhaalde elke bubbel ook
nog "replied via the fediverse", terwijl dat voor de hele draad geldt. Samen
kostte dat twee regels per bericht aan ruimte die de inhoud toekomt.

Binnen een draad valt nu weg: de handle achter de naam, en de standaardzin over
wat voor soort bericht het is. De naam zelf blijft, want je moet zien WIE wat
zei. Buiten een draad verandert er niets: daar dragen die twee wel informatie.

Wat blijft staan omdat het geen boilerplate is: de hulpvraag-boei, de zwaai, het
slotje bij een prive-bericht en de View-original-links. Is er daarna niets
betekenisvols over, dan vervalt de hele regel in plaats van als lege div ruimte
te blijven pakken.

Gecontroleerd op de dev-data: van de twee bubbels houdt alleen die met een
View-original-link nog een msg-what-regel, en er staat geen herhaalde handle
meer in. Suite 410/410.

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

  • Property mode set to 100644
File size: 12.8 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 <%# Tegenpartij en aantal in EEN uitsparing: het is een label bij het
17 gesprek, geen kop erboven. Zo houdt de inhoud de ruimte. %>
18 <span class="msg-thread-who"><%= _tlabel %><% if (n.count > 1) { %><span class="msg-thread-count"><%= n.count %></span><% } %></span>
19 <% if (_tnew) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
20 <%# De context bij de draad: waar gaat dit gesprek over? Zonder deze
21 link is een antwoord in een lijst niet te plaatsen. %>
22 <% if (n.post) { %>
23 <a class="msg-thread-post" href="/<%= n.post.slug %>">
24 <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>
25 <%= n.post.title || n.post.slug %>
26 </a>
27 <% } %>
28 </div>
29 <ul class="msg-thread-msgs">
30 <% (n.messages || []).forEach(function (m) { %><%- include('msg-item', { n: m, seen: _tseen, inThread: true }) %><% }); %>
31 </ul>
32 </li>
33<% } else { %>
34<%
35 var _seen = (typeof seen !== 'undefined' && seen) ? seen : 0;
36 var _t = n.type === 'announce' ? 'boost' : n.type; // reply|mention|report|like|boost|follow|sent
37 var _new = _seen && n.created_at ? (Date.parse(n.created_at) > _seen) : false;
38 var _who = n.name || n.handle || '';
39 var _priv0 = (n.visibility === 'followers' || n.visibility === 'direct');
40 // Emmers: Activiteit = likes/boosts/follows/polls, Moderatie =
41 // reports, en al het overige is gesprek. De oude emmers 'msgs' en
42 // 'sent' bestaan niet meer sinds Berichten, Gesprekken en Verzonden
43 // samenvielen -- en dat is geen cosmetische hernoeming: een
44 // gespreksregel die om wat voor reden dan ook geen draad werd (geen
45 // post, geen herkenbare tegenpartij) hield anders een data-kind
46 // waarvoor geen chip meer bestond, en was daarmee onder ELKE chip
47 // behalve Alles onzichtbaar.
48 var _kind = (_t === 'like' || _t === 'boost' || _t === 'follow' || _t === 'poll_done') ? 'act'
49 : _t === 'report' ? 'mod'
50 : 'conv';
51 // Binnen een draad is dit geen zelfstandige regel: de chip filtert op
52 // de draad, niet op de losse zinnen erin.
53 var _sub = (typeof inThread !== 'undefined' && inThread);
54 var _init = String(_who || '?').replace(/^@/, '').charAt(0).toUpperCase();
55 var _priv = (n.visibility === 'followers' || n.visibility === 'direct');
56 %>
57 <li class="<%= _sub ? 'msg-sub' : 'msg-item' %> msg-<%= _t %><%= _new ? ' is-new' : '' %>"<% if (!_sub) { %> data-kind="<%= _kind %>"<% } %> data-who="<%= String(_who).toLowerCase() %>">
58 <span class="msg-av<%= _t === 'sent' ? ' msg-av-sent' : '' %>" aria-hidden="true">
59 <% 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>
60 <% } 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>
61 <% } else if (n.icon) { %><img src="<%= avatar(n.icon, 96) %>" alt="" loading="lazy">
62 <% } else { %><%= _init %><% } %>
63 <span class="msg-dot msg-dot-<%= _t %>">
64 <% 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>
65 <% } 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>
66 <% } 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>
67 <% } 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>
68 <% } 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>
69 <% } 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>
70 <% } 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>
71 <% } 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><% } %>
72 </span>
73 </span>
74
75 <div class="msg-body">
76 <div class="msg-line">
77 <% if (_t === 'sent') { %>
78 <span class="msg-who"><%= t('msg.you') %></span>
79 <% if (n.to_handle && !_sub) { %><span class="msg-handle">→ <%= n.to_handle %></span><% } %>
80 <% } else { %>
81 <a class="msg-who" href="<%= n.url %>" target="_blank" rel="nofollow noopener"><%- emojiName(_who, n.actor_emoji_json) %></a>
82 <% /* De naam blijft: binnen een draad moet je zien WIE wat zei.
83 De handle erachter niet -- die staat in de kop. */ %>
84 <% if (n.handle && n.name && !_sub) { %><span class="msg-handle"><%= n.handle %></span><% } %>
85 <% } %>
86 <% if (_new) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
87 <% /* When the post was written, like de Krant and de Guardian PWA
88 show it. created_at (when it reached us) stays the sort key
89 and drives the "new since your last visit" dot above. */ %>
90 <% if (n.published || n.created_at) { %><span class="msg-time"><%= formatDateTime(n.published || n.created_at) %></span><% } %>
91 </div>
92
93 <% var _hasWhat = !_sub || _priv
94 || (_t === 'mention' && (n.help_request || n.wave || n.note_url))
95 || (_t === 'sent' && n.in_reply_to); %>
96 <% if (_hasWhat) { %>
97 <div class="msg-what">
98 <% if (n.count && n.count > 1) { %>
99 <strong><%= t('msg.and_more', { n: n.count - 1 }) %></strong>
100 <%= _t === 'like' ? t('msg.liked_many') : t('msg.boosted_many') %>
101 <% } else if (_t === 'follow') { %><%= t('notif.followed') %>
102 <% } else if (_t === 'like') { %><%= t('notif.liked') %>
103 <% } else if (_t === 'boost') { %><%= t('notif.boosted') %>
104 <% } else if (_t === 'report') { %><%= t('notif.reported') %>
105 <% } else if (_t === 'mention' && n.help_request) { %>🛟 <%= t('msg.help_request') %>
106 <% } else if (_t === 'mention' && n.wave) { %>👋 <%= t('msg.waved_at_you') %>
107 <% } else if (_sub) { %><%# binnen een draad zegt de kop al dat dit een gesprek is %>
108 <% } else if (_t === 'mention') { %><%= t('notif.mentioned') %>
109 <% } else if (_t === 'sent') { %><%= t('msg.sent_reply') %>
110 <% } else if (_t === 'poll_done') { %><strong><%= t('msg.poll_done') %></strong>
111 <% } else { %><%= t('notif.replied') %><% } %>
112 <% if (_priv) { %><span class="msg-priv" title="<%= t('msg.private_hint') %>">🔒 <%= t('msg.private') %></span><% } %>
113 <% if (n.post_slug && !_sub) { %><a class="msg-post" href="/<%= n.post_slug %>"><%= n.post_title || n.post_slug %></a><% } %>
114 <% if (_t === 'mention' && n.note_url) { %><a class="msg-post" href="<%= n.note_url %>" target="_blank" rel="nofollow noopener"><%= t('tl.view_original') %></a><% } %>
115 <% 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><% } %>
116 </div>
117 <% } %>
118
119 <% if (_t === 'report' && n.content) { %><div class="msg-content"><%= n.content %></div>
120 <% } else if ((_t === 'reply' || _t === 'mention' || _t === 'sent') && n.content) { %><div class="msg-content msg-note"><%- include('../partials/note-body', { nb: n }) %></div>
121 <% if (_t === 'mention' && n.wave && n.actorUri && canMutate) { %>
122 <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">
123 <input type="hidden" name="to" value="<%= n.actorUri %>">
124 <button class="btn small" name="text" value="<%= t('msg.wave_r1') %>"><%= t('msg.wave_r1') %></button>
125 <button class="btn small" name="text" value="<%= t('msg.wave_r2') %>"><%= t('msg.wave_r2') %></button>
126 <button class="btn small" name="text" value="👋"><%= t('msg.wave_back') %></button>
127 </form>
128 <% } %>
129 <% } else if (_t === 'poll_done' && n.poll) { %>
130 <div class="msg-poll" role="group">
131 <% n.poll.options.forEach(function (o) { %>
132 <div class="msg-poll-opt">
133 <div class="msg-poll-top"><span class="msg-poll-name"><%= o.name %></span><span class="msg-poll-pct"><%= o.pct %>%</span></div>
134 <div class="msg-poll-bar"><span style="width:<%= o.pct %>%"></span></div>
135 </div>
136 <% }); %>
137 <div class="msg-poll-total"><%= t('msg.poll_total', { n: n.poll.voters }) %></div>
138 </div>
139 <% } %>
140
141 <% if (_t === 'sent' && n.outboxId) { %>
142 <div class="msg-actions">
143 <details class="msg-edit">
144 <summary><%= t('fedi.edit') %></summary>
145 <div class="msg-edit-form">
146 <%- include('../partials/reply-editor', {
147 action: '/fediverse/' + n.outboxId + '/edit',
148 placeholder: t('fedi.reply_ph'),
149 submitLabel: t('fedi.save_edit'),
150 rows: 2,
151 initialHtml: n.content,
152 initialText: n.editable,
153 defaultLang: n.language,
154 noAttach: true,
155 }) %>
156 </div>
157 </details>
158 <form method="post" action="/fediverse/<%= n.outboxId %>/delete" data-confirm="<%= t('fedi.delete_confirm') %>">
159 <button type="submit" class="msg-del"><%= t('comments.delete') %></button>
160 </form>
161 </div>
162 <% } %>
163 </div>
164 </li>
165<% } %>
Note: See TracBrowser for help on using the repository browser.