From 5f07eb734eaa44f8a7120cee3ae06c7195c3a02a Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Thu, 29 Jan 2026 17:05:26 +0100 Subject: [PATCH] feat(matrix-web): add markdown formatting support - Support **bold** and __bold__ syntax - Support *italic* and _italic_ syntax - Support `inline code` with styled background - Support ~~strikethrough~~ text - Refactor linkifyText to formatMessageBody Co-Authored-By: Claude Opus 4.5 --- .../src/lib/components/chat/Message.svelte | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/apps/matrix/apps/web/src/lib/components/chat/Message.svelte b/apps/matrix/apps/web/src/lib/components/chat/Message.svelte index 5eaafc3f2..2bf503ba7 100644 --- a/apps/matrix/apps/web/src/lib/components/chat/Message.svelte +++ b/apps/matrix/apps/web/src/lib/components/chat/Message.svelte @@ -67,15 +67,43 @@ .replace(/'/g, '''); } - // Convert URLs to clickable links - function linkifyText(text: string, isOwn: boolean): string { + // Apply markdown formatting (bold, italic, code, strikethrough) + function applyMarkdown(text: string, isOwn: boolean): string { + const codeColor = isOwn ? 'bg-white/20 text-white' : 'bg-black/5 dark:bg-white/10'; + + // Inline code (backticks) - process first to avoid conflicts + text = text.replace(/`([^`]+)`/g, `$1`); + + // Bold (**text** or __text__) + text = text.replace(/\*\*([^*]+)\*\*/g, '$1'); + text = text.replace(/__([^_]+)__/g, '$1'); + + // Italic (*text* or _text_) - be careful not to match inside URLs + text = text.replace(/(?$1'); + text = text.replace(/(?$1'); + + // Strikethrough (~~text~~) + text = text.replace(/~~([^~]+)~~/g, '$1'); + + return text; + } + + // Convert URLs to clickable links and apply markdown + function formatMessageBody(text: string, isOwn: boolean): string { const escaped = escapeHtml(text); const linkClass = isOwn ? 'underline underline-offset-2 hover:opacity-80' : 'text-primary underline underline-offset-2 hover:opacity-80'; - return escaped.replace(urlRegex, (url) => { + + // First apply markdown + let formatted = applyMarkdown(escaped, isOwn); + + // Then linkify URLs + formatted = formatted.replace(urlRegex, (url) => { return `${url}`; }); + + return formatted; } // Extract first URL for preview @@ -403,7 +431,7 @@

{:else} -

{@html linkifyText(message.body, message.isOwn)}

+

{@html formatMessageBody(message.body, message.isOwn)}

{#if firstUrl()}