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 @@
{@html linkifyText(message.body, message.isOwn)}
+{@html formatMessageBody(message.body, message.isOwn)}
{#if firstUrl()}