From 17398e8e4199f04f016c7f92cd9b8d9cc6e99d60 Mon Sep 17 00:00:00 2001 From: MarekWo Date: Mon, 27 Jul 2026 11:58:53 +0200 Subject: [PATCH] feat(chat): quote with the '>' line prefix instead of guillemets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Quote button produced `@[user] »text« ` — a shape mc-webui invented back when it could not send newlines, and one that other MeshCore clients neither write nor understand. It now writes the quote on its own line behind a '>' and leaves the cursor underneath it, matching the plain-text convention some users already type by hand. processQuotes() styles both syntaxes, so messages sent by older builds keep their formatting. The '>' match is anchored to a line start or a leading @[mention] badge and looks for the escaped '>', so neither "5 > 3" in prose nor the brackets of generated tags can trigger it. Co-Authored-By: Claude Opus 5 --- app/static/js/app.js | 8 ++++++-- app/static/js/message-utils.js | 26 ++++++++++++++++++++------ docs/user-guide.md | 13 +++++++++++++ docs/whatsnew.md | 11 ++++++++++- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/app/static/js/app.js b/app/static/js/app.js index 76b1c52..a3a9dbf 100644 --- a/app/static/js/app.js +++ b/app/static/js/app.js @@ -1531,11 +1531,15 @@ function truncateToBytes(text, maxBytes) { } /** - * Insert a quote into the message input. + * Insert a quote into the message input, leaving the cursor on a fresh line + * for the reply. Uses the `>` line prefix rather than the guillemets of older + * versions, so the quote also reads as one in clients that don't style it. */ function insertQuote(username, quotedText) { const input = document.getElementById('messageInput'); - input.value = `@[${username}] »${quotedText}« `; + // One '>' per line — a quoted multi-line message stays fully quoted. + const quoted = quotedText.split('\n').map(line => `>${line}`).join('\n'); + input.value = `@[${username}] ${quoted}\n`; updateCharCounter(); input.focus(); } diff --git a/app/static/js/message-utils.js b/app/static/js/message-utils.js index ba43eee..8de7a49 100644 --- a/app/static/js/message-utils.js +++ b/app/static/js/message-utils.js @@ -134,18 +134,32 @@ function processChannelLinks(text) { } /** - * Convert »quoted text« to styled quote blocks + * Convert quoted text to styled quote blocks. Two syntaxes are recognised: + * `>quoted line` (current, also what other MeshCore clients use) and + * `»quoted text«` (what mc-webui produced before 2.2.0 — still rendered so + * older messages keep their styling). * @param {string} text - HTML-escaped text * @returns {string} - Text with styled quotes */ function processQuotes(text) { - // Match »...« pattern (guillemets) including optional trailing whitespace - const quotePattern = /»([^«]+)«\s*/g; - - return text.replace(quotePattern, (_match, quoted) => { - // Display without guillemets (styling is enough) + line break after + // Legacy guillemets: the markers are dropped (styling replaces them) and + // the pattern eats the space separating quote from reply, hence the
. + const legacyPattern = /»([^«]+)«\s*/g; + text = text.replace(legacyPattern, (_match, quoted) => { return `${quoted}
`; }); + + // `>quoted line`. The text arrives HTML-escaped, so a typed '>' shows up as + // '>' and the '>' of generated tags can never match. Anchored to the + // start of a line or to a leading @[mention] badge, so "5 > 3" mid + // sentence is left alone. The trailing newline stays in place — the message + // containers are pre-wrap and render it as the break. + const quotePattern = /(^|\n|<\/span>[ \t]*)>[ \t]*([^\n]*)/g; + + return text.replace(quotePattern, (match, prefix, quoted) => { + if (!quoted.trim()) return match; + return `${prefix}${quoted}`; + }); } /** diff --git a/docs/user-guide.md b/docs/user-guide.md index 270f256..f31637a 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -163,6 +163,19 @@ Archives are created automatically at midnight (00:00 UTC) each day. The live vi Click the reply button on any message to insert `@[UserName]` into the text field, then type your reply. +### Quoting a Message + +Click the quote button (") on any message to quote it. The quoted text is put on its own line prefixed with `>`, and the cursor lands on the line below it, ready for your answer: + +``` +@[daniel5120] >Are we still on for tonight? +Yes, 8pm works. +``` + +The `>` prefix is the plain-text quoting convention used across the internet and by other MeshCore clients, so your quote reads correctly for everyone, not just mc-webui users. mc-webui shows the quoted line in an italic, tinted block. Quotes typed by hand are styled the same way, as are the `»quoted text«` guillemets mc-webui used before version 2.2.0. + +Long messages open a dialog first, offering the full text or a truncated version — see **Max quote length** in [Settings](#settings). + ### Message Actions Your own messages carry a small row of action buttons: diff --git a/docs/whatsnew.md b/docs/whatsnew.md index fe9df04..f3c6bc6 100644 --- a/docs/whatsnew.md +++ b/docs/whatsnew.md @@ -10,7 +10,16 @@ For deep technical notes, see [architecture.md](architecture.md). For the full g ## Unreleased -_Nothing yet since 2.1.0._ +### New features + +- **Quotes now use the `>` convention everyone else already uses.** Quoting a message used to wrap it in guillemets — `@[Daniel] »Hejka« Cześć!` — a shape mc-webui invented back when it couldn't send multi-line messages. It now puts the quote on its own line behind a `>` and drops the cursor underneath it, so a reply reads as a quote in the standard MeshCore app and every other client too, not just here: + + ``` + @[Daniel] >Are we still on for tonight? + Yes, 8pm works. + ``` + + Quotes you type by hand get the same italic, tinted styling, so `>` written manually now looks like a proper quote as well. Nothing you received earlier changes: the old `»…«` form is still recognised and still displayed exactly as before. ---