Changeset 33e1dbd in Klonkt for src/views/partials/fedi-node.ejs


Ignore:
Timestamp:
07/19/2026 05:08:32 PM (7 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
feced2c
Parents:
2d66d66
git-author:
Robin <roboburr@…> (07/19/2026 05:08:12 PM)
git-committer:
Robin <roboburr@…> (07/19/2026 05:08:32 PM)
Message:

Feature: rich replies phase 1 — shared editor, mobile full-screen, language (klonkt-demo-c7f)

Replying to fediverse comments used bare textareas in four places. This adds
ONE shared, progressively-enhanced editor component and mounts it on the two
new-reply spots (inline thread reply in fedi-node, and authorize_interaction);
the edit forms and prutter follow with the media phase.

  • partials/reply-editor.ejs + assets/js/reply-editor.js + css: renders a plain textarea that works without JS; the JS upgrades it to a contenteditable with a small toolbar (bold/italic/link/list/quote) and a language select. Assets load once per render even when the partial repeats per comment.
  • Mobile (max-width 700px): focusing the editor opens a FULL-SCREEN compose overlay (top bar with cancel and send, scroll lock), the right pattern on phones. Two real-world fixes came out of browser verification: site CSS gives thread forms display:contents, which collapses the form box and breaks both flex and position:fixed (now overridden with !important); and the overlay sits at z-index 1200, above the bottom tab bar (1050) and sheets (1100).
  • Server: fedi-reply and authorize_interaction accept content (editor HTML) + language next to text. deliverReply sanitizes the HTML (HtmlSanitizerService), runs the same mention/hashtag/URL enrichment as the plain path, and places the parent mention inline in the first paragraph (own paragraph before block content, merged paragraph around bare inline text). Plain-text path unchanged (no-JS fallback).
  • ap_outbox.language (additive) -> contentMap on the outgoing Note.

5 new tests (sanitize, mention placement, plain path unchanged, empty-html
reject, bogus language dropped); 88 green. Live-verified in the browser:
desktop upgrade, mobile full-screen (enter/cancel/scroll-lock), and a real
submit landing in ap_outbox with markup + language intact.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/partials/fedi-node.ejs

    r2d66d66 r33e1dbd  
    3131      <details class="fedi-owner-reply">
    3232        <summary class="fedi-cact fedi-cact-reply" title="<%= t('fedi.remote_reply_short') %>" aria-label="<%= t('fedi.remote_reply_short') %>"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg></summary>
    33         <form method="post" action="<%= _base %>/posts/<%= postSlug %>/fedi-reply" class="comment-reply-form">
    34           <input type="hidden" name="interaction_id" value="<%= n.id %>">
    35           <textarea name="text" rows="2" required placeholder="<%= t('fedi.reply_ph') %>"></textarea>
    36           <div class="comment-reply-form-actions">
    37             <button type="submit" class="btn"><%= t('fedi.send') %></button>
    38           </div>
    39         </form>
     33        <%- include('reply-editor', {
     34          action: _base + '/posts/' + postSlug + '/fedi-reply',
     35          hiddenFields: [{ name: 'interaction_id', value: n.id }],
     36          placeholder: t('fedi.reply_ph'),
     37          submitLabel: t('fedi.send'),
     38          rows: 2,
     39        }) %>
    4040      </details>
    4141      <%# Owner moderation: report to their instance + remove (tombstoned: never comes back via re-delivery or thread-crawl). %>
Note: See TracChangeset for help on using the changeset viewer.