Changeset 3ceaef6 in Klonkt for src/views


Ignore:
Timestamp:
09/30/2026 06:16:32 AM (5 hours ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
9eb6e1b
Parents:
407353e
Message:

Zoeken op een adres: het object erachter, met de knoppen erbij

Plak je een link naar een fediverse-post of -profiel in de zoekbalk, dan is dat
geen zoekterm maar een aanwijzing. Klonkt haalt hem op en zet hem bovenaan de
resultaten, met dezelfde knoppen als /authorize_interaction: antwoorden,
waarderen, boosten, stemmen, volgen en melden.

De weg erheen was vooral opruimen. De render en de formulieren stonden als 200
regels in authorize-interaction.ejs, en er een tweede kopie van maken voor de
zoekpagina zou een tweede plek zijn waar een poort, een sanitizer of een knop
vergeten kan worden. Ze staan nu in partials/remote-object.ejs en
partials/remote-actor.ejs, met de opmaak in een derde. De pagina die ze had
gebruikt ze nu ook, dus er is één render en de formulieren posten in beide
gevallen naar /authorize_interaction/..., waar het werk en de rechtencontrole
al zaten.

DRIE DINGEN DIE VASTLIGGEN, en elk om een eigen reden:

Het schema is verplicht. "soundfabrics.nl" is een geldige zoekterm -- iemand
zoekt naar de naam -- en een kale domeinnaam als adres opvatten maakt van elke
zoekopdracht met een punt erin een netwerkverzoek. Met ​https:// ervoor is er
geen twijfel over de bedoeling.

Ophalen mag alleen een beheerder van de site laten doen. Dat is dezelfde grens
als /authorize_interaction, en met opzet: ophalen is een uitgaand verzoek dat
deze server namens de bezoeker doet. Zonder die grens is de zoekbalk een
haalservice waarmee een vreemde deze server laat aankloppen op adressen naar
keuze. Een bezoeker die toch een link plakt krijgt de gewone zoekresultaten en
een zin die zegt waarom er verder niets staat.

De ophaling gaat ONDERTEKEND als de site. Een post die alleen voor volgers
zichtbaar is weigert een anonieme GET, en dan lijkt een bestaande post te
ontbreken -- dezelfde val als bij het antwoorden op een post van een vriend.

Bijgekomen zonder dat erom gevraagd is, en het is het vermelden waard: het
profiel toont nu zijn avatar. Die hadden we al in handen (actor_icon uit
resolveRemoteActor) en hij stond op geen van beide schermen.

Getoetst: de herkenning zelf, dat een zoekterm GEEN verzoek wordt, dat de post
met zijn vier formulieren binnenkomt, dat een profiel de volgknop geeft, dat
een bezoeker niets laat ophalen, en dat /authorize_interaction na de verhuizing
nog steeds hetzelfde toont -- die pagina had zelf geen enkele toets, dus dat
was de bodem die er onder moest. Tegenproef per zaak.

Nog open: een @naam@server in de zoekbalk (webfinger kan het al, dus klein
werk) en een hint in de live-suggesties terwijl je plakt.

shaer-utpi

Location:
src/views
Files:
3 added
2 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/authorize-interaction.ejs

    r407353e r3ceaef6  
    9595  <% } else if (typeof followTarget !== 'undefined' && followTarget) { %>
    9696  <h1 class="auth-interact-title"><%= t('fedi.follow_heading') %></h1>
    97   <p class="auth-interact-meta">
    98     <%= t('fedi.follow_intro') %>
    99     <a href="<%= followTarget.actor_url %>" rel="nofollow noopener" target="_blank"><strong><%= followTarget.actor_name %></strong></a>
    100     <span class="fedi-handle"><%= followTarget.actor_handle %></span>
    101   </p>
    102   <form method="post" action="/authorize_interaction/follow" class="auth-interact-form">
    103     <input type="hidden" name="uri" value="<%= followTarget.actor_uri %>">
    104     <div class="auth-interact-actions">
    105       <button type="submit" class="btn btn-primary"><%= t('fedi.follow_btn') %></button>
    106       <a href="/" class="btn"><%= t('comments.cancel') %></a>
    107     </div>
    108   </form>
    109   <p class="auth-interact-note"><%= t('fedi.remote_as', { site: siteTitle }) %></p>
     97  <%- include('../partials/remote-actor', { actor: followTarget, cancelUrl: '/', siteTitle: siteTitle }) %>
    11098  <% } else { %>
    11199  <h1 class="auth-interact-title"><%= t('fedi.remote_title') %></h1>
    … …  
    118106    </form>
    119107  <% } else { %>
    120     <p class="auth-interact-meta">
    121       <%= t('fedi.remote_replying_to') %>
    122       <a href="<%= target.actor_url %>" rel="nofollow noopener" target="_blank"><strong><%= target.actor_name %></strong></a>
    123       <span class="fedi-handle"><%= target.actor_handle %></span>
    124     </p>
    125     <blockquote class="auth-interact-preview">
    126       <% if (target.content) { %><div class="auth-interact-content"><%- target.content %></div>
    127       <% } else if (target.preview) { %><%= target.preview %><% } %>
    128       <% (target.images || []).forEach(function(im){ %>
    129         <img class="auth-interact-img" src="<%= im %>" alt="" loading="lazy">
    130       <% }); %>
    131     </blockquote>
    132     <% if (target.url || uri) { %>
    133       <a class="auth-view-src" href="<%= target.url || uri %>" target="_blank" rel="nofollow noopener">
    134         <svg viewBox="0 0 24 24" width="17" height="17" 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>
    135         <span><%= t('fedi.remote_view_original') %></span>
    136       </a>
    137     <% } %>
    138     <% 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); %>
    139       <% if (!_pl.closed) { %>
    140         <form method="post" action="/authorize_interaction/vote" class="auth-poll">
    141           <input type="hidden" name="uri" value="<%= uri %>">
    142           <% _pl.options.forEach(function(o){ %>
    143             <label class="auth-poll-choice"><input type="<%= _pl.multiple ? 'checkbox' : 'radio' %>" name="choice" value="<%= o.name %>"><span><%= o.name %></span></label>
    144           <% }); %>
    145           <div class="auth-interact-actions">
    146             <button type="submit" class="btn btn-primary"><%= t('poll.vote') %></button>
    147           </div>
    148           <p class="auth-poll-foot"><%= _vn %> <%= _vn === 1 ? t('poll.voter_one') : t('poll.voter_many') %> · <%= t('poll.open') %><% if (_pl.endTime) { %> · <%= t('poll.closes') %> <%= new Date(_pl.endTime).toLocaleString() %><% } %><% if (_pl.multiple) { %> · <%= t('poll.multiple') %><% } %></p>
    149         </form>
    150       <% } else { %>
    151         <div class="auth-poll">
    152           <% _pl.options.forEach(function(o){ var _pct = _tot ? Math.round((o.count||0)*100/_tot) : 0; %>
    153             <div class="auth-poll-res"><span class="auth-poll-fill" style="width:<%= _pct %>%"></span><span class="auth-poll-name"><%= o.name %></span><span class="auth-poll-pct"><%= _pct %>%</span></div>
    154           <% }); %>
    155           <p class="auth-poll-foot"><%= _vn %> <%= _vn === 1 ? t('poll.voter_one') : t('poll.voter_many') %> · <%= t('poll.closed') %><% if (_pl.multiple) { %> · <%= t('poll.multiple') %><% } %></p>
    156         </div>
    157       <% } %>
    158     <% } %>
    159     <% var _liked = (typeof reacted !== 'undefined' && reacted.liked); var _boosted = (typeof reacted !== 'undefined' && reacted.boosted); %>
    160     <div class="auth-interact-react">
    161       <form method="post" action="/authorize_interaction/like" class="fedi-react-form">
    162         <input type="hidden" name="uri" value="<%= uri %>">
    163         <button type="submit" class="fedi-bigact fedi-bigact-like<%= _liked ? ' is-on' : '' %>" data-on="<%= t('fedi.unlike_short') %>" data-off="<%= t('fedi.like_short') %>">
    164           <svg viewBox="0 0 24 24" fill="currentColor" 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>
    165           <span class="fedi-bigact-label"><%= _liked ? t('fedi.unlike_short') : t('fedi.like_short') %></span>
    166         </button>
    167       </form>
    168       <form method="post" action="/authorize_interaction/boost" class="fedi-react-form">
    169         <input type="hidden" name="uri" value="<%= uri %>">
    170         <button type="submit" class="fedi-bigact fedi-bigact-boost<%= _boosted ? ' is-on' : '' %>" data-on="<%= t('tl.unboost') %>" data-off="<%= t('fedi.boost_short') %>">
    171           <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>
    172           <span class="fedi-bigact-label"><%= _boosted ? t('tl.unboost') : t('fedi.boost_short') %></span>
    173         </button>
    174       </form>
    175     </div>
    176     <% if (locals.mayReply !== false) { %>
    177     <p class="auth-interact-or"><%= t('fedi.or_reply') %></p>
    178     <p class="auth-interact-where">💬 <%= t('fedi.reply_where') %></p>
    179     <div class="auth-interact-form">
    180       <%- include('../partials/reply-editor', {
    181         action: '/authorize_interaction',
    182         hiddenFields: [{ name: 'uri', value: uri }],
    183         placeholder: t('fedi.reply_ph'),
    184         submitLabel: t('fedi.send'),
    185         rows: 4,
    186         participants: (target && target.actor_uri) ? [{
    187           uri: target.actor_uri,
    188           url: target.actor_url || target.actor_uri,
    189           handle: target.actor_handle || '',
    190         }] : [],
    191       }) %>
    192       <div class="auth-interact-actions"><a href="<%= uri %>" class="btn"><%= t('comments.cancel') %></a></div>
    193     </div>
    194     <% } %>
    195     <p class="auth-interact-note"><%= t('fedi.remote_as', { site: siteTitle }) %></p>
    196     <details class="auth-report">
    197       <summary>🚩 <%= t('fedi.report_open') %></summary>
    198       <form method="post" action="/authorize_interaction/report" class="auth-interact-form">
    199         <input type="hidden" name="uri" value="<%= uri %>">
    200         <input type="hidden" name="actor_uri" value="<%= target.actor_uri %>">
    201         <p class="auth-report-note"><%= t('fedi.report_where') %></p>
    202         <textarea name="reason" rows="3" maxlength="3000" placeholder="<%= t('fedi.report_ph') %>"></textarea>
    203         <div class="auth-interact-actions">
    204           <button type="submit" class="btn btn-danger"><%= t('fedi.report_send') %></button>
    205         </div>
    206       </form>
    207     </details>
     108    <%- include('../partials/remote-object', { target: target, uri: uri, reacted: (typeof reacted !== 'undefined' ? reacted : { liked: false, boosted: false }), siteTitle: siteTitle, cancelUrl: uri }) %>
    208109  <% } %>
    209110  <% } %>
    210111</div>
    211112
    212 <style>
    213   .auth-interact { max-width: 640px; margin: 1rem auto; padding: 0 1rem; }
    214   .auth-interact-title { margin: 0 0 1rem; }
    215   .auth-interact-meta { color: var(--ink-soft, #888); margin: 0 0 .75rem; }
    216   .auth-interact-preview {
    217     margin: 0 0 1rem; padding: .75rem 1rem; border-left: 3px solid var(--accent, #888);
    218     background: color-mix(in srgb, var(--ink, #000) 4%, transparent); border-radius: 0 12px 12px 0;
    219     color: var(--ink, inherit);
    220   }
    221   .auth-interact-form { display: flex; flex-direction: column; gap: .75rem; }
    222   .auth-interact-form textarea, .auth-interact-form input[type=url] {
    223     width: 100%; box-sizing: border-box; padding: .6rem .8rem; font: inherit; resize: vertical;
    224     border-radius: 12px; border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent);
    225     background: var(--paper, #fff); color: var(--ink, #000);
    226   }
    227   .auth-interact-actions { display: flex; gap: .5rem; align-items: center; }
    228   .auth-interact-note { color: var(--ink-soft, #999); font-size: .85rem; margin-top: 1rem; }
    229   .auth-interact-where { margin: .25rem 0 .85rem; padding: .6rem .8rem; font-size: .85rem; line-height: 1.5; border-radius: 10px; background: color-mix(in srgb, var(--accent, #888) 12%, transparent); color: var(--ink, inherit); }
    230   .auth-interact-content { line-height: 1.55; }
    231   .auth-interact-content p { margin: .35rem 0; }
    232   .auth-interact-content p:first-child { margin-top: 0; }
    233   .auth-interact-img { max-width: 100%; height: auto; border-radius: 10px; margin: .5rem 0 0; display: block; }
    234   .auth-interact-orig { margin: .75rem 0 0; font-size: .85rem; }
    235   .auth-interact-orig a { color: var(--accent, #06c); }
    236   .auth-view-src { display: inline-flex; align-items: center; gap: .5rem; margin: 0 0 1.1rem; padding: .6rem 1rem;
    237     border: 1px solid color-mix(in srgb, var(--accent, #888) 45%, transparent); border-radius: 12px;
    238     background: color-mix(in srgb, var(--accent, #888) 10%, transparent); color: var(--accent, #06c);
    239     text-decoration: none; font-weight: 600; font-size: .92rem; transition: background .15s, border-color .15s; }
    240   .auth-view-src:hover { background: color-mix(in srgb, var(--accent, #888) 18%, transparent); border-color: var(--accent, #888); }
    241   .auth-interact-react { display: flex; gap: .6rem; flex-wrap: wrap; margin: 0 0 .25rem; }
    242   .auth-interact-react form { margin: 0; }
    243   .fedi-bigact { display: inline-flex; align-items: center; gap: .5rem; padding: .55rem 1.1rem; border-radius: 999px;
    244     border: 1px solid color-mix(in srgb, var(--ink, #000) 14%, transparent);
    245     background: color-mix(in srgb, var(--ink, #000) 4%, transparent);
    246     color: var(--ink, inherit); font: inherit; font-weight: 600; font-size: .92rem; cursor: pointer; white-space: nowrap;
    247     transition: background .12s, border-color .12s; }
    248   .fedi-bigact svg { width: 17px; height: 17px; flex: 0 0 17px; }
    249   .fedi-bigact-like svg { color: #e8b04b; }
    250   .fedi-bigact-like:hover, .fedi-bigact-like.is-on { background: color-mix(in srgb, #e8b04b 16%, transparent); border-color: color-mix(in srgb, #e8b04b 55%, transparent); }
    251   .fedi-bigact-boost svg { color: #2fa85a; }
    252   .fedi-bigact-boost:hover, .fedi-bigact-boost.is-on { background: color-mix(in srgb, #2fa85a 16%, transparent); border-color: color-mix(in srgb, #2fa85a 55%, transparent); }
    253   .fedi-manage { list-style: none; padding: 0; margin: 1.25rem 0 1rem; display: flex; flex-direction: column; gap: .7rem; }
    254   .fedi-manage-item { padding: .9rem 1rem; border-radius: 14px; background: color-mix(in srgb, var(--ink, #000) 3.5%, transparent); border: 1px solid color-mix(in srgb, var(--ink, #000) 9%, transparent); transition: border-color .15s ease, box-shadow .15s ease; }
    255   .fedi-manage-item:hover { border-color: color-mix(in srgb, var(--accent, #888) 28%, transparent); box-shadow: 0 2px 12px color-mix(in srgb, var(--ink, #000) 6%, transparent); }
    256   .fedi-manage-head { display: flex; align-items: center; gap: .5rem; margin: 0 0 .5rem; }
    257   .fedi-manage-icon { flex: 0 0 26px; width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
    258     background: color-mix(in srgb, var(--accent, #888) 16%, transparent); color: var(--accent, #06c); }
    259   .fedi-manage-icon svg { width: 14px; height: 14px; }
    260   .fedi-manage-to { font-weight: 600; color: var(--ink, inherit); font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
    261   .fedi-manage-time { color: var(--ink-soft, #999); font-size: .76rem; margin-left: auto; flex: 0 0 auto; white-space: nowrap; }
    262   .fedi-manage-content { line-height: 1.55; overflow-wrap: anywhere; padding-left: calc(26px + .5rem); }
    263   .fedi-manage-content p { margin: .15rem 0; }
    264   .fedi-manage-content p:first-child { margin-top: 0; }
    265   .fedi-manage-content p:last-child { margin-bottom: 0; }
    266   .fedi-manage-foot { display: flex; align-items: center; justify-content: flex-start; flex-wrap: wrap; gap: .5rem; margin-top: .65rem; }
    267   .fedi-goto-btn { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid color-mix(in srgb, var(--accent, #888) 45%, transparent); background: color-mix(in srgb, var(--accent, #888) 12%, transparent); color: var(--accent, #06c); border-radius: 999px; padding: .3rem .8rem; font-size: .82rem; text-decoration: none; transition: background .15s ease; }
    268   .fedi-goto-btn:hover { background: color-mix(in srgb, var(--accent, #888) 22%, transparent); }
    269   .fedi-del-btn { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid color-mix(in srgb, #d9534f 45%, transparent); background: color-mix(in srgb, #d9534f 12%, transparent); color: #e06b66; border-radius: 999px; padding: .3rem .8rem; font: inherit; font-size: .82rem; cursor: pointer; transition: background .15s ease; }
    270   .fedi-del-btn:hover { background: color-mix(in srgb, #d9534f 24%, transparent); }
    271   .fedi-bm { margin: 0 0 1.5rem; padding: 1rem; border-radius: 14px;
    272     border: 1px dashed color-mix(in srgb, var(--accent, #888) 45%, transparent);
    273     background: color-mix(in srgb, var(--accent, #888) 7%, transparent); }
    274   .fedi-bm-btn { display: inline-flex; align-items: center; gap: .45rem; padding: .5rem 1rem; border-radius: 999px;
    275     background: var(--accent, #06c); color: #fff; font: inherit; font-weight: 600; font-size: .9rem; text-decoration: none;
    276     cursor: grab; user-select: none; box-shadow: 0 2px 8px color-mix(in srgb, var(--accent, #000) 30%, transparent); }
    277   .fedi-bm-btn:active { cursor: grabbing; }
    278   .fedi-bm-btn.nudge { animation: fedi-bm-nudge .6s ease; }
    279   @keyframes fedi-bm-nudge { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
    280   .fedi-bm-help { color: var(--ink-soft, #888); font-size: .82rem; line-height: 1.5; margin: .6rem 0 0; }
    281   .fedi-edit-btn { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid color-mix(in srgb, var(--ink, #888) 28%, transparent);
    282     background: color-mix(in srgb, var(--ink, #888) 8%, transparent); color: var(--ink-soft, #aaa); border-radius: 999px; padding: .3rem .8rem;
    283     font: inherit; font-size: .82rem; cursor: pointer; transition: background .15s ease, color .15s ease; }
    284   .fedi-edit-btn:hover { background: color-mix(in srgb, var(--ink, #888) 16%, transparent); }
    285   .fedi-edit-btn.is-open { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
    286   .fedi-del-form { margin-left: auto; }
    287   .fedi-edit-form { display: none; margin: .55rem 0 0; }
    288   .fedi-edit-form.is-open { display: block; }
    289   .fedi-edit-ta { width: 100%; box-sizing: border-box; min-height: 70px; resize: vertical; padding: .55rem .7rem;
    290     border: 1.5px solid var(--rule, #333); border-radius: 10px; background: var(--paper-2, #14141a); color: var(--ink, #eee); font: inherit; font-size: .9rem; }
    291   .fedi-edit-ta:focus { outline: none; border-color: var(--accent); }
    292   .fedi-edit-actions { display: flex; justify-content: flex-end; margin-top: .5rem; }
    293   .fedi-edit-save { padding: .4rem 1rem; border: 0; border-radius: 999px; background: var(--accent); color: var(--paper, #fff);
    294     font: inherit; font-weight: 600; font-size: .82rem; cursor: pointer; }
    295   /* Poll ballot / results on the interact page */
    296   .auth-poll { display: flex; flex-direction: column; gap: 8px; margin: 0 0 1rem; }
    297   .auth-poll-choice { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 10px; cursor: pointer;
    298     border: 1px solid color-mix(in srgb, var(--ink, #000) 14%, transparent); }
    299   .auth-poll-choice:hover { border-color: var(--accent); }
    300   .auth-poll-choice input { accent-color: var(--accent); }
    301   .auth-poll-res { position: relative; padding: 9px 12px; border-radius: 10px; overflow: hidden; display: flex; align-items: center; gap: 8px;
    302     background: color-mix(in srgb, var(--ink, #000) 6%, transparent); }
    303   .auth-poll-fill { position: absolute; inset: 0 auto 0 0; background: color-mix(in srgb, var(--accent) 22%, transparent); z-index: 0; }
    304   .auth-poll-name { position: relative; z-index: 1; flex: 1; font-size: .95rem; }
    305   .auth-poll-pct { position: relative; z-index: 1; font-variant-numeric: tabular-nums; font-weight: 500; }
    306   .auth-poll-foot { font-size: .82rem; color: var(--ink-soft, #888); margin: .1rem 0 0; }
    307   .auth-report { margin: .6rem 0 0; }
    308   .auth-report summary { cursor: pointer; font-size: .85rem; color: var(--ink-soft, #888); }
    309   .auth-report summary:hover, .auth-report[open] summary { color: #c0392b; }
    310   .auth-report[open] summary { margin-bottom: .5rem; }
    311   .auth-report-note { font-size: .82rem; color: var(--ink-muted, #999); margin: 0 0 .5rem; }
    312 </style>
    313 
    314 
     113<%- include('../partials/fedi-interact-styles') %>
  • src/views/pages/search.ejs

    r407353e r3ceaef6  
    2626      <%= t(total === 1 ? 'search.results_one' : 'search.results_other', { n: total, q: query }) %>
    2727    </p>
     28  <% } %>
     29
     30  <%# Een geplakt adres is geen zoekterm maar een aanwijzing (shaer-utpi): het
     31      object van de andere server staat bovenaan, met dezelfde knoppen als op
     32      /authorize_interaction -- dezelfde partial, dus één render en één plek
     33      waar een poort of een sanitizer kan wonen. %>
     34  <% if (typeof remoteUri !== 'undefined' && remoteUri) { %>
     35    <h2 class="search-section-title"><%= t('search.section_fediverse') %></h2>
     36    <div class="auth-interact search-remote">
     37      <% if (!mayLookup) { %>
     38        <%# Ophalen is een uitgaand verzoek namens deze server; dat doen we niet
     39            op verzoek van een willekeurige bezoeker. %>
     40        <p class="auth-interact-note"><%= t('search.fedi_signin') %></p>
     41      <% } else if (remote && remoteKind === 'note') { %>
     42        <%- include('../partials/remote-object', { target: remote, uri: remoteUri, reacted: remoteReacted, siteTitle: siteTitle, cancelUrl: _base + '/search' }) %>
     43      <% } else if (remote && remoteKind === 'actor') { %>
     44        <%- include('../partials/remote-actor', { actor: remote, cancelUrl: _base + '/search', siteTitle: siteTitle }) %>
     45      <% } else { %>
     46        <p class="auth-interact-note"><%= t('fedi.remote_notfound') %></p>
     47      <% } %>
     48    </div>
     49    <%- include('../partials/fedi-interact-styles') %>
    2850  <% } %>
    2951
Note: See TracChangeset for help on using the changeset viewer.