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/pages/authorize-interaction.ejs

    r2d66d66 r33e1dbd  
    189189    <p class="auth-interact-or"><%= t('fedi.or_reply') %></p>
    190190    <p class="auth-interact-where">💬 <%= t('fedi.reply_where') %></p>
    191     <form method="post" action="/authorize_interaction" class="auth-interact-form">
    192       <input type="hidden" name="uri" value="<%= uri %>">
    193       <textarea name="text" rows="4" required placeholder="<%= t('fedi.reply_ph') %>"></textarea>
    194       <div class="auth-interact-actions">
    195         <button type="submit" class="btn"><%= t('fedi.send') %></button>
    196         <a href="<%= uri %>" class="btn"><%= t('comments.cancel') %></a>
    197       </div>
    198     </form>
     191    <div class="auth-interact-form">
     192      <%- include('../partials/reply-editor', {
     193        action: '/authorize_interaction',
     194        hiddenFields: [{ name: 'uri', value: uri }],
     195        placeholder: t('fedi.reply_ph'),
     196        submitLabel: t('fedi.send'),
     197        rows: 4,
     198      }) %>
     199      <div class="auth-interact-actions"><a href="<%= uri %>" class="btn"><%= t('comments.cancel') %></a></div>
     200    </div>
    199201    <p class="auth-interact-note"><%= t('fedi.remote_as', { site: siteTitle }) %></p>
    200202    <details class="auth-report">
Note: See TracChangeset for help on using the changeset viewer.