| 1 | <%#
|
|---|
| 2 | Een post van een andere server: hoe hij eruit ziet, en wat je ermee kunt.
|
|---|
| 3 |
|
|---|
| 4 | EEN PLEK, DRIE INGANGEN: de live-preview onder de zoekbalk, de zoekpagina en
|
|---|
| 5 | /authorize_interaction. Eén render, zodat een poort, een sanitizer of een knop
|
|---|
| 6 | niet op één plek vergeten kan worden. De formulieren posten overal naar
|
|---|
| 7 | /authorize_interaction/..., want daar zit het werk en de rechtencontrole.
|
|---|
| 8 |
|
|---|
| 9 | Hij ziet eruit als een POST, niet als een formulier over een post: kop met
|
|---|
| 10 | gezicht, de inhoud, en één rij knoppen eronder. Wat daar vroeger omheen stond
|
|---|
| 11 | (een zin "je reageert op", een aparte knop naar het origineel, twee grote
|
|---|
| 12 | pillen, "of reageer:" en een altijd open antwoordvenster) is teruggebracht tot
|
|---|
| 13 | die ene rij. Antwoorden klapt pas open als je erom vraagt, melden staat
|
|---|
| 14 | onderaan en niet in de weg.
|
|---|
| 15 |
|
|---|
| 16 | Verwacht: target (uit resolveRemoteNote), uri, reacted {liked,boosted}.
|
|---|
| 17 | Optioneel:
|
|---|
| 18 | compact de live-preview: geen antwoordvenster en geen meldformulier; die
|
|---|
| 19 | twee staan een tik verder op de volle pagina. Een editor in een
|
|---|
| 20 | uitklaplijst is op een telefoon geen plek om te schrijven.
|
|---|
| 21 | mayReply false = alleen lezen en reageren, geen antwoordknop
|
|---|
| 22 | replyOpen het antwoordvenster staat al open (?reply=1, de terugval zonder JS)
|
|---|
| 23 | reportOpen idem voor melden (?report=1)
|
|---|
| 24 | cancelUrl waar Annuleren heen gaat zonder JS, standaard de volle pagina
|
|---|
| 25 | siteTitle
|
|---|
| 26 | %>
|
|---|
| 27 | <%
|
|---|
| 28 | const _compact = !!locals.compact;
|
|---|
| 29 | const _mayReply = locals.mayReply !== false;
|
|---|
| 30 | const _full = '/authorize_interaction?uri=' + encodeURIComponent(uri);
|
|---|
| 31 | const _cancel = locals.cancelUrl || _full;
|
|---|
| 32 | const _liked = !!(locals.reacted && reacted.liked);
|
|---|
| 33 | const _boosted = !!(locals.reacted && reacted.boosted);
|
|---|
| 34 | const _src = target.url || uri;
|
|---|
| 35 | // Een inhoudswaarschuwing wordt gerespecteerd. De oude render toonde alles
|
|---|
| 36 | // gewoon open, ook wat de schrijver achter een waarschuwing had gezet.
|
|---|
| 37 | const _warn = target.cw || (target.sensitive ? t('fedi.sensitive') : '');
|
|---|
| 38 | const _imgs = (target.images || []).slice(0, 4);
|
|---|
| 39 | const _initial = String(target.actor_name || target.actor_handle || '?').replace(/^@/, '').slice(0, 1).toUpperCase();
|
|---|
| 40 | %>
|
|---|
| 41 | <article class="rp-card<%= _compact ? ' rp-compact' : '' %>">
|
|---|
| 42 | <header class="rp-head">
|
|---|
| 43 | <% if (target.actor_icon) { %>
|
|---|
| 44 | <img class="rp-avatar" src="<%= target.actor_icon %>" alt="" width="40" height="40" loading="lazy">
|
|---|
| 45 | <% } else { %>
|
|---|
| 46 | <span class="rp-avatar rp-avatar-empty" aria-hidden="true"><%= _initial %></span>
|
|---|
| 47 | <% } %>
|
|---|
| 48 | <div class="rp-who">
|
|---|
| 49 | <a class="rp-name" href="<%= target.actor_url || target.actor_uri %>" rel="nofollow noopener" target="_blank"><%= target.actor_name || target.actor_handle %></a>
|
|---|
| 50 | <span class="rp-handle"><%= target.actor_handle %></span>
|
|---|
| 51 | </div>
|
|---|
| 52 | </header>
|
|---|
| 53 |
|
|---|
| 54 | <% if (_warn) { %>
|
|---|
| 55 | <details class="rp-cw">
|
|---|
| 56 | <summary><span class="rp-cw-text"><%= _warn %></span><span class="rp-cw-open"><%= t('fedi.cw_open') %></span></summary>
|
|---|
| 57 | <% } %>
|
|---|
| 58 | <% if (target.content) { %>
|
|---|
| 59 | <div class="rp-body"><%- target.content %></div>
|
|---|
| 60 | <% } else if (target.preview) { %>
|
|---|
| 61 | <div class="rp-body"><p><%= target.preview %></p></div>
|
|---|
| 62 | <% } %>
|
|---|
| 63 | <% if (_imgs.length) { %>
|
|---|
| 64 | <div class="rp-media rp-media-<%= _imgs.length %>">
|
|---|
| 65 | <% _imgs.forEach(function (im) { %>
|
|---|
| 66 | <a href="<%= im %>" target="_blank" rel="nofollow noopener"><img src="<%= im %>" alt="" loading="lazy"></a>
|
|---|
| 67 | <% }); %>
|
|---|
| 68 | </div>
|
|---|
| 69 | <% } %>
|
|---|
| 70 | <% if (_warn) { %>
|
|---|
| 71 | </details>
|
|---|
| 72 | <% } %>
|
|---|
| 73 |
|
|---|
| 74 | <% if (target.poll) { var _pl = target.poll; var _tot = _pl.options.reduce(function(s,o){return s+(o.count||0);},0); var _vn = (_pl.voters!=null?_pl.voters:_tot); %>
|
|---|
| 75 | <% if (!_pl.closed) { %>
|
|---|
| 76 | <form method="post" action="/authorize_interaction/vote" class="rp-poll">
|
|---|
| 77 | <input type="hidden" name="uri" value="<%= uri %>">
|
|---|
| 78 | <% _pl.options.forEach(function(o){ %>
|
|---|
| 79 | <label class="rp-poll-choice"><input type="<%= _pl.multiple ? 'checkbox' : 'radio' %>" name="choice" value="<%= o.name %>"><span><%= o.name %></span></label>
|
|---|
| 80 | <% }); %>
|
|---|
| 81 | <div class="rp-poll-foot">
|
|---|
| 82 | <span><%= _vn %> <%= _vn === 1 ? t('poll.voter_one') : t('poll.voter_many') %><% if (_pl.endTime) { %> · <%= t('poll.closes') %> <%= new Date(_pl.endTime).toLocaleString() %><% } %><% if (_pl.multiple) { %> · <%= t('poll.multiple') %><% } %></span>
|
|---|
| 83 | <button type="submit" class="rp-act rp-primary"><%= t('poll.vote') %></button>
|
|---|
| 84 | </div>
|
|---|
| 85 | </form>
|
|---|
| 86 | <% } else { %>
|
|---|
| 87 | <div class="rp-poll">
|
|---|
| 88 | <% _pl.options.forEach(function(o){ var _pct = _tot ? Math.round((o.count||0)*100/_tot) : 0; %>
|
|---|
| 89 | <div class="rp-poll-res"><span class="rp-poll-fill" style="width:<%= _pct %>%"></span><span class="rp-poll-name"><%= o.name %></span><span class="rp-poll-pct"><%= _pct %>%</span></div>
|
|---|
| 90 | <% }); %>
|
|---|
| 91 | <div class="rp-poll-foot"><span><%= _vn %> <%= _vn === 1 ? t('poll.voter_one') : t('poll.voter_many') %> · <%= t('poll.closed') %></span></div>
|
|---|
| 92 | </div>
|
|---|
| 93 | <% } %>
|
|---|
| 94 | <% } %>
|
|---|
| 95 |
|
|---|
| 96 | <%# Eén rij. Op een smalle telefoon vallen de woorden weg en blijven de
|
|---|
| 97 | tekens staan, elk minstens 44 punten groot: een duim is geen muis. De
|
|---|
| 98 | woorden blijven voor een schermlezer wel gewoon bestaan. %>
|
|---|
| 99 | <footer class="rp-actions">
|
|---|
| 100 | <% if (_mayReply) { %>
|
|---|
| 101 | <a class="rp-act rp-reply-btn" href="<%= _full %>&reply=1#rp-reply" data-rp-reply<% if (!_compact) { %> aria-controls="rp-reply" aria-expanded="<%= locals.replyOpen ? 'true' : 'false' %>"<% } %>>
|
|---|
| 102 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><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>
|
|---|
| 103 | <span class="rp-act-label"><%= t('fedi.reply_short') %></span>
|
|---|
| 104 | </a>
|
|---|
| 105 | <% } %>
|
|---|
| 106 | <form method="post" action="/authorize_interaction/like" class="fedi-react-form">
|
|---|
| 107 | <input type="hidden" name="uri" value="<%= uri %>">
|
|---|
| 108 | <button type="submit" class="rp-act rp-like<%= _liked ? ' is-on' : '' %>" aria-pressed="<%= _liked %>" data-on="<%= t('fedi.unlike_short') %>" data-off="<%= t('fedi.like_short') %>">
|
|---|
| 109 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" aria-hidden="true"><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>
|
|---|
| 110 | <span class="rp-act-label"><%= _liked ? t('fedi.unlike_short') : t('fedi.like_short') %></span>
|
|---|
| 111 | </button>
|
|---|
| 112 | </form>
|
|---|
| 113 | <form method="post" action="/authorize_interaction/boost" class="fedi-react-form">
|
|---|
| 114 | <input type="hidden" name="uri" value="<%= uri %>">
|
|---|
| 115 | <button type="submit" class="rp-act rp-boost<%= _boosted ? ' is-on' : '' %>" aria-pressed="<%= _boosted %>" data-on="<%= t('tl.unboost') %>" data-off="<%= t('fedi.boost_short') %>">
|
|---|
| 116 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><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>
|
|---|
| 117 | <span class="rp-act-label"><%= _boosted ? t('tl.unboost') : t('fedi.boost_short') %></span>
|
|---|
| 118 | </button>
|
|---|
| 119 | </form>
|
|---|
| 120 | <a class="rp-act rp-src" href="<%= _src %>" target="_blank" rel="nofollow noopener" title="<%= t('fedi.remote_view_original') %>">
|
|---|
| 121 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 17 17 7"/><path d="M7 7h10v10"/></svg>
|
|---|
| 122 | <span class="rp-act-label"><%= t('fedi.src_short') %></span>
|
|---|
| 123 | </a>
|
|---|
| 124 | </footer>
|
|---|
| 125 | </article>
|
|---|
| 126 |
|
|---|
| 127 | <% if (_compact) { %>
|
|---|
| 128 | <a class="rp-open" href="<%= _full %>"><%= t('fedi.open_full') %> →</a>
|
|---|
| 129 | <% } else { %>
|
|---|
| 130 | <% if (_mayReply) { %>
|
|---|
| 131 | <%# Dicht tot je op Reageer tikt. Zonder JS opent ?reply=1 hem, zodat de
|
|---|
| 132 | knop ook dan ergens heen gaat. %>
|
|---|
| 133 | <section class="rp-reply" id="rp-reply"<%= locals.replyOpen ? '' : ' hidden' %>>
|
|---|
| 134 | <p class="rp-reply-where"><%= t('fedi.reply_where') %></p>
|
|---|
| 135 | <%- include('./reply-editor', {
|
|---|
| 136 | action: '/authorize_interaction',
|
|---|
| 137 | hiddenFields: [{ name: 'uri', value: uri }],
|
|---|
| 138 | placeholder: t('fedi.reply_ph'),
|
|---|
| 139 | submitLabel: t('fedi.send'),
|
|---|
| 140 | rows: 4,
|
|---|
| 141 | participants: (target && target.actor_uri) ? [{
|
|---|
| 142 | uri: target.actor_uri,
|
|---|
| 143 | url: target.actor_url || target.actor_uri,
|
|---|
| 144 | handle: target.actor_handle || '',
|
|---|
| 145 | }] : [],
|
|---|
| 146 | }) %>
|
|---|
| 147 | <div class="rp-reply-foot"><a href="<%= _cancel %>" class="rp-act" data-rp-reply-close><%= t('comments.cancel') %></a></div>
|
|---|
| 148 | </section>
|
|---|
| 149 | <% } %>
|
|---|
| 150 | <p class="rp-as"><%= t('fedi.remote_as', { site: siteTitle }) %></p>
|
|---|
| 151 | <details class="rp-report" id="rp-report"<%= locals.reportOpen ? ' open' : '' %>>
|
|---|
| 152 | <summary><%= t('fedi.report_open') %></summary>
|
|---|
| 153 | <form method="post" action="/authorize_interaction/report" class="rp-report-form">
|
|---|
| 154 | <input type="hidden" name="uri" value="<%= uri %>">
|
|---|
| 155 | <input type="hidden" name="actor_uri" value="<%= target.actor_uri %>">
|
|---|
| 156 | <p class="rp-report-note"><%= t('fedi.report_where') %></p>
|
|---|
| 157 | <textarea name="reason" rows="3" maxlength="3000" placeholder="<%= t('fedi.report_ph') %>"></textarea>
|
|---|
| 158 | <div><button type="submit" class="btn btn-danger"><%= t('fedi.report_send') %></button></div>
|
|---|
| 159 | </form>
|
|---|
| 160 | </details>
|
|---|
| 161 | <% } %>
|
|---|