Skip to content

Commit 4376622

Browse files
committed
implements own markdown-component; replace links with custom component
1 parent e6ce8a0 commit 4376622

12 files changed

+295
-200
lines changed

frontend/src/components/ChatMessage.vue

Lines changed: 6 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<template v-if="isUserMessage">
33
<v-row class="justify-end pa-2 mb-0 mt-1 mx-1 ml-15">
44
<v-sheet color="green-accent-2" class="pa-2" rounded>
5-
<vue-markdown :source="textMessage" :options="options" />
5+
<Markdown :content="textMessage" />
66

77
<!-- at the moment, only user messages can have attachments -->
88
<template v-for="attachmentMeta of attachmentsMeta" :key="attachmentMeta.Path">
@@ -73,7 +73,7 @@
7373
<v-row class="pa-2 mb-0 mt-1 mx-1" v-if="textMessage">
7474
<v-col>
7575
<v-sheet class="pa-2" rounded>
76-
<vue-markdown :source="textMessage" :options="options" />
76+
<Markdown :content="textMessage" />
7777
<ChatMessageActions @toggleVisibility="onToggleVisibility" :hide-edit="hideEdit" @onEdit="onEdit" />
7878
</v-sheet>
7979
</v-col>
@@ -82,7 +82,7 @@
8282
<template v-else>
8383
<v-row class="pa-2 mb-0 mt-1 mx-1 mr-15">
8484
<v-sheet color="grey-lighten-2" class="pa-2" rounded>
85-
<vue-markdown :source="textMessage" :options="options" />
85+
<Markdown :content="textMessage" />
8686
<small class="d-flex justify-space-between align-center">
8787
<ChatMessageActions @toggleVisibility="onToggleVisibility" :hide-edit="hideEdit" @on-edit="onEdit" />
8888
<template v-if="consumption">
@@ -102,18 +102,13 @@
102102

