feat: 添加 Markdown 渲染组件及样式配置
This commit is contained in:
1 parent
d5a4846a05
commit
b91f52cf4a
2 files changed
+237
-6
No files matched your search
+7
-6
@@ -10,7 +10,7 @@
|
|||||||
--header-text: #ffffff;
|
--header-text: #ffffff;
|
||||||
--header-text-hover: #ffffff;
|
--header-text-hover: #ffffff;
|
||||||
|
|
||||||
--accent-color: #bd6262;
|
--accent-color: #419b38;
|
||||||
|
|
||||||
--font-sans: 'Open Sans', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', 'WenQuanYi Micro Hei', 'Segoe UI Emoji', 'Segoe UI Symbol', Helvetica, Arial, -apple-system, system-ui, sans-serif;
|
--font-sans: 'Open Sans', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', 'WenQuanYi Micro Hei', 'Segoe UI Emoji', 'Segoe UI Symbol', Helvetica, Arial, -apple-system, system-ui, sans-serif;
|
||||||
--font-serif: 'Noto Serif SC', var(--font-sans);
|
--font-serif: 'Noto Serif SC', var(--font-sans);
|
||||||
@@ -78,7 +78,8 @@ a:hover {
|
|||||||
background-color: var(--header-bg);
|
background-color: var(--header-bg);
|
||||||
color: var(--header-text);
|
color: var(--header-text);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
transform: translateZ(0);
|
||||||
|
transition: box-shadow 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||||
}
|
}
|
||||||
|
|
||||||
@supports (backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)) {
|
@supports (backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)) {
|
||||||
@@ -154,7 +155,7 @@ a:hover {
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background-color: var(--accent-color, #bd6262);
|
background-color: var(--accent-color, #419b38);
|
||||||
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1044,7 +1045,7 @@ footer section p:first-child {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.TOC li a:hover, .TOC li a.is-active-link {
|
.TOC li a:hover, .TOC li a.is-active-link {
|
||||||
color: #54bc4b;
|
color: #419b38;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1060,7 +1061,7 @@ footer section p:first-child {
|
|||||||
left: -1rem;
|
left: -1rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: calc(100% + 1rem);
|
width: calc(100% + 1rem);
|
||||||
border-left: 2px solid #54BC4B;
|
border-left: 2px solid #419b38;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -1074,7 +1075,7 @@ footer section p:first-child {
|
|||||||
left: -1rem;
|
left: -1rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: calc(100% + 1rem);
|
width: calc(100% + 1rem);
|
||||||
border-left: 2px solid #54BC4B;
|
border-left: 2px solid #419b38;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Marked } from 'marked';
|
||||||
|
import hljs from 'highlight.js';
|
||||||
|
import 'highlight.js/styles/github.css';
|
||||||
|
import { Fancybox } from '@fancyapps/ui/dist/index.js';
|
||||||
|
import '@fancyapps/ui/dist/fancybox/fancybox.css';
|
||||||
|
|
||||||
|
let { content = '' } = $props<{ content: string }>();
|
||||||
|
|
||||||
|
let container: HTMLElement;
|
||||||
|
|
||||||
|
// 创建独立 Marked 实例
|
||||||
|
const markedInstance = new Marked();
|
||||||
|
markedInstance.use({
|
||||||
|
renderer: {
|
||||||
|
code(token) {
|
||||||
|
const code = token.text;
|
||||||
|
const lang = (token.lang || '').split(' ')[0];
|
||||||
|
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
|
||||||
|
const highlighted = hljs.highlight(code, { language }).value;
|
||||||
|
const title = lang || 'text';
|
||||||
|
const encodedCode = encodeURIComponent(code);
|
||||||
|
|
||||||
|
const wrappedLines = highlighted
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => `<span class="code-line">${line}</span>`)
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
const chevronRight = '<svg class="chevron-icon" viewBox="0 0 320 512" fill="currentColor" width="0.625em" height="1em"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>';
|
||||||
|
const listOlIcon = '<svg viewBox="0 0 512 512" fill="currentColor" width="1em" height="1em"><path d="M61.77 401l17.5-20.15a19.92 19.92 0 0 0 5.07-14.19v-3.31C84.34 356 80.5 352 73 352H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h22.83a157.41 157.41 0 0 0-11 12.31l-5.61 7c-4 5.07-5.25 10.13-2.8 14.88l1.05 1.93c3 5.76 6.29 7.88 12.25 7.88h4.73c10.33 0 15.94 2.44 15.94 9.09 0 4.72-4.2 8.22-14.36 8.22a41.54 41.54 0 0 1-15.47-3.12c-6.49-3.88-11.74-3.5-15.6 3.12l-5.59 9.31c-3.72 6.13-3.19 11.72 2.63 15.94 7.71 4.69 20.38 9.44 37 9.44 34.16 0 48.5-22.75 48.5-44.12-.03-14.38-9.12-29.76-28.73-34.88zM496 224H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM16 160h64a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H64V40a8 8 0 0 0-8-8H32a8 8 0 0 0-7.14 4.42l-8 16A8 8 0 0 0 24 64h8v64H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8zm-3.91 160H80a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H41.32c3.29-10.29 48.34-18.68 48.34-56.44 0-29.06-25-39.56-44.47-39.56-21.36 0-33.8 10-40.46 18.75-4.37 5.59-3 10.84 2.8 15.37l8.58 6.88c5.61 4.56 11 2.47 16.12-2.44a13.44 13.44 0 0 1 9.46-3.84c3.33 0 9.28 1.56 9.28 8.75C51 248.19 0 257.31 0 304.59v4C0 316 5.08 320 12.09 320z"></path></svg>';
|
||||||
|
const barsIcon = '<svg viewBox="0 0 448 512" fill="currentColor" width="1em" height="1em"><path d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"></path></svg>';
|
||||||
|
const copyIcon = '<svg viewBox="0 0 448 512" fill="currentColor" width="1em" height="1em"><path d="M433.941 65.941l-51.882-51.882A48 48 0 00348.118 0H176c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h224c26.51 0 48-21.49 48-48v-48h80c26.51 0 48-21.49 48-48V99.882a48 48 0 00-14.059-33.941zM266 464H54a6 6 0 01-6-6V150a6 6 0 016-6h74v224c0 26.51 21.49 48 48 48h96v42a6 6 0 01-6 6zm128-96H182a6 6 0 01-6-6V54a6 6 0 016-6h106v88c0 13.255 10.745 24 24 24h88v200a6 6 0 01-6 6zm6-256h-64V48h9.632c1.591 0 3.117.632 4.243 1.757l48.368 48.368a6 6 0 011.757 4.243V112z"></path></svg>';
|
||||||
|
const checkIcon = '<svg viewBox="0 0 512 512" fill="currentColor" width="1em" height="1em"><path d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z"></path></svg>';
|
||||||
|
const ellipsisIcon = '<svg viewBox="0 0 512 512" fill="currentColor" width="1em" height="1em"><path d="M328 256c0 39.8-32.2 72-72 72s-72-32.2-72-72 32.2-72 72-72 72 32.2 72 72zm104-72c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72zm-352 0c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72z"></path></svg>';
|
||||||
|
|
||||||
|
return `<div class="code-block highlight is-open show-line-numbers">
|
||||||
|
<div class="code-block-header">
|
||||||
|
<button class="code-block-title-btn" aria-hidden="true">
|
||||||
|
${chevronRight}
|
||||||
|
<span class="code-title">${title}</span>
|
||||||
|
</button>
|
||||||
|
<div class="code-header-actions">
|
||||||
|
<button class="action-icon line-number-button is-active" title="Toggle line numbers">${listOlIcon}</button>
|
||||||
|
<button class="action-icon wrap-code-button" title="Toggle code wrap">${barsIcon}</button>
|
||||||
|
<button class="action-icon copy-code-button" title="Copy code" data-code="${encodedCode}">
|
||||||
|
<span class="copy-icon" style="display:block">${copyIcon}</span>
|
||||||
|
<span class="check-icon" style="display:none">${checkIcon}</span>
|
||||||
|
</button>
|
||||||
|
<span class="ellipsis-icon" aria-hidden="true">${ellipsisIcon}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre style="counter-reset:codeblock;"><code class="hljs language-${language}">${wrappedLines}</code></pre>
|
||||||
|
</div>`;
|
||||||
|
},
|
||||||
|
image(token) {
|
||||||
|
const src = token.href;
|
||||||
|
const alt = token.text || '';
|
||||||
|
const title = token.title || alt;
|
||||||
|
|
||||||
|
let figcaption = '';
|
||||||
|
if (title) {
|
||||||
|
figcaption = `<figcaption>${title}</figcaption>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<figure><a data-fancybox="gallery" data-caption="${title}" href="${src}"><img src="${src}" alt="${alt}" title="${title}"></a>${figcaption}</figure>`;
|
||||||
|
},
|
||||||
|
heading(token) {
|
||||||
|
const text = token.text;
|
||||||
|
const rawText = text.replace(/<[^>]*>?/gm, ''); // Strip HTML tags
|
||||||
|
const level = token.depth;
|
||||||
|
const id = rawText.trim().toLowerCase().replace(/\s+/g, '-');
|
||||||
|
return `<h${level} id="${id}">${text}</h${level}>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function parseAdmonitions(markdown: string) {
|
||||||
|
const icons = {
|
||||||
|
note: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M290.74 93.24l128.02 128.02-277.99 277.99-114.14 12.6C11.35 513.54-1.56 500.62.14 485.34l12.7-114.22 277.9-277.88zm207.2-19.06l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.76 18.75-49.16 0-67.91z"></path></svg>',
|
||||||
|
abstract: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M48 48a48 48 0 1 0 48 48 48.14 48.14 0 0 0-48-48zm0 160a48 48 0 1 0 48 48 48.14 48.14 0 0 0-48-48zm0 160a48 48 0 1 0 48 48 48.14 48.14 0 0 0-48-48zm448 16H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"></path></svg>',
|
||||||
|
info: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"></path></svg>',
|
||||||
|
tip: '<svg viewBox="0 0 352 512" fill="currentColor" height="1em" width="1em"><path d="M96.06 454.35c.01 6.29 1.87 12.45 5.36 17.69l17.09 25.69a31.99 31.99 0 0 0 26.64 14.28h61.71a31.99 31.99 0 0 0 26.64-14.28l17.09-25.69a31.989 31.989 0 0 0 5.36-17.69l.04-38.35H96.01l.05 38.35zM0 176c0 44.37 16.45 84.85 43.56 115.78 16.64 18.99 42.74 58.8 52.42 92.16h160.03c9.68-33.35 35.78-73.16 52.42-92.16C335.55 260.85 352 220.37 352 176 352 78.8 273.2 0 176 0S0 78.8 0 176z"></path></svg>',
|
||||||
|
success: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"></path></svg>',
|
||||||
|
question: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zM262.655 90c-54.497 0-89.255 22.957-116.549 63.758-3.536 5.286-2.353 12.415 2.715 16.258l34.699 26.31c5.205 3.947 12.621 3.008 16.665-2.122 17.864-22.658 30.113-35.797 57.303-35.797 20.429 0 45.698 13.148 45.698 32.958 0 14.976-12.363 22.667-32.534 33.976C247.128 238.528 216 254.941 216 296v4c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12v-1.333c0-28.462 83.186-29.647 83.186-106.667 0-58.002-60.165-102-116.531-102zM256 338c-25.365 0-46 20.635-46 46 0 25.364 20.635 46 46 46s46-20.636 46-46c0-25.365-20.635-46-46-46z"></path></svg>',
|
||||||
|
warning: '<svg viewBox="0 0 576 512" fill="currentColor" height="1em" width="1em"><path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.466-32.004 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>',
|
||||||
|
failure: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"></path></svg>',
|
||||||
|
danger: '<svg viewBox="0 0 448 512" fill="currentColor" height="1em" width="1em"><path d="M439.15 453.06L297.17 384l141.99-69.06c7.9-3.95 11.11-13.56 7.15-21.46L432 264.85c-3.95-7.9-13.56-11.11-21.47-7.16L224 348.41 37.47 257.69c-7.9-3.95-17.51-.75-21.47 7.16L1.69 293.48c-3.96 7.9-.76 17.51 7.15 21.46L150.83 384 8.85 453.06c-7.9 3.95-11.11 13.56-7.15 21.47l14.31 28.63c3.95 7.9 13.56 11.11 21.47 7.15L224 419.59l186.53 90.72c7.9 3.95 17.51.75 21.47-7.15l14.31-28.63c3.95-7.91.75-17.52-7.16-21.47zM150 237.28l-5.48 25.87c-2.67 12.62 5.42 24.85 16.45 24.85h126.08c11.03 0 19.12-12.23 16.45-24.85l-5.5-25.87c41.78-22.41 70-62.8 70-109.28C368 61.85 303.73 0 224 0S80 61.85 80 128c0 46.48 28.22 86.87 70 109.28zM280 112c17.65 0 32 14.35 32 32s-14.35 32-32 32-32-14.35-32-32 14.35-32 32-32zm-112 0c17.65 0 32 14.35 32 32s-14.35 32-32 32-32-14.35-32-32 14.35-32 32-32z"></path></svg>',
|
||||||
|
bug: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M511.98 256.03c0-34.92-27.46-64-62.24-64h-38.38c-8.91-44.57-30.82-84.34-60.77-116.14l27.13-27.13c12.5-12.5 12.5-32.76 0-45.25l-22.63-22.63c-12.5-12.5-32.76-12.5-45.25 0l-43.14 43.14A220.617 220.617 0 0 0 256 16.03c-3.69 0-7.38.15-11.05.35l-43.15-43.15c-12.5-12.5-32.76-12.5-45.25 0l-22.63 22.63c-12.5 12.5-12.5 32.76 0 45.25l27.13 27.13c-29.95 31.8-51.86 71.57-60.77 116.14H62.26c-34.78 0-62.24 29.08-62.24 64 0 34.39 26.89 62.48 61 63.92V336.1c0 51.52 19.34 98.4 51.05 133.72l-25.56 25.56c-12.5 12.5-12.5 32.76 0 45.25l22.63 22.63c12.5 12.5 32.76 12.5 45.25 0l42.66-42.66c30.2 16.92 64.71 27.42 101 27.42s70.8-10.5 101-27.42l42.66 42.66c12.5 12.5 32.76 12.5 45.25 0l22.63-22.63c12.5-12.5 12.5-32.76 0-45.25l-25.56-25.56C430.68 434.5 450 387.62 450 336.1v-23.79c34.11-1.44 61.98-29.53 61.98-63.92v-8.36zM152 280.03c0-13.25 10.75-24 24-24s24 10.75 24 24v56c0 13.25-10.75 24-24 24s-24-10.75-24-24v-56zm160 0c0-13.25 10.75-24 24-24s24 10.75 24 24v56c0 13.25-10.75 24-24 24s-24-10.75-24-24v-56z"></path></svg>',
|
||||||
|
example: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M61.77 401l17.5-20.15a19.92 19.92 0 0 0 5.07-14.19v-3.31C84.34 356 80.5 352 73 352H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h34.71L15.32 424.64A29.85 29.85 0 0 0 8 444v16c0 26.51 21.49 48 48 48h24a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H56c-8.84 0-16-7.16-16-16v-4.52a6.01 6.01 0 0 1 1.76-4.24l19.24-19.24a48.28 48.28 0 0 0 7.58 3.06L64 448c0 35.35 28.65 64 64 64s64-28.65 64-64-28.65-64-64-64c-9.67 0-18.77 2.21-27.05 6.04L75.64 361.7A29.8 29.8 0 0 0 56 352h-7.66c10.37-4.14 17.66-14.24 17.66-26.34v-3.31c0-15.46-12.54-28-28-28H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h22c2.21 0 4 1.79 4 4v3.31c0 2.21-1.79 4-4 4H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h15.4c17.21 0 33.15 6.94 44.97 19.46l5.4-6.23a43.83 43.83 0 0 1 7.23-7.19h-15zM480 352H208a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h272a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM208 112h272a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16H208a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16zM480 208H208a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h272a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM88 32H16C7.16 32 0 39.16 0 48v20c0 8.84 7.16 16 16 16h16v64c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16V48c0-8.84-7.16-16-16-16h-48c0-8.84 7.16-16 16-16zm64 160c0-35.35-28.65-64-64-64s-64 28.65-64 64 28.65 64 64 64 64-28.65 64-64zm-32 0c0 17.67-14.33 32-32 32s-32-14.33-32-32 14.33-32 32-32 32 14.33 32 32zm0-24c0 17.67-14.33 32-32 32s-32-14.33-32-32 14.33-32 32-32 32 14.33 32 32zm0-24c0 17.67-14.33 32-32 32s-32-14.33-32-32 14.33-32 32-32 32 14.33 32 32z"></path></svg>',
|
||||||
|
quote: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M464 256h-80v-64c0-35.3 28.7-64 64-64h8c13.3 0 24-10.7 24-24V56c0-13.3-10.7-24-24-24h-8c-88.4 0-160 71.6-160 160v240c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48zm-288 0H96v-64c0-35.3 28.7-64 64-64h8c13.3 0 24-10.7 24-24V56c0-13.3-10.7-24-24-24h-8C71.6 32 0 103.6 0 192v240c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48z"></path></svg>',
|
||||||
|
important: '<svg viewBox="0 0 192 512" fill="currentColor" height="1em" width="1em"><path d="M176 432c0 44.112-35.888 80-80 80s-80-35.888-80-80 35.888-80 80-80 80 35.888 80 80zM25.26 25.33l7.12 256.33c.35 12.63 10.71 22.34 23.36 22.34h80.51c12.65 0 23.01-9.71 23.36-22.34l7.12-256.33c.37-13.37-10.36-24.33-23.75-24.33H49.02c-13.4 0-24.12 10.96-23.76 24.33z"></path></svg>',
|
||||||
|
caution: '<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em"><path d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>'
|
||||||
|
};
|
||||||
|
|
||||||
|
const githubRegex = /(?:^|\r?\n)> ?\[!(NOTE|ABSTRACT|INFO|TIP|SUCCESS|QUESTION|WARNING|FAILURE|DANGER|BUG|EXAMPLE|QUOTE|IMPORTANT|CAUTION)\][ \t]*(.*?)\r?\n((?:>.*\r?\n?)*)/gi;
|
||||||
|
let html = markdown.replace(githubRegex, (match, type, title, content) => {
|
||||||
|
const typeLower = type.toLowerCase();
|
||||||
|
const displayTitle = title ? title : type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();
|
||||||
|
const icon = icons[typeLower as keyof typeof icons] || icons.note;
|
||||||
|
const cleanContent = content.replace(/^> ?/gm, '');
|
||||||
|
return `\n<div class="details admonition ${typeLower} open">\n<div class="details-summary admonition-title"><span class="icon">${icon}</span><span>${displayTitle}</span></div>\n<div class="details-content">\n<div class="admonition-content">\n\n${cleanContent}\n\n</div>\n</div>\n</div>\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const hugoRegex = /\{\{<\s*admonition\s+([a-zA-Z]+)(?:\s+"(.*?)")?\s*>\}\}\r?\n([\s\S]*?)\{\{<\s*\/admonition\s*>\}\}/gi;
|
||||||
|
html = html.replace(hugoRegex, (match, type, title, content) => {
|
||||||
|
const typeLower = type.toLowerCase();
|
||||||
|
const displayTitle = title ? title : type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();
|
||||||
|
const icon = icons[typeLower as keyof typeof icons] || icons.note;
|
||||||
|
return `\n<div class="details admonition ${typeLower} open">\n<div class="details-summary admonition-title"><span class="icon">${icon}</span><span>${displayTitle}</span></div>\n<div class="details-content">\n<div class="admonition-content">\n\n${content}\n\n</div>\n</div>\n</div>\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderMarkdown(raw: string) {
|
||||||
|
const preprocessedContent = parseAdmonitions(raw);
|
||||||
|
return markedInstance.parse(preprocessedContent) as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlContent = $derived(renderMarkdown(content));
|
||||||
|
|
||||||
|
function bindEvents() {
|
||||||
|
Fancybox.bind('[data-fancybox]', {});
|
||||||
|
|
||||||
|
if (!container) return;
|
||||||
|
container.querySelectorAll('.code-block').forEach((codeBlock) => {
|
||||||
|
const titleButton = codeBlock.querySelector('button.code-block-title-btn') as HTMLElement;
|
||||||
|
const codeEl = codeBlock.querySelector('pre code') as HTMLElement;
|
||||||
|
const copyCodeButton = codeBlock.querySelector('button.copy-code-button') as HTMLElement;
|
||||||
|
const lineNumButton = codeBlock.querySelector('button.line-number-button') as HTMLElement;
|
||||||
|
const wrapButton = codeBlock.querySelector('button.wrap-code-button') as HTMLElement;
|
||||||
|
const copyIconEl = copyCodeButton?.querySelector('span.copy-icon') as HTMLElement;
|
||||||
|
const checkIconEl = copyCodeButton?.querySelector('span.check-icon') as HTMLElement;
|
||||||
|
|
||||||
|
if (codeEl && codeBlock.classList.contains('is-open')) {
|
||||||
|
codeEl.style.maxHeight = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
titleButton?.addEventListener('click', () => {
|
||||||
|
if (!codeEl) return;
|
||||||
|
if (codeBlock.classList.contains('is-open')) {
|
||||||
|
if (codeEl.style.maxHeight === 'none' || codeEl.style.maxHeight === '') {
|
||||||
|
codeEl.style.maxHeight = codeEl.scrollHeight + 'px';
|
||||||
|
void codeEl.offsetHeight; // 强制 reflow
|
||||||
|
}
|
||||||
|
codeEl.style.maxHeight = '0px';
|
||||||
|
codeBlock.classList.remove('is-open');
|
||||||
|
codeBlock.classList.add('is-closed');
|
||||||
|
} else {
|
||||||
|
codeBlock.classList.remove('is-closed');
|
||||||
|
codeBlock.classList.add('is-open');
|
||||||
|
codeEl.style.maxHeight = codeEl.scrollHeight + 'px';
|
||||||
|
const handler = (e: Event) => {
|
||||||
|
if (e.target === codeEl && codeBlock.classList.contains('is-open')) {
|
||||||
|
codeEl.style.maxHeight = 'none';
|
||||||
|
}
|
||||||
|
codeEl.removeEventListener('transitionend', handler);
|
||||||
|
};
|
||||||
|
codeEl.addEventListener('transitionend', handler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
lineNumButton?.addEventListener('click', () => {
|
||||||
|
codeBlock.classList.toggle('show-line-numbers');
|
||||||
|
lineNumButton.classList.toggle('is-active');
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapButton?.addEventListener('click', () => {
|
||||||
|
codeBlock.classList.toggle('is-wrap');
|
||||||
|
wrapButton.classList.toggle('is-active');
|
||||||
|
});
|
||||||
|
|
||||||
|
copyCodeButton?.addEventListener('click', () => {
|
||||||
|
if (codeEl) {
|
||||||
|
navigator.clipboard.writeText(codeEl.textContent || '');
|
||||||
|
if (copyIconEl) copyIconEl.style.display = 'none';
|
||||||
|
if (checkIconEl) checkIconEl.style.display = 'block';
|
||||||
|
setTimeout(() => {
|
||||||
|
if (copyIconEl) copyIconEl.style.display = 'block';
|
||||||
|
if (checkIconEl) checkIconEl.style.display = 'none';
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
container.querySelectorAll('.details').forEach((detailsEl) => {
|
||||||
|
const summaryEl = detailsEl.querySelector('.details-summary') as HTMLElement;
|
||||||
|
if (!summaryEl) return;
|
||||||
|
const contentEl = summaryEl.nextElementSibling as HTMLElement;
|
||||||
|
if (!contentEl) return;
|
||||||
|
|
||||||
|
if (detailsEl.classList.contains('open')) {
|
||||||
|
contentEl.style.maxHeight = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
summaryEl.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (detailsEl.classList.contains('open')) {
|
||||||
|
if (contentEl.style.maxHeight === 'none' || contentEl.style.maxHeight === '') {
|
||||||
|
contentEl.style.maxHeight = contentEl.scrollHeight + 'px';
|
||||||
|
void contentEl.offsetHeight;
|
||||||
|
}
|
||||||
|
contentEl.style.maxHeight = '0px';
|
||||||
|
detailsEl.classList.remove('open');
|
||||||
|
} else {
|
||||||
|
detailsEl.classList.add('open');
|
||||||
|
contentEl.style.maxHeight = contentEl.scrollHeight + 'px';
|
||||||
|
|
||||||
|
const transitionEndHandler = (e: Event) => {
|
||||||
|
if (e.target === contentEl && detailsEl.classList.contains('open')) {
|
||||||
|
contentEl.style.maxHeight = 'none';
|
||||||
|
}
|
||||||
|
contentEl.removeEventListener('transitionend', transitionEndHandler);
|
||||||
|
};
|
||||||
|
contentEl.addEventListener('transitionend', transitionEndHandler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (htmlContent) {
|
||||||
|
bindEvents();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={container} class="articleBody article-content js-toc-content yue">
|
||||||
|
{@html htmlContent}
|
||||||
|
</div>
|
||||||
Reference in new issue
Block a user