This repository has been archived on 2025-10-29. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
FPGA_WebLab/src/components/MarkdownRenderer.vue
2025-05-20 10:15:42 +08:00

652 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue';
import { marked } from 'marked';
import hljs from 'highlight.js';
// 导入亮色主题样式
import 'highlight.js/styles/github.css'; // 亮色主题
// 导入主题存储
import { useThemeStore } from '@/stores/theme';
const props = defineProps({
content: {
type: String,
required: true
},
removeFirstH1: {
type: Boolean,
default: false
}
});
// 使用主题存储
const themeStore = useThemeStore();
// 使用 isDarkTheme 函数来检查当前是否为暗色主题
const isDarkMode = computed(() => themeStore.isDarkTheme());
// 监听主题变化
watch(() => themeStore.currentTheme, () => {
// 主题变化时更新代码高亮样式
updateCodeBlocksTheme();
});
// 更新代码块主题样式
const updateCodeBlocksTheme = () => {
// 这个函数可以在需要时手动更新代码块的样式
// 由于我们使用CSS变量控制样式可能不需要特定实现
// 但如果需要,可以在这里添加额外逻辑
};
const renderedContent = computed(() => {
if (!props.content) return '<p>没有内容</p>';
let processedContent = props.content;
// 如果需要,移除第一个一级标题
if (props.removeFirstH1) {
const lines = processedContent.split('\n');
const firstH1Index = lines.findIndex(line => line.startsWith('# '));
if (firstH1Index !== -1) {
processedContent = lines.slice(firstH1Index + 1).join('\n');
}
}
// 创建自定义渲染器
const renderer = new marked.Renderer();
// 重写代码块渲染方法,添加语言信息
renderer.code = (code, incomingLanguage) => {
// 确保语言参数是字符串
const language = incomingLanguage || 'plaintext';
// 验证语言
const validLanguage = hljs.getLanguage(language) ? language : 'plaintext';
// 高亮代码
const highlightedCode = hljs.highlight(code, { language: validLanguage }).value;
// 添加语言标签到代码块
return `<pre class="hljs" data-language="${validLanguage}"><code class="language-${validLanguage}">${highlightedCode}</code></pre>`;
};
// 设置 marked 选项
marked.use({
renderer: renderer,
gfm: true,
breaks: true
});
return marked(processedContent);
});
// 页面挂载后,确保应用正确的主题样式
onMounted(() => {
updateCodeBlocksTheme();
});
</script>
<template>
<div class="markdown-content" :data-theme="themeStore.currentTheme" v-html="renderedContent"></div>
</template>
<style scoped>
.markdown-content {
color: hsl(var(--bc));
line-height: 1.6;
padding: 1rem 1.5rem;
max-width: 100%;
background-color: inherit; /* 继承父元素的背景色 */
height: 100%;
}
.markdown-content :deep(img) {
max-width: 60%;
height: auto;
display: block;
margin: 1rem auto;
border-radius: 0.5rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.12);
}
.markdown-content :deep(h1) {
margin-top: 2.5rem;
margin-bottom: 1.5rem;
color: hsl(var(--bc));
font-weight: 700;
font-size: 2.2rem;
line-height: 1.3;
padding-bottom: 0.7rem;
border-bottom: 2px solid hsl(var(--p) / 0.7);
text-shadow: 1px 1px 2px rgba(0,0,0,0.05);
}
.markdown-content :deep(h2) {
margin-top: 2rem;
margin-bottom: 1rem;
color: hsl(var(--bc));
font-weight: 600;
font-size: 1.7rem;
line-height: 1.4;
padding: 0.5rem 1rem;
border-left: 5px solid hsl(var(--p));
background: linear-gradient(to right, hsl(var(--b2) / 0.5), transparent);
border-radius: 0.3rem;
}
.markdown-content :deep(h3) {
margin-top: 1.8rem;
margin-bottom: 0.9rem;
color: hsl(var(--bc));
font-weight: 600;
font-size: 1.4rem;
line-height: 1.4;
padding-left: 1rem;
border-left: 3px solid hsl(var(--s));
padding-top: 0.3rem;
padding-bottom: 0.3rem;
}
.markdown-content :deep(h4),
.markdown-content :deep(h5),
.markdown-content :deep(h6) {
margin-top: 1.5rem;
margin-bottom: 0.7rem;
color: hsl(var(--bc));
font-weight: 600;
font-size: 1.2rem;
line-height: 1.5;
padding-left: 1.5rem;
position: relative;
}
.markdown-content :deep(h4::before),
.markdown-content :deep(h5::before),
.markdown-content :deep(h6::before) {
content: '▶';
color: hsl(var(--p) / 0.7);
position: absolute;
left: 0.2rem;
font-size: 0.9em;
}
.markdown-content :deep(p) {
text-indent: 2em;
margin: 1rem 0;
color: hsl(var(--bc) / 0.8);
line-height: 1.8;
}
.markdown-content :deep(ul),
.markdown-content :deep(ol) {
padding-left: 2.5em;
margin: 1.25rem 0;
color: hsl(var(--bc) / 0.8);
background-color: hsl(var(--b1) / 0.3);
border-radius: 0.5rem;
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-right: 1rem;
border-left: 3px solid hsl(var(--p) / 0.7);
}
.markdown-content :deep(li) {
margin: 0.5rem 0;
position: relative;
padding-left: 0.5rem;
}
.markdown-content :deep(ul ul),
.markdown-content :deep(ul ol),
.markdown-content :deep(ol ul),
.markdown-content :deep(ol ol) {
margin: 0.5rem 0 0.5rem 0.5rem;
padding-left: 1.5rem;
border-left: 2px solid hsl(var(--s) / 0.5);
background-color: transparent;
}
.markdown-content :deep(ul) {
list-style-type: disc;
}
.markdown-content :deep(ol) {
list-style-type: decimal;
}
.markdown-content :deep(ul ul) {
list-style-type: circle;
}
.markdown-content :deep(ul ul ul) {
list-style-type: square;
}
.markdown-content :deep(ul li::marker) {
color: hsl(var(--p));
}
.markdown-content :deep(ol li::marker) {
color: hsl(var(--s));
}
/* 代码块样式增强 - 响应主题 */
.markdown-content :deep(pre) {
background-color: var(--code-bg, hsl(var(--b2)));
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
border: 1px solid hsl(var(--b2));
margin: 1.5rem 0;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
position: relative;
color: var(--code-color, hsl(var(--bc)));
}
.markdown-content :deep(pre::before) {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, hsl(var(--p)), hsl(var(--s)));
border-radius: 0.5rem 0.5rem 0 0;
}
/* 代码语言标签 */
.markdown-content :deep(pre.hljs::after) {
content: attr(data-language);
position: absolute;
top: 0;
right: 0;
color: var(--code-label-color, hsl(var(--bc) / 0.7));
font-size: 0.75rem;
background-color: var(--code-label-bg, hsl(var(--b3)));
padding: 0.2rem 0.5rem;
border-radius: 0 0.3rem 0 0.3rem;
opacity: 0.8;
}
/* 内联代码样式 */
.markdown-content :deep(code) {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
background-color: var(--inline-code-bg, hsl(var(--b3) / 0.7));
padding: 0.2rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.9em;
color: var(--inline-code-color, hsl(var(--p)));
border: 1px solid hsl(var(--b2) / 0.5);
}
/* 确保代码块内的代码不受内联代码样式影响 */
.markdown-content :deep(pre code) {
background-color: transparent;
padding: 0;
border: none;
color: inherit;
font-size: 0.95em;
line-height: 1.5;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
/* 为常见语言添加一些特殊的高亮效果 */
.markdown-content :deep(.hljs-keyword),
.markdown-content :deep(.hljs-tag),
.markdown-content :deep(.hljs-selector-tag) {
color: #cc99cd; /* 紫色,用于关键字 */
}
.markdown-content :deep(.hljs-string),
.markdown-content :deep(.hljs-regexp),
.markdown-content :deep(.hljs-template-tag) {
color: #7ec699; /* 绿色,用于字符串 */
}
.markdown-content :deep(.hljs-number),
.markdown-content :deep(.hljs-literal) {
color: #f08d49; /* 橙色,用于数字 */
}
.markdown-content :deep(.hljs-comment) {
color: #999999; /* 灰色,用于注释 */
font-style: italic;
}
.markdown-content :deep(.hljs-name),
.markdown-content :deep(.hljs-attribute),
.markdown-content :deep(.hljs-selector-id),
.markdown-content :deep(.hljs-selector-class) {
color: #e2777a; /* 红色用于HTML标签名和属性 */
}
.markdown-content :deep(.hljs-built_in),
.markdown-content :deep(.hljs-builtin-name) {
color: #6196cc; /* 蓝色,用于内置函数 */
}
.markdown-content :deep(.hljs-title),
.markdown-content :deep(.hljs-function) {
color: #f8c555; /* 金色,用于函数名和类名 */
}
.markdown-content :deep(table) {
border-collapse: separate;
border-spacing: 0;
width: 100%;
margin: 1.5rem 0;
background-color: hsl(var(--b1));
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
border: 1px solid hsl(var(--b2));
}
.markdown-content :deep(th),
.markdown-content :deep(td) {
border: 1px solid hsl(var(--b2));
padding: 0.75rem 1rem;
text-align: left;
}
.markdown-content :deep(th) {
background-color: hsl(var(--p) / 0.15);
font-weight: 600;
color: hsl(var(--bc));
border-bottom: 2px solid hsl(var(--p) / 0.5);
}
.markdown-content :deep(tr:nth-child(even)) {
background-color: hsl(var(--b2) / 0.3);
}
.markdown-content :deep(tr:hover) {
background-color: hsl(var(--b2) / 0.5);
}
.markdown-content :deep(td) {
color: hsl(var(--bc) / 0.8);
}
.markdown-content :deep(blockquote) {
margin: 1.5rem 0;
padding: 1rem 1.5rem;
border-left: 4px solid hsl(var(--p));
background-color: hsl(var(--b2) / 0.3);
color: hsl(var(--bc) / 0.9);
font-style: italic;
border-radius: 0 0.5rem 0.5rem 0;
box-shadow: 0 2px 5px rgba(0,0,0,0.03);
position: relative;
}
.markdown-content :deep(blockquote::before) {
content: '"';
font-size: 2rem;
color: hsl(var(--p) / 0.3);
position: absolute;
top: 0.5rem;
left: 0.5rem;
font-family: serif;
}
.markdown-content :deep(blockquote p) {
margin-top: 0.5rem;
}
.markdown-content :deep(hr) {
border: none;
border-top: 1px solid hsl(var(--b2));
margin: 1.5rem 0;
}
.markdown-content :deep(a) {
color: hsl(var(--p));
text-decoration: none;
transition: color 0.2s;
}
.markdown-content :deep(a:hover) {
color: hsl(var(--pf));
text-decoration: underline;
}
/* 亮色主题下的代码样式 */
:root[data-theme="winter"] .markdown-content :deep(.hljs),
.markdown-content[data-theme="winter"] :deep(.hljs),
[data-theme="winter"] .markdown-content :deep(.hljs) {
--code-bg: #f5f7ff;
--code-color: #333;
--inline-code-bg: #f0f2fa;
--inline-code-color: #d32f2f;
--code-label-bg: #e6e9f5;
--code-label-color: #666;
}
/* 亮色主题下的语法高亮 */
:root[data-theme="winter"] .markdown-content :deep(.hljs-keyword),
.markdown-content[data-theme="winter"] :deep(.hljs-keyword),
[data-theme="winter"] .markdown-content :deep(.hljs-keyword),
:root[data-theme="winter"] .markdown-content :deep(.hljs-tag),
.markdown-content[data-theme="winter"] :deep(.hljs-tag),
[data-theme="winter"] .markdown-content :deep(.hljs-tag),
:root[data-theme="winter"] .markdown-content :deep(.hljs-selector-tag),
.markdown-content[data-theme="winter"] :deep(.hljs-selector-tag),
[data-theme="winter"] .markdown-content :deep(.hljs-selector-tag) {
color: #8959a8; /* 紫色,用于关键字 */
}
:root[data-theme="winter"] .markdown-content :deep(.hljs-string),
.markdown-content[data-theme="winter"] :deep(.hljs-string),
[data-theme="winter"] .markdown-content :deep(.hljs-string),
:root[data-theme="winter"] .markdown-content :deep(.hljs-regexp),
.markdown-content[data-theme="winter"] :deep(.hljs-regexp),
[data-theme="winter"] .markdown-content :deep(.hljs-regexp) {
color: #2e7d32; /* 绿色,用于字符串 */
}
:root[data-theme="winter"] .markdown-content :deep(.hljs-number),
.markdown-content[data-theme="winter"] :deep(.hljs-number),
[data-theme="winter"] .markdown-content :deep(.hljs-number),
:root[data-theme="winter"] .markdown-content :deep(.hljs-literal),
.markdown-content[data-theme="winter"] :deep(.hljs-literal),
[data-theme="winter"] .markdown-content :deep(.hljs-literal) {
color: #f5871f; /* 橙色,用于数字 */
}
:root[data-theme="winter"] .markdown-content :deep(.hljs-comment),
.markdown-content[data-theme="winter"] :deep(.hljs-comment),
[data-theme="winter"] .markdown-content :deep(.hljs-comment) {
color: #8e908c; /* 灰色,用于注释 */
font-style: italic;
}
:root[data-theme="winter"] .markdown-content :deep(.hljs-built_in),
.markdown-content[data-theme="winter"] :deep(.hljs-built_in),
[data-theme="winter"] .markdown-content :deep(.hljs-built_in) {
color: #3e999f; /* 青色,用于内置函数 */
}
:root[data-theme="winter"] .markdown-content :deep(.hljs-title),
.markdown-content[data-theme="winter"] :deep(.hljs-title),
[data-theme="winter"] .markdown-content :deep(.hljs-title),
:root[data-theme="winter"] .markdown-content :deep(.hljs-function),
.markdown-content[data-theme="winter"] :deep(.hljs-function),
[data-theme="winter"] .markdown-content :deep(.hljs-function) {
color: #4271ae; /* 蓝色,用于函数名 */
}
:root[data-theme="winter"] .markdown-content :deep(.hljs-name),
.markdown-content[data-theme="winter"] :deep(.hljs-name),
[data-theme="winter"] .markdown-content :deep(.hljs-name),
:root[data-theme="winter"] .markdown-content :deep(.hljs-attribute),
.markdown-content[data-theme="winter"] :deep(.hljs-attribute),
[data-theme="winter"] .markdown-content :deep(.hljs-attribute) {
color: #c82829; /* 红色用于HTML标签和属性 */
}
/* 暗黑主题下的代码样式 */
:root[data-theme="night"] .markdown-content :deep(.hljs),
.markdown-content[data-theme="night"] :deep(.hljs),
[data-theme="night"] .markdown-content :deep(.hljs) {
--code-bg: #1e1e2e;
--code-color: #f8f8f2;
--inline-code-bg: #282a36;
--inline-code-color: #ff79c6;
--code-label-bg: #282a36;
--code-label-color: #bd93f9;
}
/* 暗黑主题下的语法高亮 */
:root[data-theme="night"] .markdown-content :deep(.hljs-keyword),
.markdown-content[data-theme="night"] :deep(.hljs-keyword),
[data-theme="night"] .markdown-content :deep(.hljs-keyword),
:root[data-theme="night"] .markdown-content :deep(.hljs-tag),
.markdown-content[data-theme="night"] :deep(.hljs-tag),
[data-theme="night"] .markdown-content :deep(.hljs-tag),
:root[data-theme="night"] .markdown-content :deep(.hljs-selector-tag),
.markdown-content[data-theme="night"] :deep(.hljs-selector-tag),
[data-theme="night"] .markdown-content :deep(.hljs-selector-tag) {
color: #cc99cd; /* 紫色,用于关键字 */
}
:root[data-theme="night"] .markdown-content :deep(.hljs-string),
.markdown-content[data-theme="night"] :deep(.hljs-string),
[data-theme="night"] .markdown-content :deep(.hljs-string),
:root[data-theme="night"] .markdown-content :deep(.hljs-regexp),
.markdown-content[data-theme="night"] :deep(.hljs-regexp),
[data-theme="night"] .markdown-content :deep(.hljs-regexp) {
color: #7ec699; /* 绿色,用于字符串 */
}
:root[data-theme="night"] .markdown-content :deep(.hljs-number),
.markdown-content[data-theme="night"] :deep(.hljs-number),
[data-theme="night"] .markdown-content :deep(.hljs-number),
:root[data-theme="night"] .markdown-content :deep(.hljs-literal),
.markdown-content[data-theme="night"] :deep(.hljs-literal),
[data-theme="night"] .markdown-content :deep(.hljs-literal) {
color: #f08d49; /* 橙色,用于数字 */
}
:root[data-theme="night"] .markdown-content :deep(.hljs-comment),
.markdown-content[data-theme="night"] :deep(.hljs-comment),
[data-theme="night"] .markdown-content :deep(.hljs-comment) {
color: #999999; /* 灰色,用于注释 */
font-style: italic;
}
:root[data-theme="night"] .markdown-content :deep(.hljs-built_in),
.markdown-content[data-theme="night"] :deep(.hljs-built_in),
[data-theme="night"] .markdown-content :deep(.hljs-built_in) {
color: #6196cc; /* 蓝色,用于内置函数 */
}
:root[data-theme="night"] .markdown-content :deep(.hljs-title),
.markdown-content[data-theme="night"] :deep(.hljs-title),
[data-theme="night"] .markdown-content :deep(.hljs-title),
:root[data-theme="night"] .markdown-content :deep(.hljs-function),
.markdown-content[data-theme="night"] :deep(.hljs-function),
[data-theme="night"] .markdown-content :deep(.hljs-function) {
color: #f8c555; /* 金色,用于函数名 */
}
:root[data-theme="night"] .markdown-content :deep(.hljs-name),
.markdown-content[data-theme="night"] :deep(.hljs-name),
[data-theme="night"] .markdown-content :deep(.hljs-name),
:root[data-theme="night"] .markdown-content :deep(.hljs-attribute),
.markdown-content[data-theme="night"] :deep(.hljs-attribute),
[data-theme="night"] .markdown-content :deep(.hljs-attribute) {
color: #e2777a; /* 红色用于HTML标签和属性 */
}
.markdown-content :deep(table) {
border-collapse: separate;
border-spacing: 0;
width: 100%;
margin: 1.5rem 0;
background-color: hsl(var(--b1));
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
border: 1px solid hsl(var(--b2));
}
.markdown-content :deep(th),
.markdown-content :deep(td) {
border: 1px solid hsl(var(--b2));
padding: 0.75rem 1rem;
text-align: left;
}
.markdown-content :deep(th) {
background-color: hsl(var(--p) / 0.15);
font-weight: 600;
color: hsl(var(--bc));
border-bottom: 2px solid hsl(var(--p) / 0.5);
}
.markdown-content :deep(tr:nth-child(even)) {
background-color: hsl(var(--b2) / 0.3);
}
.markdown-content :deep(tr:hover) {
background-color: hsl(var(--b2) / 0.5);
}
.markdown-content :deep(td) {
color: hsl(var(--bc) / 0.8);
}
.markdown-content :deep(blockquote) {
margin: 1.5rem 0;
padding: 1rem 1.5rem;
border-left: 4px solid hsl(var(--p));
background-color: hsl(var(--b2) / 0.3);
color: hsl(var(--bc) / 0.9);
font-style: italic;
border-radius: 0 0.5rem 0.5rem 0;
box-shadow: 0 2px 5px rgba(0,0,0,0.03);
position: relative;
}
.markdown-content :deep(blockquote::before) {
content: '"';
font-size: 2rem;
color: hsl(var(--p) / 0.3);
position: absolute;
top: 0.5rem;
left: 0.5rem;
font-family: serif;
}
.markdown-content :deep(blockquote p) {
margin-top: 0.5rem;
}
.markdown-content :deep(hr) {
border: none;
border-top: 1px solid hsl(var(--b2));
margin: 1.5rem 0;
}
.markdown-content :deep(a) {
color: hsl(var(--p));
text-decoration: none;
transition: color 0.2s;
}
.markdown-content :deep(a:hover) {
color: hsl(var(--pf));
text-decoration: underline;
}
/* 暗黑模式下的代码高亮调整 */
@media (prefers-color-scheme: dark) {
.markdown-content :deep(pre) {
background-color: hsl(var(--b3));
border-color: hsl(var(--b1) / 0.7);
}
.markdown-content :deep(code) {
background-color: hsl(var(--b2) / 0.7);
}
}
</style>