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

main
Last change on this file since b1512e0 was ef1853c, checked in by Robin Genis <roboburr@…>, 6 weeks ago

Web: custom-emoji ook in messages + threads (Shaer-pariteit)

Na de nieuwsfeed nu ook de andere note-surfaces: messages (msg-item) en
thread-replies (fedi-node) renderen custom-emoji's in de content en in de
auteur-naam. De emoji-tags werden voor replies nog niet bewaard; nu vangt
ap_interactions ze (emoji_json = content-emoji uit o.tag/child.tag,
actor_emoji_json = naam-emoji uit actorInfo) op inbound reply, like/boost en de
thread-crawl, en getNotifications/getInteractions serveren ze mee.

De .emoji-CSS staat nu globaal in shared-styles (was news-only), zodat alle
surfaces 'm delen.

Changed files:
src/config/database.js

  • ap_interactions.emoji_json + actor_emoji_json kolommen

src/services/ActivityPubService.js

  • INSERT ap_interactions + 3 callers (reply/like-boost/thread) vullen de emoji-kolommen
  • emojiJsonOf() helper
  • _listI + getNotifications SELECT en getInteractions-node geven emoji mee

src/views/partials/msg-item.ejs

  • naam + content via emojiName/emojiHtml

src/views/partials/fedi-node.ejs

  • auteur-naam + content via emojiName/emojiHtml

src/views/partials/shared-styles.ejs

  • globale img.emoji-regels (inline, geen media-styling)

src/views/pages/news.ejs

  • dubbele img.emoji-regels weg (nu globaal)

remarks: 187 tests groen. Visueel geverifieerd via standalone render van msg-item
+ fedi-node. Nieuwe replies vangen emoji direct; oude rijen niet (geen self-heal).
Quote-in-replies en de Cirkel-tegel-titels bewust nog niet meegenomen.

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

  • Property mode set to 100644
