diff --git a/core/http/static/chat.js b/core/http/static/chat.js index aacf061f4..e908f90f5 100644 --- a/core/http/static/chat.js +++ b/core/http/static/chat.js @@ -2456,11 +2456,7 @@ document.addEventListener("alpine:init", () => { const N = chat.history.length - 1; if (role === "thinking" || role === "reasoning") { - let c = ""; - const lines = content.split("\n"); - lines.forEach((line) => { - c += DOMPurify.sanitize(marked.parse(line)); - }); + const c = DOMPurify.sanitize(marked.parse(content)); chat.history.push({ role, content, html: c, image, audio }); } else if (chat.history.length && chat.history[N].role === role) { @@ -2475,11 +2471,7 @@ document.addEventListener("alpine:init", () => { chat.history[N].audio = [...(chat.history[N].audio || []), ...audio]; } } else { - let c = ""; - const lines = content.split("\n"); - lines.forEach((line) => { - c += DOMPurify.sanitize(marked.parse(line)); - }); + const c = DOMPurify.sanitize(marked.parse(content)); chat.history.push({ role, content, diff --git a/core/http/static/general.css b/core/http/static/general.css index f0de5397a..92a57e01f 100644 --- a/core/http/static/general.css +++ b/core/http/static/general.css @@ -104,3 +104,97 @@ li:last-child { scrollbar-width: thin; scrollbar-color: var(--color-bg-secondary) var(--color-bg-primary); } + +/* Chat message markdown content styles */ +#messages pre { + background-color: var(--color-bg-primary); + border: 1px solid var(--color-border-subtle, rgba(255,255,255,0.1)); + border-radius: 0.5rem; + padding: 1rem; + overflow-x: auto; + max-width: 100%; + margin: 0.5rem 0; + white-space: pre; +} + +#messages pre code { + background: transparent; + padding: 0; + white-space: pre; + word-wrap: normal; + overflow-wrap: normal; +} + +#messages code:not(pre code) { + background-color: var(--color-bg-primary); + padding: 0.2em 0.4em; + border-radius: 3px; + font-size: 0.875em; +} + +#messages table { + width: 100%; + border-collapse: collapse; + margin: 0.5rem 0; + display: block; + overflow-x: auto; +} + +#messages th, +#messages td { + border: 1px solid var(--color-border-subtle, rgba(255,255,255,0.1)); + padding: 0.5rem; + text-align: left; +} + +#messages th { + background-color: var(--color-bg-secondary); +} + +#messages blockquote { + border-left: 4px solid var(--color-primary); + padding-left: 1rem; + margin: 0.5rem 0; + color: var(--color-text-secondary); +} + +#messages h1, #messages h2, #messages h3, #messages h4, #messages h5, #messages h6 { + margin-top: 1rem; + margin-bottom: 0.5rem; + font-weight: 600; + line-height: 1.25; +} + +#messages h1 { font-size: 1.5rem; } +#messages h2 { font-size: 1.25rem; } +#messages h3 { font-size: 1.125rem; } +#messages h4 { font-size: 1rem; } + +#messages p { + margin: 0.5rem 0; +} + +#messages ul, #messages ol { + margin: 0.5rem 0; + padding-left: 1.5rem; +} + +#messages hr { + border: none; + border-top: 1px solid var(--color-border-subtle, rgba(255,255,255,0.1)); + margin: 1rem 0; +} + +/* Mobile responsiveness for chat */ +@media (max-width: 768px) { + #messages { + max-width: 100%; + padding-left: 0.5rem; + padding-right: 0.5rem; + } + + #messages pre { + max-width: calc(100vw - 3rem); + font-size: 0.8rem; + } +} diff --git a/core/http/views/chat.html b/core/http/views/chat.html index 6c064977c..2678fe2b9 100644 --- a/core/http/views/chat.html +++ b/core/http/views/chat.html @@ -324,17 +324,11 @@ SOFTWARE. c = DOMPurify.sanitize('
' + formatted + '
'); } catch (e) { // If not JSON, treat as markdown - const lines = content.split("\n"); - lines.forEach((line) => { - c += DOMPurify.sanitize(marked.parse(line)); - }); + c = DOMPurify.sanitize(marked.parse(content)); } } else { // For thinking and reasoning, format as markdown - const lines = content.split("\n"); - lines.forEach((line) => { - c += DOMPurify.sanitize(marked.parse(line)); - }); + c = DOMPurify.sanitize(marked.parse(content)); } // Set expanded state: thinking and reasoning are expanded by default in non-MCP mode, collapsed in MCP mode // tool_call and tool_result are always collapsed by default @@ -366,11 +360,7 @@ SOFTWARE. chat.history[N].model = messageModel; } } else { - let c = ""; - const lines = content.split("\n"); - lines.forEach((line) => { - c += DOMPurify.sanitize(marked.parse(line)); - }); + const c = DOMPurify.sanitize(marked.parse(content)); chat.history.push({ role, content, @@ -1332,7 +1322,7 @@ SOFTWARE.
-
+