760 lines
23 KiB
Vue
760 lines
23 KiB
Vue
<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';
|
||
import { AuthManager } from '@/utils/AuthManager';
|
||
|
||
const props = defineProps({
|
||
content: {
|
||
type: String,
|
||
required: true
|
||
},
|
||
removeFirstH1: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
examId: {
|
||
type: String,
|
||
default: ''
|
||
}
|
||
});
|
||
|
||
// 使用主题存储
|
||
const themeStore = useThemeStore();
|
||
// 使用 isDarkTheme 函数来检查当前是否为暗色主题
|
||
const isDarkMode = computed(() => themeStore.isDarkTheme());
|
||
|
||
// 图片资源缓存
|
||
const imageResourceCache = ref<Map<string, string>>(new Map());
|
||
|
||
// 获取图片资源ID的函数
|
||
async function getImageResourceId(examId: string, imagePath: string): Promise<string | null> {
|
||
try {
|
||
const client = AuthManager.createAuthenticatedResourceClient();
|
||
const resources = await client.getResourceList(examId, 'images', 'template');
|
||
|
||
// 查找匹配的图片资源
|
||
const imageResource = resources.find(r => r.name === imagePath || r.name.endsWith(imagePath));
|
||
|
||
return imageResource ? imageResource.id.toString() : null;
|
||
} catch (error) {
|
||
console.error('获取图片资源ID失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 通过资源ID获取图片数据URL
|
||
async function getImageDataUrl(resourceId: string): Promise<string | null> {
|
||
try {
|
||
const client = AuthManager.createAuthenticatedResourceClient();
|
||
const response = await client.getResourceById(parseInt(resourceId));
|
||
|
||
if (response && response.data) {
|
||
return URL.createObjectURL(response.data);
|
||
}
|
||
|
||
return null;
|
||
} catch (error) {
|
||
console.error('获取图片数据失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 监听主题变化
|
||
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.image = (href, title, text) => {
|
||
let src = href;
|
||
|
||
console.log(`原始图片路径: ${href}, examId: ${props.examId}`);
|
||
|
||
// 如果是相对路径且有实验ID,需要通过动态API获取
|
||
if (props.examId && href && href.startsWith('./')) {
|
||
// 对于相对路径的图片,我们需要先获取图片资源ID,然后通过动态API获取
|
||
// 暂时保留原始路径,在后处理中进行替换
|
||
src = href;
|
||
console.log(`保留原始路径用于后处理: ${src}`);
|
||
}
|
||
|
||
const titleAttr = title ? ` title="${title}"` : '';
|
||
const altAttr = text ? ` alt="${text}"` : '';
|
||
const dataOriginal = href && href.startsWith('./') ? ` data-original-src="${href}"` : '';
|
||
console.log(`最终渲染的HTML: <img src="${src}"${titleAttr}${altAttr}${dataOriginal} />`);
|
||
return `<img src="${src}"${titleAttr}${altAttr}${dataOriginal} />`;
|
||
};
|
||
|
||
// 重写代码块渲染方法,添加语言信息
|
||
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 选项并解析内容
|
||
let html = marked.parse(processedContent, {
|
||
renderer: renderer,
|
||
gfm: true,
|
||
breaks: true
|
||
}) as string;
|
||
|
||
// 后处理HTML,异步处理图片
|
||
if (props.examId) {
|
||
// 查找所有需要处理的图片
|
||
const imgMatches = Array.from(html.matchAll(/(<img[^>]+data-original-src=["'])\.\/([^"']+)(["'][^>]*>)/g));
|
||
|
||
// 异步处理每个图片
|
||
imgMatches.forEach(async (match) => {
|
||
const [fullMatch, prefix, path, suffix] = match;
|
||
const imagePath = path.replace('images/', '');
|
||
|
||
// 检查缓存
|
||
if (imageResourceCache.value.has(imagePath)) {
|
||
const cachedUrl = imageResourceCache.value.get(imagePath)!;
|
||
html = html.replace(fullMatch, `${prefix}${cachedUrl}${suffix.replace(' data-original-src="./'+path+'"', '')}`);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 获取图片资源ID
|
||
const resourceId = await getImageResourceId(props.examId, imagePath);
|
||
if (resourceId) {
|
||
// 获取图片数据URL
|
||
const dataUrl = await getImageDataUrl(resourceId);
|
||
if (dataUrl) {
|
||
// 缓存URL
|
||
imageResourceCache.value.set(imagePath, dataUrl);
|
||
|
||
// 更新HTML中的图片src
|
||
const updatedHtml = html.replace(fullMatch, `${prefix}${dataUrl}${suffix.replace(' data-original-src="./'+path+'"', '')}`);
|
||
|
||
// 触发重新渲染
|
||
setTimeout(() => {
|
||
const imgElements = document.querySelectorAll(`img[data-original-src="./${path}"]`);
|
||
imgElements.forEach(img => {
|
||
(img as HTMLImageElement).src = dataUrl;
|
||
img.removeAttribute('data-original-src');
|
||
});
|
||
}, 0);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error(`处理图片 ${imagePath} 失败:`, error);
|
||
}
|
||
});
|
||
}
|
||
|
||
return html;
|
||
});
|
||
|
||
// 页面挂载后,确保应用正确的主题样式
|
||
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>
|