File size: 9.2 KB
RevLine 
[1485933]1<%
2 var _seen = (typeof seen !== 'undefined' && seen) ? seen : 0;
3 var _t = n.type === 'announce' ? 'boost' : n.type; // reply|mention|report|like|boost|follow|sent
4 var _new = _seen && n.created_at ? (Date.parse(n.created_at) > _seen) : false;
5 var _who = n.name || n.handle || '';
6 var _priv0 = (n.visibility === 'followers' || n.visibility === 'direct');
7 // Buckets (klonkt-demo-3jf): Messages = @mentions + private (DM) replies;
8 // Activity = likes/boosts/follows; Moderation = reports; Sent = your
9 // replies; Conversations = every other (public) reply.
10 var _kind = _t === 'sent' ? 'sent'
11 : (_t === 'like' || _t === 'boost' || _t === 'follow' || _t === 'poll_done') ? 'act'
12 : _t === 'report' ? 'mod'
13 : (_t === 'mention' || _priv0) ? 'msgs'
14 : 'conv';
15 var _init = String(_who || '?').replace(/^@/, '').charAt(0).toUpperCase();
16 var _priv = (n.visibility === 'followers' || n.visibility === 'direct');
17 %>
18 <li class="msg-item msg-<%= _t %><%= _new ? ' is-new' : '' %>" data-kind="<%= _kind %>" data-who="<%= String(_who).toLowerCase() %>">
19 <span class="msg-av<%= _t === 'sent' ? ' msg-av-sent' : '' %>" aria-hidden="true">
20 <% 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>
21 <% } 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>
22 <% } else if (n.icon) { %><img src="<%= avatar(n.icon, 96) %>" alt="" loading="lazy">
23 <% } else { %><%= _init %><% } %>
24 <span class="msg-dot msg-dot-<%= _t %>">
25 <% 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>
26 <% } 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>
27 <% } 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>
28 <% } 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>
29 <% } 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>
30 <% } 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>
31 <% } 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>
32 <% } 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><% } %>
33 </span>
34 </span>
35
36 <div class="msg-body">
37 <div class="msg-line">
38 <% if (_t === 'sent') { %>
39 <span class="msg-who"><%= t('msg.you') %></span>
40 <% if (n.to_handle) { %><span class="msg-handle">→ <%= n.to_handle %></span><% } %>
41 <% } else { %>
[ef1853c]42 <a class="msg-who" href="<%= n.url %>" target="_blank" rel="nofollow noopener"><%- emojiName(_who, n.actor_emoji_json) %></a>
[1485933]43 <% if (n.handle && n.name) { %><span class="msg-handle"><%= n.handle %></span><% } %>
44 <% } %>
45 <% if (_new) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
46 <% if (n.created_at) { %><span class="msg-time"><%= formatDateTime(n.created_at) %></span><% } %>
47 </div>
48
49 <div class="msg-what">
50 <% if (n.count && n.count > 1) { %>
51 <strong><%= t('msg.and_more', { n: n.count - 1 }) %></strong>
52 <%= _t === 'like' ? t('msg.liked_many') : t('msg.boosted_many') %>
53 <% } else if (_t === 'follow') { %><%= t('notif.followed') %>
54 <% } else if (_t === 'like') { %><%= t('notif.liked') %>
55 <% } else if (_t === 'boost') { %><%= t('notif.boosted') %>
56 <% } else if (_t === 'report') { %><%= t('notif.reported') %>
[ad6f62a]57 <% } else if (_t === 'mention' && n.wave) { %>👋 <%= t('msg.waved_at_you') %>
[1485933]58 <% } else if (_t === 'mention') { %><%= t('notif.mentioned') %>
59 <% } else if (_t === 'sent') { %><%= t('msg.sent_reply') %>
60 <% } else if (_t === 'poll_done') { %><strong><%= t('msg.poll_done') %></strong>
61 <% } else { %><%= t('notif.replied') %><% } %>
62 <% if (_priv) { %><span class="msg-priv" title="<%= t('msg.private_hint') %>">🔒 <%= t('msg.private') %></span><% } %>
63 <% if (n.post_slug) { %><a class="msg-post" href="/<%= n.post_slug %>"><%= n.post_title || n.post_slug %></a><% } %>
64 <% if (_t === 'mention' && n.note_url) { %><a class="msg-post" href="<%= n.note_url %>" target="_blank" rel="nofollow noopener"><%= t('tl.view_original') %></a><% } %>
65 <% 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><% } %>
66 </div>
67
68 <% if (_t === 'report' && n.content) { %><div class="msg-content"><%= n.content %></div>
[ef1853c]69 <% } else if ((_t === 'reply' || _t === 'mention' || _t === 'sent') && n.content) { %><div class="msg-content"><%- emojiHtml(n.content, n.emoji_json) %></div>
[ad6f62a]70 <% if (_t === 'mention' && n.wave && n.actorUri && canMutate) { %>
71 <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">
72 <input type="hidden" name="to" value="<%= n.actorUri %>">
73 <button class="btn small" name="text" value="<%= t('msg.wave_r1') %>"><%= t('msg.wave_r1') %></button>
74 <button class="btn small" name="text" value="<%= t('msg.wave_r2') %>"><%= t('msg.wave_r2') %></button>
75 <button class="btn small" name="text" value="👋"><%= t('msg.wave_back') %></button>
76 </form>
77 <% } %>
[1485933]78 <% } else if (_t === 'poll_done' && n.poll) { %>
79 <div class="msg-poll" role="group">
80 <% n.poll.options.forEach(function (o) { %>
81 <div class="msg-poll-opt">
82 <div class="msg-poll-top"><span class="msg-poll-name"><%= o.name %></span><span class="msg-poll-pct"><%= o.pct %>%</span></div>
83 <div class="msg-poll-bar"><span style="width:<%= o.pct %>%"></span></div>
84 </div>
85 <% }); %>
86 <div class="msg-poll-total"><%= t('msg.poll_total', { n: n.poll.voters }) %></div>
87 </div>
88 <% } %>
89
90 <% if (_t === 'sent' && n.outboxId) { %>
91 <div class="msg-actions">
92 <details class="msg-edit">
93 <summary><%= t('fedi.edit') %></summary>
94 <div class="msg-edit-form">
95 <%- include('../partials/reply-editor', {
96 action: '/fediverse/' + n.outboxId + '/edit',
97 placeholder: t('fedi.reply_ph'),
98 submitLabel: t('fedi.save_edit'),
99 rows: 2,
100 initialHtml: n.content,
101 initialText: n.editable,
102 defaultLang: n.language,
103 noAttach: true,
104 }) %>
105 </div>
106 </details>
107 <form method="post" action="/fediverse/<%= n.outboxId %>/delete" data-confirm="<%= t('fedi.delete_confirm') %>">
108 <button type="submit" class="msg-del"><%= t('comments.delete') %></button>
109 </form>
110 </div>
111 <% } %>
112 </div>
113 </li>
Note: See TracBrowser for help on using the repository browser.