Fix: Markdown rendering style for different themes

This commit is contained in:
Joseph Hau committed 2025-03-15 11:43:36 +08:00
1 parent caa4f47480
commit 9fecf2d201
2 files changed
+501 -188

No files matched your search

+179 -188
View File
@@ -1,192 +1,183 @@
<template>
<div class="markdown-content" v-html="renderedMarkdown"></div>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
const props = defineProps({
content: {
type: String,
default: ''
}
});
const renderedMarkdown = ref('');
// 配置marked使用highlight.js进行代码高亮
marked.setOptions({
highlight: function(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
},
langPrefix: 'hljs language-',
breaks: true,
gfm: true,
headerIds: true,
mangle: false,
sanitize: false,
smartLists: true,
smartypants: false
});
// 渲染Markdown内容
const renderMarkdown = () => {
if (!props.content) {
renderedMarkdown.value = '';
return;
}
try {
// 使用marked将Markdown转为HTML
const rawHtml = marked.parse(props.content);
// 使用DOMPurify清理HTML,防止XSS攻击
renderedMarkdown.value = DOMPurify.sanitize(rawHtml);
} catch (error) {
console.error('Markdown parsing error:', error);
renderedMarkdown.value = `<p class="text-red-500">Error rendering markdown: ${error.message}</p>`;
}
};
// 监听content变化时重新渲染
watch(() => props.content, renderMarkdown, { immediate: true });
// 组件挂载时渲染
onMounted(() => {
renderMarkdown();
});
</script>
<style>
/* Markdown样式 */
.markdown-content {
color: var(--theme-text-color, #333);
line-height: 1.6;
word-wrap: break-word;
<div class="markdown-content theme-markdown-content theme-text" v-html="renderedMarkdown"></div>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
const props = defineProps({
content: {
type: String,
default: ''
}
});
const renderedMarkdown = ref('');
// 配置marked使用highlight.js进行代码高亮
marked.setOptions({
highlight: function(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
},
langPrefix: 'hljs language-',
breaks: true,
gfm: true,
headerIds: true,
mangle: false,
sanitize: false,
smartLists: true,
smartypants: false
});
// 渲染Markdown内容
const renderMarkdown = () => {
if (!props.content) {
renderedMarkdown.value = '';
return;
}
.markdown-content h1 {
font-size: 2em;
margin-top: 1.5em;
margin-bottom: 0.8em;
font-weight: 600;
try {
// 使用marked将Markdown转为HTML
const rawHtml = marked.parse(props.content);
// 使用DOMPurify清理HTML,防止XSS攻击
renderedMarkdown.value = DOMPurify.sanitize(rawHtml);
} catch (error) {
console.error('Markdown parsing error:', error);
renderedMarkdown.value = `<p class="text-red-500">Error rendering markdown: ${error.message}</p>`;
}
.markdown-content h2 {
font-size: 1.5em;
margin-top: 1.3em;
margin-bottom: 0.7em;
font-weight: 600;
border-bottom: 1px solid #eee;
padding-bottom: 0.3em;
}
.markdown-content h3 {
font-size: 1.25em;
margin-top: 1.2em;
margin-bottom: 0.6em;
font-weight: 600;
}
.markdown-content h4 {
font-size: 1em;
margin-top: 1.1em;
margin-bottom: 0.5em;
font-weight: 600;
}
.markdown-content p {
margin-bottom: 1em;
white-space: pre-wrap;
}
.markdown-content ul,
.markdown-content ol {
padding-left: 2em;
margin-bottom: 1em;
}
.markdown-content li {
margin-bottom: 0.5em;
}
.markdown-content pre {
background-color: #f6f8fa;
border-radius: 6px;
padding: 1em;
overflow: auto;
margin-bottom: 1em;
}
.markdown-content code {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.9em;
padding: 0.2em 0.4em;
margin: 0;
background-color: rgba(175, 184, 193, 0.2);
border-radius: 3px;
}
.markdown-content pre code {
padding: 0;
background-color: transparent;
}
.markdown-content blockquote {
padding: 0 1em;
color: #6a737d;
border-left: 0.25em solid #dfe2e5;
margin-left: 0;
margin-right: 0;
margin-bottom: 1em;
}
.markdown-content table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1em;
overflow: auto;
}
.markdown-content table th,
.markdown-content table td {
padding: 0.5em 1em;
border: 1px solid #dfe2e5;
}
.markdown-content table th {
font-weight: 600;
background-color: #f6f8fa;
}
.markdown-content table tr:nth-child(2n) {
background-color: #f6f8fa;
}
.markdown-content img {
max-width: 100%;
box-sizing: border-box;
margin: 1em 0;
}
.markdown-content hr {
height: 0.25em;
padding: 0;
margin: 1.5em 0;
background-color: #e1e4e8;
border: 0;
}
.markdown-content a {
color: var(--theme-primary-color, #0366d6);
text-decoration: none;
}
.markdown-content a:hover {
text-decoration: underline;
}
</style>
};
// 监听content变化时重新渲染
watch(() => props.content, renderMarkdown, { immediate: true });
// 组件挂载时渲染
onMounted(() => {
renderMarkdown();
});
</script>
<style>
/* 基本布局和非颜色样式 */
.markdown-content {
line-height: 1.6;
word-wrap: break-word;
}
/* 标题样式 */
.markdown-content h1 {
font-size: 2em;
margin-top: 1.5em;
margin-bottom: 0.8em;
font-weight: 600;
}
.markdown-content h2 {
font-size: 1.5em;
margin-top: 1.3em;
margin-bottom: 0.7em;
font-weight: 600;
padding-bottom: 0.3em;
}
.markdown-content h3 {
font-size: 1.25em;
margin-top: 1.2em;
margin-bottom: 0.6em;
font-weight: 600;
}
.markdown-content h4 {
font-size: 1em;
margin-top: 1.1em;
margin-bottom: 0.5em;
font-weight: 600;
}
/* 段落样式 */
.markdown-content p {
margin-bottom: 1em;
white-space: pre-wrap;
}
/* 列表样式 */
.markdown-content ul,
.markdown-content ol {
padding-left: 2em;
margin-bottom: 1em;
}
.markdown-content li {
margin-bottom: 0.5em;
}
/* 代码块样式 */
.markdown-content pre {
border-radius: 6px;
padding: 1em;
overflow: auto;
margin-bottom: 1em;
}
.markdown-content code {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.9em;
padding: 0.2em 0.4em;
margin: 0;
border-radius: 3px;
}
.markdown-content pre code {
padding: 0;
background-color: transparent;
}
/* 引用样式 */
.markdown-content blockquote {
padding: 0 1em;
margin-left: 0;
margin-right: 0;
margin-bottom: 1em;
}
/* 表格样式 */
.markdown-content table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1em;
overflow: auto;
}
.markdown-content table th,
.markdown-content table td {
padding: 0.5em 1em;
}
/* 图片样式 */
.markdown-content img {
max-width: 100%;
box-sizing: border-box;
margin: 1em 0;
}
/* 水平线样式 */
.markdown-content hr {
height: 0.25em;
padding: 0;
margin: 1.5em 0;
border: 0;
}
/* 链接样式 */
.markdown-content a {
text-decoration: none;
}
.markdown-content a:hover {
text-decoration: underline;
}
</style>
+322
View File
@@ -440,6 +440,89 @@ html * {
.theme-manager-text-disabled {
@apply text-stone-400;
}
/* Markdown主题样式 - Light Mode (默认主题) */
.theme-markdown-content {
@apply text-stone-600;
}
.theme-markdown-content h1,
.theme-markdown-content h2,
.theme-markdown-content h3,
.theme-markdown-content h4 {
@apply text-stone-700;
}
.theme-markdown-content h2 {
@apply border-b border-stone-200;
}
.theme-markdown-content a {
@apply text-stone-800 underline hover:text-stone-600;
}
.theme-markdown-content pre {
@apply bg-stone-100 border border-stone-200;
}
.theme-markdown-content code {
@apply bg-stone-100 text-stone-700;
}
.theme-markdown-content blockquote {
@apply border-l-4 border-stone-300 bg-stone-50 text-stone-600 px-4 py-2;
}
.theme-markdown-content table {
@apply border-collapse border border-stone-200 my-4;
}
.theme-markdown-content table th {
@apply bg-stone-100 text-stone-700 border border-stone-300 p-2 font-semibold;
}
.theme-markdown-content table td {
@apply border border-stone-200 text-stone-600 p-2;
}
.theme-markdown-content tr:nth-child(even) {
@apply bg-stone-50;
}
.theme-markdown-content hr {
@apply border-stone-200 my-4;
}
.theme-markdown-content ul {
@apply list-disc pl-5 my-3;
}
.theme-markdown-content ol {
@apply list-decimal pl-5 my-3;
}
.theme-markdown-content img {
@apply max-w-full rounded border border-stone-200 my-3;
}
.theme-markdown-content p {
@apply my-3;
}
.theme-markdown-content strong {
@apply font-semibold text-stone-700;
}
.theme-markdown-content em {
@apply italic;
}
.theme-markdown-content pre code {
@apply block p-4 overflow-x-auto;
}
.theme-markdown-content code {
@apply px-1.5 py-0.5 rounded text-sm;
}
}
/* 主题变体 */
@@ -758,6 +841,66 @@ html * {
@apply
text-blue-400;
}
/* 蓝色主题的 Markdown 样式 */
.theme-markdown-content {
@apply text-sky-700;
}
.theme-markdown-content h1,
.theme-markdown-content h2,
.theme-markdown-content h3,
.theme-markdown-content h4 {
@apply text-sky-800;
}
.theme-markdown-content h2 {
@apply border-b border-sky-200;
}
.theme-markdown-content a {
@apply text-blue-600 hover:text-blue-800;
}
.theme-markdown-content pre {
@apply bg-sky-50 border border-sky-200;
}
.theme-markdown-content code {
@apply bg-sky-50 text-sky-800;
}
.theme-markdown-content blockquote {
@apply border-l-4 border-sky-300 bg-sky-50/60 text-sky-700;
}
.theme-markdown-content table {
@apply border border-sky-200;
}
.theme-markdown-content table th {
@apply bg-sky-100 text-sky-800 border border-sky-300;
}
.theme-markdown-content table td {
@apply border border-sky-200 text-sky-700;
}
.theme-markdown-content tr:nth-child(even) {
@apply bg-sky-50;
}
.theme-markdown-content hr {
@apply border-sky-200;
}
.theme-markdown-content img {
@apply border border-sky-200;
}
.theme-markdown-content strong {
@apply text-sky-800;
}
}
:root[data-theme="green"] {
@@ -973,6 +1116,65 @@ html * {
text-red-900 hover:text-white
transition-colors;
}
/* 绿色主题的 Markdown 样式 */
.theme-markdown-content {
@apply text-teal-200;
}
.theme-markdown-content h1,
.theme-markdown-content h2,
.theme-markdown-content h3,
.theme-markdown-content h4 {
@apply text-teal-100;
}
.theme-markdown-content h2 {
@apply border-b border-teal-600;
}
.theme-markdown-content a {
@apply text-teal-300 hover:text-teal-200;
}
.theme-markdown-content pre {
@apply bg-teal-900/50 border border-teal-700;
}
.theme-markdown-content code {
@apply bg-teal-800 text-teal-200;
}
.theme-markdown-content blockquote {
@apply border-l-4 border-teal-600 bg-teal-800/50 text-teal-300;
}
.theme-markdown-content table {
@apply border border-teal-700;
}
.theme-markdown-content table th {
@apply bg-teal-800 text-teal-200 border border-teal-600;
}
.theme-markdown-content table td {
@apply border border-teal-700 text-teal-300;
}
.theme-markdown-content tr:nth-child(even) {
@apply bg-teal-800/50;
}
.theme-markdown-content hr {
@apply border-teal-600;
}
.theme-markdown-content img {
@apply border border-teal-700;
}
.theme-markdown-content strong {
@apply text-teal-100;
}
}
:root[data-theme="purple"] {
@@ -1245,6 +1447,66 @@ html * {
.theme-manager-text-disabled {
@apply text-white/40;
}
/* 紫色主题的 Markdown 样式 */
.theme-markdown-content {
@apply text-white/90;
}
.theme-markdown-content h1,
.theme-markdown-content h2,
.theme-markdown-content h3,
.theme-markdown-content h4 {
@apply text-white;
}
.theme-markdown-content h2 {
@apply border-b border-purple-600/50;
}
.theme-markdown-content a {
@apply text-purple-300 hover:text-purple-200;
}
.theme-markdown-content pre {
@apply bg-black/20 border border-purple-600/50;
}
.theme-markdown-content code {
@apply bg-purple-900/50 text-purple-200;
}
.theme-markdown-content blockquote {
@apply border-l-4 border-purple-500 bg-purple-900/30 text-purple-200;
}
.theme-markdown-content table {
@apply border border-purple-700/50;
}
.theme-markdown-content table th {
@apply bg-purple-800/50 text-white border border-purple-600/50;
}
.theme-markdown-content table td {
@apply border border-purple-700/50 text-white/90;
}
.theme-markdown-content tr:nth-child(even) {
@apply bg-purple-800/30;
}
.theme-markdown-content hr {
@apply border-purple-600/50;
}
.theme-markdown-content img {
@apply border border-purple-600/50;
}
.theme-markdown-content strong {
@apply text-white;
}
}
:root[data-theme="dark"] {
@@ -1462,4 +1724,64 @@ html * {
.theme-history-card-header {
@apply border-slate-700/50 /*卡片头部下边线*/;
}
/* 暗色主题的 Markdown 样式 */
.theme-markdown-content {
@apply text-slate-100;
}
.theme-markdown-content h1,
.theme-markdown-content h2,
.theme-markdown-content h3,
.theme-markdown-content h4 {
@apply text-white;
}
.theme-markdown-content h2 {
@apply border-b border-slate-700;
}
.theme-markdown-content a {
@apply text-purple-400 hover:text-purple-300;
}
.theme-markdown-content pre {
@apply bg-slate-800 border border-slate-700;
}
.theme-markdown-content code {
@apply bg-slate-800 text-slate-200;
}
.theme-markdown-content blockquote {
@apply border-l-4 border-slate-600 bg-slate-800/50 text-slate-300;
}
.theme-markdown-content table {
@apply border border-slate-700;
}
.theme-markdown-content table th {
@apply bg-slate-800 text-slate-200 border border-slate-700;
}
.theme-markdown-content table td {
@apply border border-slate-700 text-slate-300;
}
.theme-markdown-content tr:nth-child(even) {
@apply bg-slate-800/70;
}
.theme-markdown-content hr {
@apply border-slate-700;
}
.theme-markdown-content img {
@apply border border-slate-700;
}
.theme-markdown-content strong {
@apply text-white;
}
}