diff --git a/backend/src/app_mixins/chat.py b/backend/src/app_mixins/chat.py index def0d48..c9f7fbe 100644 --- a/backend/src/app_mixins/chat.py +++ b/backend/src/app_mixins/chat.py @@ -13,6 +13,7 @@ def message_json(msg): "sender": msg.sender, "kind": msg.kind, "subkind": msg.subkind, + "format": msg.format, "content": msg.content, "threadId": msg.thread_id, } diff --git a/backend/src/server/websocket.py b/backend/src/server/websocket.py index d3e1d3f..0887453 100644 --- a/backend/src/server/websocket.py +++ b/backend/src/server/websocket.py @@ -276,7 +276,7 @@ def register(server, app, auth_manager): elif action == "update-chat-message": message = await app.update_chat_message( message_id=body['messageId'], - content=body['content'], + content=body.get('content'), kind=body.get('kind'), subkind=body.get('subkind'), format=body.get('format'), diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index 248bfba..af0c2dc 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -94,4 +94,14 @@ input:disabled, textarea:disabled, select:disabled { .with-sidebar-expanded .when-sidebar-collapsed { display: none; +} + +/* Content */ +h1, h2, h3, h4, h5, h6 { + margin: 1em 0 0.5em; + font-weight: bold; +} + +p, ul, il { + margin: 0.5em 0; } \ No newline at end of file diff --git a/frontend/src/chat.js b/frontend/src/chat.js index a696d07..f3665e5 100644 --- a/frontend/src/chat.js +++ b/frontend/src/chat.js @@ -545,6 +545,33 @@ export class ChatSession { this.creatingThread.value = Boolean(fork); } + // Sets the render format of a message ("markdown", or "" for plain text). + // Omit `content` so the backend leaves the existing content untouched. + setMessageFormat (message, format) { + backend.sendAction("update-chat-message", { + messageId: message.id, format, + }).then(response => { + if (response && response.error) { + ui.alert("Error updating message format: " + response.error); + } + }); + + // No update event is broadcast (matching the content-edit path above), so + // patch the source message and rebuild the entries locally. Other sessions + // and stale views won't reflect this until reload — which is correct, since + // the format is persisted. If we ever broadcast edits, flip this to rely on + // the incoming update instead. + let thread = this.getThread(message.threadId); + let existing = thread.messages.find(msg => msg.id == message.id); + if (existing) { + existing.format = format; + } else { + console.error("Can't set format locally?", {messageId: message.id, thread}); + } + + this.computeChatEntries(); + } + // Adds a bulk of messages to the message list, in their correct // chronological position and replacing duplicates addMessageBulk (messages) { diff --git a/frontend/src/components/Message.vue b/frontend/src/components/Message.vue index 9511de7..683ce3f 100644 --- a/frontend/src/components/Message.vue +++ b/frontend/src/components/Message.vue @@ -4,13 +4,17 @@ import { marked } from "marked"; import * as backend from '../backend'; marked.use({ renderer: { - code (code, infostring, escaped) { - let langElem = infostring ? - `