Changeset 33e1dbd in Klonkt for src/routes


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/routes/posts.js

    r2d66d66 r33e1dbd  
    712712  const uri = (req.body.uri || '').toString();
    713713  const text = (req.body.text || '').toString();
    714   if (site && uri && text.trim()) {
     714  const html = (req.body.content || '').toString();      // rich reply editor HTML (sanitized in deliverReply)
     715  const language = (req.body.language || '').toString();
     716  if (site && uri && (text.trim() || html.trim())) {
    715717    // Resolve + deliver in the background so Send responds instantly.
    716718    ActivityPubService.resolveRemoteNote(uri)
    717       .then((parent) => parent && ActivityPubService.deliverReply(site, { postId: parent.localPostId || '', postSlug: null, parent, text }))
     719      .then((parent) => parent && ActivityPubService.deliverReply(site, { postId: parent.localPostId || '', postSlug: null, parent, text, html, language }))
    718720      .catch((e) => console.warn('[AP] remote reply failed:', e.message));
    719721  }
     
    12571259  const parent = ActivityPubService.getInteractionById(req.body.interaction_id);
    12581260  const text = (req.body.text || '').toString();
    1259   if (parent && parent.post_id === post.id && text.trim()) {
     1261  const html = (req.body.content || '').toString();      // rich reply editor HTML (sanitized in deliverReply)
     1262  if (parent && parent.post_id === post.id && (text.trim() || html.trim())) {
    12601263    try {
    1261       await ActivityPubService.deliverReply(site, { postId: post.id, postSlug: post.slug, parent, text });
     1264      await ActivityPubService.deliverReply(site, {
     1265        postId: post.id, postSlug: post.slug, parent, text, html,
     1266        language: (req.body.language || '').toString(),
     1267      });
    12621268    } catch (e) { console.warn('[AP] reply send failed:', e.message); }
    12631269  }
Note: See TracChangeset for help on using the changeset viewer.