feat: 功能3 - Markdown 渲染和代码高亮 (v0.9.8)
- 添加 MarkdownMessage.vue 组件 - 集成 markdown-it 库 - 集成 highlight.js 代码高亮 - 支持标题/列表/代码块/表格等 - ChatWindow 使用 Markdown 渲染 - 添加 .gitignore 忽略 node_modules
This commit is contained in:
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,11 +1,2 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.pytest_cache/
|
||||
*.db
|
||||
*.sqlite
|
||||
.env
|
||||
venv/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
venv/
|
||||
frontend/node_modules/
|
||||
frontend/package-lock.json
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
"typecheck": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.0",
|
||||
"vue-router": "^4.2.0",
|
||||
"@highlightjs/vue-plugin": "^2.1.0",
|
||||
"axios": "^1.6.0",
|
||||
"date-fns": "^3.0.0",
|
||||
"highlight.js": "^11.11.1",
|
||||
"markdown-it": "^14.1.1",
|
||||
"pinia": "^2.1.0",
|
||||
"socket.io-client": "^4.7.0",
|
||||
"axios": "^1.6.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"highlight.js": "^11.9.0",
|
||||
"@highlightjs/vue-plugin": "^2.1.0",
|
||||
"date-fns": "^3.0.0"
|
||||
"vue": "^3.4.0",
|
||||
"vue-router": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
import { useChatStore } from '@/stores/chat'
|
||||
import MarkdownMessage from '@/components/chat/MarkdownMessage.vue'
|
||||
|
||||
const chatStore = useChatStore()
|
||||
const messagesContainer = ref<HTMLElement | null>(null)
|
||||
@@ -64,7 +65,7 @@ function isOwnMessage(msg: any): boolean {
|
||||
<span class="message-time">{{ formatTime(message.created_at) }}</span>
|
||||
</div>
|
||||
<div class="message-bubble">
|
||||
{{ message.content }}
|
||||
<MarkdownMessage :content="message.content" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
119
frontend/src/components/chat/MarkdownMessage.vue
Normal file
119
frontend/src/components/chat/MarkdownMessage.vue
Normal file
@@ -0,0 +1,119 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import hljs from 'highlight.js'
|
||||
import 'highlight.js/styles/github-dark.css'
|
||||
|
||||
const props = defineProps<{
|
||||
content: string
|
||||
}>()
|
||||
|
||||
const md = new MarkdownIt({
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value
|
||||
} catch (__) {}
|
||||
}
|
||||
return hljs.highlightAuto(str).value
|
||||
},
|
||||
linkify: true,
|
||||
breaks: true
|
||||
})
|
||||
|
||||
const renderedContent = computed(() => {
|
||||
return md.render(props.content)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="markdown-body" v-html="renderedContent" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.markdown-body {
|
||||
color: inherit;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.markdown-body :deep(h1),
|
||||
.markdown-body :deep(h2),
|
||||
.markdown-body :deep(h3),
|
||||
.markdown-body :deep(h4),
|
||||
.markdown-body :deep(h5),
|
||||
.markdown-body :deep(h6) {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body :deep(h1) { font-size: 1.5em; }
|
||||
.markdown-body :deep(h2) { font-size: 1.3em; }
|
||||
.markdown-body :deep(h3) { font-size: 1.1em; }
|
||||
.markdown-body :deep(h4) { font-size: 1em; }
|
||||
|
||||
.markdown-body :deep(p) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.markdown-body :deep(ul),
|
||||
.markdown-body :deep(ol) {
|
||||
margin-bottom: 12px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.markdown-body :deep(li) {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.markdown-body :deep(pre) {
|
||||
background: #1e1e1e;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.markdown-body :deep(code) {
|
||||
font-family: 'Fira Code', 'Monaco', 'Consolas', monospace;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.markdown-body :deep(:not(pre) > code) {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.markdown-body :deep(a) {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body :deep(a:hover) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.markdown-body :deep(blockquote) {
|
||||
border-left: 4px solid var(--primary-color);
|
||||
padding-left: 16px;
|
||||
margin-left: 0;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.markdown-body :deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.markdown-body :deep(th),
|
||||
.markdown-body :deep(td) {
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.markdown-body :deep(th) {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user