Commit 607b73b6 authored by tyyin lan's avatar tyyin lan

feat: 代码执行块渲染

parent 54aec989
......@@ -8,7 +8,7 @@
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_4711453_6yk5447mfvj.css" />
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_4711453_f6b3gmjqw8q.css" />
<link
rel="preload"
href="https://gsst-poe-sit.gz.bcebos.com/front/SourceHanSansCN-Medium.otf"
......
......@@ -29,7 +29,6 @@
"dompurify": "^3.2.0",
"echarts": "^5.5.1",
"file-saver": "^2.0.5",
"github-markdown-css": "^5.7.0",
"highlight.js": "^11.10.0",
"howler": "^2.2.4",
"katex": "^0.16.21",
......
This diff is collapsed.
......@@ -7,7 +7,7 @@ import { throttle, debounce } from 'lodash-es'
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
import 'highlight.js/styles/panda-syntax-light.css'
import 'github-markdown-css'
import './style/github-markdown.css'
import markedKatex, { MarkedKatexOptions } from 'marked-katex-extension'
import { copyToClip } from '@/utils/copy'
import { useI18n } from 'vue-i18n'
......@@ -16,12 +16,14 @@ interface Props {
rawTextContent: string
fontSize?: number | string
color?: string
darkTheme?: boolean
}
const props = withDefaults(defineProps<Props>(), {
rawTextContent: '',
fontSize: '14px',
color: '#333',
darkTheme: false,
})
const katexOptions: MarkedKatexOptions = {
......@@ -39,14 +41,23 @@ const marked = new Marked()
.use(
markedHighlight({
emptyLangClass: 'hljs',
langPrefix: 'hljs language-',
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>${language}</span><span class="code-copy-btn iconfont icon-copy"></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><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>'
)
},
}),
)
......@@ -96,6 +107,7 @@ const codeCopyBtnEventBind = debounce(
() => {
if (markdownRenderContainerRef.value) {
const codeCopyBtnElList = markdownRenderContainerRef.value.getElementsByClassName('code-copy-btn')
const foldBtnElList = markdownRenderContainerRef.value.getElementsByClassName('fold-btn')
btnEventController.abort()
btnEventController = new AbortController()
......@@ -105,7 +117,7 @@ const codeCopyBtnEventBind = debounce(
elItem.addEventListener(
'click',
() => {
const code = elItem.parentElement?.nextElementSibling?.firstChild?.textContent
const code = elItem.parentElement?.parentElement?.nextElementSibling?.firstChild?.firstChild?.textContent
if (code) {
copyToClip(code).then(() => {
......@@ -116,6 +128,23 @@ const codeCopyBtnEventBind = debounce(
{ signal: btnEventController.signal },
)
})
/* 遍历 */
;[...foldBtnElList].forEach((elItem) => {
elItem.addEventListener(
'click',
() => {
elItem && elItem.classList.toggle('folding')
const codeRenderWrapperEl = elItem.parentElement?.parentElement?.nextElementSibling
if (codeRenderWrapperEl) {
codeRenderWrapperEl?.classList.toggle('folding')
}
},
{ signal: btnEventController.signal },
)
})
}
},
1000,
......@@ -143,7 +172,12 @@ defineExpose({
<template>
<div ref="markdownRenderContainerRef" class="markdown-render-container">
<article class="markdown-body markdown-render-inner" :style="articleContainerStyle" v-html="renderTextContent" />
<article
class="markdown-body markdown-render-inner"
data-theme="dark"
:style="articleContainerStyle"
v-html="renderTextContent"
/>
</div>
</template>
......@@ -169,11 +203,31 @@ defineExpose({
.code-operation-bar-container {
display: flex;
justify-content: space-between;
padding: 10px 16px;
padding: 8px 16px;
color: v-bind('props.darkTheme ? "#fff" : "#ccc"');
user-select: none;
background-color: #f1f1f1;
background-color: v-bind('props.darkTheme ? "#484a4b" : "#f1f1f1"');
.code-copy-btn {
.language {
display: flex;
align-items: center;
justify-content: center;
}
.fold-btn {
display: inline-block;
margin-left: 16px;
transition: transform ease-in-out 0.2s !important;
transform: rotate(270deg);
&.folding {
transform: rotate(90deg);
}
}
.code-copy-btn,
.fold-btn {
font-size: 14px;
cursor: pointer;
transition: color ease-in-out 0.3s;
......@@ -184,10 +238,32 @@ defineExpose({
}
.code-render-inner {
padding: 10px 16px 0;
padding: 10px 16px;
margin: 0;
overflow-x: auto;
}
.code-render-wrapper {
height: fit-content;
transition: all 0.3s linear;
&.folding {
height: 0;
overflow: hidden;
}
}
}
}
:deep(.markdown-body) {
&[data-theme='dark'] {
/* stylelint-disable-next-line custom-property-pattern */
--bgColor-muted: #1d1e1f;
}
& .code-container-wrapper {
display: inline-flex;
flex-direction: column;
}
}
......
This diff is collapsed.
......@@ -156,7 +156,7 @@ const handleContentEdit = throttle(
class="py-[10px] pr-[14px] text-end"
>
<i
class="iconfont icon-copy1 hover:text-theme-color mr-[14px] transform cursor-pointer text-[14px]"
class="iconfont icon-fuzhi hover:text-theme-color mr-[14px] transform cursor-pointer text-[14px]"
@click="handleContentCopy"
></i>
<i
......
......@@ -44,13 +44,20 @@ const isShowMessageList = ref(false)
const isAgentInitLoading = ref(true)
const currentFetchEventSourceController = ref<AbortController | null>(null)
// messageList.value.set('1', {
// role: 'user',
// agentId: 'b058f1baedd04af983ca00775368bb8c',
// content: '请推荐一些适合初学者的编程学习资源。',
// timestamp: 1726654820427,
// isAnswerLoading: true,
// })
setTimeout(() => {
messageList.value.set('1', {
role: 'user',
agentId: 'b058f1baedd04af983ca00775368bb8c',
content: '请推荐一些适合初学者的编程学习资源。',
timestamp: 1726654820427,
isAnswerLoading: false,
avatar: 'http://localhost:8848/fe/src/assets/images/home/agent-avatar.png',
name: '1234',
reasoningContent: '1324',
imageUrl: '',
pluginName: '',
})
}, 60)
// messageList.value.set('2', {
// role: 'assistant',
// agentId: 'b058f1baedd04af983ca00775368bb8c',
......
......@@ -263,7 +263,7 @@ const handleContentCopy = throttle(
class="pr-[13px] text-end"
>
<i
class="iconfont icon-copy1 hover:text-theme-color mr-[14px] transform cursor-pointer text-[14px] text-[#3d3d3d]"
class="iconfont icon-fuzhi hover:text-theme-color mr-[14px] transform cursor-pointer text-[14px] text-[#3d3d3d]"
@click="handleContentCopy"
/>
<i
......
......@@ -223,7 +223,7 @@ async function handleExportAPIChannelPointUsageData() {
<template #trigger>
<i
v-show="apiProfileInfo.apiKey"
class="iconfont icon-copy text-gray-font-color hover:text-theme-color cursor-pointer leading-4"
class="iconfont icon-fuzhi text-gray-font-color hover:text-theme-color cursor-pointer leading-4"
@click="handleCopyText(apiProfileInfo.apiKey)"
/>
</template>
......@@ -245,7 +245,7 @@ async function handleExportAPIChannelPointUsageData() {
<template #trigger>
<i
v-show="apiProfileInfo.apiSecret"
class="iconfont icon-copy text-gray-font-color hover:text-theme-color cursor-pointer leading-4"
class="iconfont icon-fuzhi text-gray-font-color hover:text-theme-color cursor-pointer leading-4"
@click="handleCopyText(apiProfileInfo.apiSecret)"
/>
</template>
......
......@@ -291,7 +291,7 @@ const handleContentCopy = throttle(
class="py-[10px] pr-[14px] text-end"
>
<i
class="iconfont icon-copy1 hover:text-theme-color mr-[14px] transform cursor-pointer text-[14px]"
class="iconfont icon-fuzhi hover:text-theme-color mr-[14px] transform cursor-pointer text-[14px]"
@click="handleContentCopy"
/>
<i
......
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