From 0f1b23772cf4974e01a94c329beca13721931c7a Mon Sep 17 00:00:00 2001 From: Fretux Date: Wed, 7 Jan 2026 10:58:10 +0100 Subject: [PATCH] Add markdown rendering for chat messages --- public/index.html | 6 ++-- public/script.js | 25 ++++++++++++++-- public/style.css | 73 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 7 deletions(-) diff --git a/public/index.html b/public/index.html index 69240fa..75321b1 100644 --- a/public/index.html +++ b/public/index.html @@ -73,7 +73,7 @@
- +
@@ -82,6 +82,8 @@
- + + + diff --git a/public/script.js b/public/script.js index 0b7046c..710f853 100644 --- a/public/script.js +++ b/public/script.js @@ -67,6 +67,16 @@ function setAuthMessage(msg, state = "") { authMsg.className = state ? `status ${state}` : 'status'; } +function setMessageContent(element, content) { + if (window.marked && window.DOMPurify) { + const rendered = marked.parse(content, { breaks: true }); + element.innerHTML = DOMPurify.sanitize(rendered); + return; + } + + element.textContent = content; +} + function addMessage(content, isUser = false, isLoading = false, saveToHistory = true) { const msgDiv = document.createElement('div'); msgDiv.className = `msg ${isUser ? 'user' : 'bot'}${isLoading ? ' loading' : ''}`; @@ -80,7 +90,16 @@ function addMessage(content, isUser = false, isLoading = false, saveToHistory = `; } else { - msgDiv.textContent = content; + const header = document.createElement('div'); + header.className = 'msg-header'; + header.textContent = isUser ? 'You' : 'DeepFake'; + + const body = document.createElement('div'); + body.className = 'msg-content'; + setMessageContent(body, content); + + msgDiv.appendChild(header); + msgDiv.appendChild(body); if (saveToHistory) { chatHistory.push({ @@ -204,7 +223,7 @@ async function sendMessage() { if (isProcessing) return; const msg = msgInput.value.trim(); if (!msg) return; - addMessage(`You: ${msg}`, true); + addMessage(msg, true); msgInput.value = ""; msgInput.style.height = 'auto'; setLoadingState(true); @@ -216,7 +235,7 @@ async function sendMessage() { messagesDiv.removeChild(loadingMsg); } if (res.reply) { - addMessage(`DeepFake: ${res.reply}`, false); + addMessage(res.reply, false); } else { addMessage(`[Error: ${res.error}]`, false); } diff --git a/public/style.css b/public/style.css index f9f5a4d..977ce36 100644 --- a/public/style.css +++ b/public/style.css @@ -338,9 +338,12 @@ button:disabled { overflow-wrap: break-word; animation: fadeIn 0.3s ease; position: relative; - white-space: pre-wrap; + white-space: normal; margin: 0; flex-shrink: 0; + display: flex; + flex-direction: column; + gap: 6px; } @keyframes fadeIn { @@ -377,6 +380,73 @@ button:disabled { justify-content: center; } +.msg-header { + font-size: 0.7rem; + letter-spacing: 0.12em; + text-transform: uppercase; + font-weight: 700; + color: rgba(255, 255, 255, 0.7); +} + +.msg-content { + display: grid; + gap: 10px; +} + +.msg-content > * { + margin: 0; +} + +.msg-content p { + margin: 0; +} + +.msg-content ul, +.msg-content ol { + margin: 0; + padding-left: 20px; +} + +.msg-content li { + margin: 4px 0; +} + +.msg-content pre { + background: rgba(15, 15, 35, 0.9); + padding: 12px 14px; + border-radius: 12px; + overflow-x: auto; + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.msg-content code { + font-family: "JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + background: rgba(255, 255, 255, 0.08); + padding: 2px 6px; + border-radius: 6px; + font-size: 0.9em; +} + +.msg-content pre code { + background: transparent; + padding: 0; +} + +.msg-content blockquote { + margin: 0; + padding-left: 14px; + border-left: 3px solid rgba(255, 255, 255, 0.2); + color: var(--text-secondary); +} + +.msg-content a { + color: #93c5fd; +} + +.msg-content a:hover { + color: #bfdbfe; +} + .typing-indicator { display: flex; align-items: center; gap: 6px; height: 16px; } .typing-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-secondary); animation: typingAnimation 1.2s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: -0.32s; } @@ -490,4 +560,3 @@ html, body { overflow-wrap: break-word; word-break: break-word; } -