103103
<script lang="ts">
104104
import { defineComponent, PropType } from 'vue'
105-
import VueMarkdown from 'vue-markdown-render'
106105
107106
import { GetAssetMeta } from '../../wailsjs/go/controller/Controller'
108107
import { controller } from '../../wailsjs/go/models.ts'
109108
import { PathSeparator } from '../common/platform.ts'
110109
import AssetMeta = controller.AssetMeta
111110
import LLMMessageContentPart = controller.LLMMessageContentPart
112111
import LLMMessageCall = controller.LLMMessageCall
113-
import hljs from 'highlight.js'
114-
import { type Options as MarkdownItOptions } from 'markdown-it'
115-
import { UseCodeStyle } from './code-style.ts'
116-
import { ClipboardSetText } from '../../wailsjs/runtime'
117112
import GeneralToolCall from './toolcall/GeneralToolCall.vue'
118113
import BuiltinToolCallFileCreation from './toolcall/BuiltinToolCallFileCreation.vue'
119114
import BuiltinToolCallCommandExecution from './toolcall/BuiltinToolCallCommandExecution.vue'
@@ -136,6 +131,7 @@ import { useConfigStore } from '../store/config.ts'
136131
import McpToolCall from './toolcall/McpToolCall.vue'
137132
import { HistoryEntryConsumption } from '../store/history.ts'
138133
import Consumption from './Consumption.vue'
134+
import Markdown from './Markdown.vue'
139135
140136
export enum Role {
141137
System = 'system',
@@ -153,6 +149,7 @@ export enum ContentType {
153149
export default defineComponent({
154150
name: 'ChatMessage',
155151
components: {
152+
Markdown,
156153
Consumption,
157154
McpToolCall,
158155
ChatMessageActions,
@@ -172,7 +169,6 @@ export default defineComponent({
172169
GeneralToolCall,
173170
BuiltinToolCallCommandExecution,
174171
BuiltinToolCallFileCreation,
175-
VueMarkdown,
176172
},
177173
emits: ['toggleVisibility', 'onEdit'],
178174
props: {
@@ -200,17 +196,6 @@ export default defineComponent({
200196
},
201197
data() {
202198
return {
203-
options: {
204-
highlight: (code: string, language: string) => {
205-
if (language && hljs.getLanguage(language)) {
206-
try {
207-
const result = hljs.highlight(code, { language })
208-
return result.value
209-
} catch (__) {}
210-
}
211-
return '' // use external default escaping
212-
},
213-
} as MarkdownItOptions,
214199
attachmentsMeta: [] as AssetMeta[],
215200
showConsumption: false,
216201
}
@@ -249,39 +234,6 @@ export default defineComponent({
249234
},
250235
},
251236
methods: {
252-
enrichCopyButtons() {
253-
const codeBlocks = document.querySelectorAll('pre:not(.code-container pre)').values()
254-
for (const pre of codeBlocks) {
255-
const div = document.createElement('div')
256-
div.className = 'code-container'
257-
258-
const button = document.createElement('button')
259-
button.className = 'copy-button mdi-clipboard-text-outline mdi v-icon notranslate v-icon--size-small'
260-
button.addEventListener('click', this.onCopyButtonClicked)
261-
262-
div.appendChild(button)
263-
div.appendChild(pre.cloneNode(true))
264-
pre.replaceWith(div)
265-
}
266-
},
267-
onCopyButtonClicked(event: MouseEvent) {
268-
const preElement = (event.target as HTMLButtonElement)?.nextElementSibling as HTMLElement
269-
if (preElement && preElement.tagName === 'PRE') {
270-
let code = preElement.innerText
271-
const newlineCount = (code.match(/\n/g) || []).length
272-
if (newlineCount === 1) {
273-
//prevent that shell-code-statements will be executed directly
274-
code = code.trim()
275-
}
276-
277-
ClipboardSetText(code).then(() => {
278-
preElement.classList.add('copied')
279-
setTimeout(() => {
280-
preElement.classList.remove('copied')
281-
}, 1000)
282-
})
283-
}
284-
},
285237
fileName(asset: AssetMeta) {
286238
return asset.Path.split(PathSeparator).pop() || ''
287239
},
@@ -296,9 +248,6 @@ export default defineComponent({
296248
},
297249
},
298250
watch: {
299-
textMessage() {
300-
this.$nextTick(() => this.enrichCopyButtons())
301-
},
302251
attachments: {
303252
async handler() {
304253
const promises = this.attachments.map((path) => GetAssetMeta(path))
@@ -311,99 +260,8 @@ export default defineComponent({
311260
immediate: true,
312261
},
313262
},
314-
mounted() {
315-
UseCodeStyle(this.profile.UI.CodeStyle)
316-
317-
this.$nextTick(() => this.enrichCopyButtons())
318-
},
319263
})
320264
</script>
321265

322-
<style>
323-
pre code {
324-
background-color: #f5f5f5;
325-
border: 1px solid #ccc;
326-
margin: 0.5em 0;
327-
padding: 0.5em 2em 0.5em 1em;
328-
border-radius: 5px;
329-
display: block;
330-
overflow-x: auto;
331-
position: relative;
332-
}
333-
334-
/* blue block when hover over code-blocks */
335-
pre code::before {
336-
content: '';
337-
position: absolute;
338-
top: 0;
339-
left: 0;
340-
width: 0;
341-
height: 100%;
342-
background-color: #007bff;
343-
transition: width 0.3s;
344-
}
345-
346-
pre code:hover::before {
347-
width: 5px;
348-
}
349-
350-
/* Add styles for the copy button */
351-
352-
div.code-container {
353-
position: relative;
354-
}
355-
356-
.copy-button {
357-
position: absolute;
358-
right: 1px;
359-
padding-top: 1em;
360-
padding-right: 0.5em;
361-
z-index: 1;
362-
float: right;
363-
}
364-
365-
pre.copied code {
366-
border: 2px solid #4db6ac;
367-
border-radius: 5px;
368-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5); /* Add elevation effect */
369-
}
370-
371-
/* Inline code blocks inside text (not in headers) */
372-
code:not(pre code):not(h1 code):not(h2 code):not(h3 code):not(h4 code):not(h5 code):not(h6 code) {
373-
background-color: #f5f5f5;
374-
border: 1px solid #ccc;
375-
padding: 2px 4px;
376-
border-radius: 3px;
377-
}
378-
379-
/* Quote-Blocks */
380-
381-
blockquote {
382-
border-left: 5px solid #ccc;
383-
margin: 0.5em 0;
384-
padding: 0.5em 1em;
385-
color: #555;
386-
background: none;
387-
border-radius: 0;
388-
}
389-
390-
blockquote:hover {
391-
border-color: #007bff;
392-
}
393-
394-
/* Header Padding increase */
395-
h1,
396-
h2,
397-
h3,
398-
h4,
399-
h5,
400-
h6 {
401-
padding-top: 1em;
402-
}
403-
404-
/* make list items visible */
405-
ol,
406-
ul li {
407-
margin-left: 2em;
408-
}
266+
<style scoped>
409267
</style>

0 commit comments

Comments
 (0)