Commit a9e7f87d authored by tyyin lan's avatar tyyin lan

fix(首页): 写作编辑器功能无法携带格式

parent ecbc18b2
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, ref, useTemplateRef, watchEffect } from 'vue' import { computed, nextTick, ref, useTemplateRef, watchEffect } from 'vue'
import { Marked } from 'marked'
import { markedHighlight } from 'marked-highlight'
import 'katex/dist/katex.min.css' import 'katex/dist/katex.min.css'
import { throttle, debounce } from 'lodash-es' import { throttle, debounce } from 'lodash-es'
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
// import 'highlight.js/styles/panda-syntax-light.css' // import 'highlight.js/styles/panda-syntax-light.css'
import 'highlight.js/styles/atom-one-dark.min.css' import 'highlight.js/styles/atom-one-dark.min.css'
import './style/github-markdown.css' import './style/github-markdown.css'
import markedKatex, { MarkedKatexOptions } from 'marked-katex-extension'
import { copyToClip } from '@/utils/copy' import { copyToClip } from '@/utils/copy'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { createMarkedInst } from './utils/markdown-parser'
interface Props { interface Props {
rawTextContent: string rawTextContent: string
...@@ -27,62 +23,10 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -27,62 +23,10 @@ const props = withDefaults(defineProps<Props>(), {
darkTheme: true, darkTheme: true,
}) })
const katexOptions: MarkedKatexOptions = {
throwOnError: false,
displayMode: true,
nonStandard: true,
output: 'html',
}
const markdownRenderContainerRef = useTemplateRef<HTMLDivElement>('markdownRenderContainerRef') const markdownRenderContainerRef = useTemplateRef<HTMLDivElement>('markdownRenderContainerRef')
const { t } = useI18n() const { t } = useI18n()
const marked = new Marked() const markedInst = createMarkedInst()
.use({ gfm: true, async: true, breaks: true })
.use(
markedHighlight({
emptyLangClass: 'hljs',
langPrefix: 'hljs code-container-wrapper language-',
highlight(code, lang, _info) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext'
// return hljs.highlight(code, { language }).value
const str = hljs.highlight(code, { language }).value
// return `<div class="code-render-container"><div class="code-operation-bar-container"><span class="language">${language}</span><span><span class="code-copy-btn iconfont icon-fuzhi"></span><span class="fold-btn iconfont icon-left"></span></span></div><pre class="code-render-inner"><code>${str}</code></pre></div>`
return (
'<div class="code-render-container">' +
'<div class="code-operation-bar-container">' +
`<span class="language">${language}</span><span><span class="code-copy-btn iconfont icon-fuzhi"></span><span class="fold-btn iconfont icon-left"></span></span>` +
'</div>' +
`<div class="code-render-wrapper"><pre class="code-render-inner"><code>${str}</code></pre></div>` +
'</div>'
)
},
}),
)
.use(markedKatex(katexOptions))
.use({
hooks: {
preprocess(markdown: string) {
/**
* 1. 将 \(...\) 和 \\(...\\) 转为 $...$ 以支持行内公式
* 2. 将 \[...\] 和 \\[...\\] 转为 $$...$$ 以支持块级公式
*/
const katexTextReplace = markdown
.replace(/\\\\\(|\\\\\)|\\\(|\\\)/g, '$')
.replace(/\\\\\[|\\\\\]|\\\[|\\\]/g, '$$$$')
return katexTextReplace
},
postprocess(html: string) {
return DOMPurify.sanitize(html)
},
},
})
let btnEventController = new AbortController() let btnEventController = new AbortController()
const renderTextContent = ref('') const renderTextContent = ref('')
...@@ -96,7 +40,7 @@ const articleContainerStyle = computed(() => { ...@@ -96,7 +40,7 @@ const articleContainerStyle = computed(() => {
const textContentParser = throttle( const textContentParser = throttle(
(text: string) => { (text: string) => {
;(marked.parse(text) as Promise<string>).then((res) => { ;(markedInst.parse(text) as Promise<string>).then((res) => {
renderTextContent.value = res renderTextContent.value = res
}) })
}, },
......
import { Marked } from 'marked'
import { markedHighlight } from 'marked-highlight'
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
import markedKatex, { type MarkedKatexOptions } from 'marked-katex-extension'
const katexOptions: MarkedKatexOptions = {
throwOnError: false,
displayMode: true,
nonStandard: true,
output: 'html',
}
export function createMarkedInst() {
return new Marked()
.use({ gfm: true, async: true, breaks: true })
.use(
markedHighlight({
emptyLangClass: 'hljs',
langPrefix: 'hljs code-container-wrapper language-',
highlight(code, lang, _info) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext'
// return hljs.highlight(code, { language }).value
const str = hljs.highlight(code, { language }).value
// return `<div class="code-render-container"><div class="code-operation-bar-container"><span class="language">${language}</span><span><span class="code-copy-btn iconfont icon-fuzhi"></span><span class="fold-btn iconfont icon-left"></span></span></div><pre class="code-render-inner"><code>${str}</code></pre></div>`
return (
'<div class="code-render-container">' +
'<div class="code-operation-bar-container">' +
`<span class="language">${language}</span><span><span class="code-copy-btn iconfont icon-fuzhi"></span><span class="fold-btn iconfont icon-left"></span></span>` +
'</div>' +
`<div class="code-render-wrapper"><pre class="code-render-inner"><code>${str}</code></pre></div>` +
'</div>'
)
},
}),
)
.use(markedKatex(katexOptions))
.use({
hooks: {
preprocess(markdown: string) {
/**
* 1. 将 \(...\) 和 \\(...\\) 转为 $...$ 以支持行内公式
* 2. 将 \[...\] 和 \\[...\\] 转为 $$...$$ 以支持块级公式
*/
const katexTextReplace = markdown
.replace(/\\\\\(|\\\\\)|\\\(|\\\)/g, '$')
.replace(/\\\\\[|\\\\\]|\\\[|\\\]/g, '$$$$')
return katexTextReplace
},
postprocess(html: string) {
return DOMPurify.sanitize(html)
},
},
})
}
export function markdownParser(markdown: string) {
return createMarkedInst().parse(markdown)
}
...@@ -17,6 +17,7 @@ import { NAvatar, NEllipsis } from 'naive-ui' ...@@ -17,6 +17,7 @@ import { NAvatar, NEllipsis } from 'naive-ui'
import type { SelectRenderLabel, SelectRenderTag } from 'naive-ui' import type { SelectRenderLabel, SelectRenderTag } from 'naive-ui'
import RichTextInputBox from './rich-text-input-box/index.vue' import RichTextInputBox from './rich-text-input-box/index.vue'
import type { WorkModeType } from '@/views/home/components/rich-text-input-box/types/index' import type { WorkModeType } from '@/views/home/components/rich-text-input-box/types/index'
import { markdownParser } from '@/components/markdown-render/utils/markdown-parser'
interface Props { interface Props {
currentSessionId: string currentSessionId: string
...@@ -240,7 +241,7 @@ function questionSubmit(question: string) { ...@@ -240,7 +241,7 @@ function questionSubmit(question: string) {
} }
}, },
onend: () => { onend: () => {
setTimeout(() => { setTimeout(async () => {
emit('updateSpecifyMessageItem', currentLatestMessageItemKeyMap.value.get('assistant')!, { emit('updateSpecifyMessageItem', currentLatestMessageItemKeyMap.value.get('assistant')!, {
isAnswerLoading: false, isAnswerLoading: false,
}) })
...@@ -250,7 +251,7 @@ function questionSubmit(question: string) { ...@@ -250,7 +251,7 @@ function questionSubmit(question: string) {
if (editorModeEnable.value) { if (editorModeEnable.value) {
editorDrawerConfig.value = { editorDrawerConfig.value = {
isShow: true, isShow: true,
content: messageContent, content: await markdownParser(messageContent),
} }
} }
}, 100) }, 100)
......
...@@ -45,16 +45,17 @@ class TemplateInputPromptBlot extends Embed { ...@@ -45,16 +45,17 @@ class TemplateInputPromptBlot extends Embed {
// 'min-w-full', // 'min-w-full',
// 'left-0', // 'left-0',
// 'right-0', // 'right-0',
'focus:outline-none',
'px-[6px]', 'px-[6px]',
// 'text-[#0057ff]', // 'text-[#0057ff]',
'whitespace-pre-wrap', 'whitespace-pre-wrap',
'break-all', 'break-all',
// 'outline-none',
) )
inputContainerEl.style.left = '0' inputContainerEl.style.left = '0'
inputContainerEl.style.right = '0' inputContainerEl.style.right = '0'
inputContainerEl.style.color = '#000dff' inputContainerEl.style.color = '#000dff'
inputContainerEl.style.outlineStyle = 'none'
inputContainerEl.textContent = '' inputContainerEl.textContent = ''
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment