diff --git a/assets/scss/custom.scss b/assets/scss/custom.scss index 37dde29..0a70ee1 100644 --- a/assets/scss/custom.scss +++ b/assets/scss/custom.scss @@ -57,4 +57,10 @@ [data-scheme="dark"] .qr-code .qr-light { display: none; -} \ No newline at end of file +} + +pre.mermaid { + background-color: #272822 !important; + color: #f8f8f2 !important; +} + diff --git a/content/post/奇技淫巧/markdown渲染框架.md b/content/post/奇技淫巧/markdown渲染框架.md new file mode 100644 index 0000000..4b0093e --- /dev/null +++ b/content/post/奇技淫巧/markdown渲染框架.md @@ -0,0 +1,327 @@ +--- +title: 支持Vue自定义组件渲染的Markdown渲染框架实现 +description: NEU小站采用的支持Vue自定义组件渲染的Markdown渲染框架,基于Vue 3实现 +date: 2025-04-16 +# image: helena-hertz-wWZzXlDpMog-unsplash.jpg +categories: + - 奇技淫巧 +tags: [ + "Markdown", + "Vue", + "前端", + "NEU小站" +] +lastmod: 2025-04-17T01:00:00+08:00 + +--- +# 概述 +NEU小站的文章页Markdown渲染框架是一个基于 Vue 3 的组件,能把 Markdown 格式的文本渲染HTML,并且实现了增强功能——包括对特定自定义 Vue 组件(`` 和 ``)的渲染支持。此外,支持的标准功能包括数学公式(KaTeX)、代码高亮(highlight.js)以及图表(Mermaid)等,并且能自动生成可交互的目录 (TOC)。 + +本文重点介绍对2种裸文本**自定义组件标签**(`` 和 ``)的渲染实现。 + +## 效果 +### 裸文本(接口传参) +```markdown +> 标签:#可预览 #PDF #PPT #公路交通 #选修课 #通识选修 + +此处收录了《公路交通与驾驶技术》完整版PPT(文件内文字可复制、查找)。 + + + +``` +### 渲染效果 +[页面传送门](https://www.东北大学.com/article/68) + + + +# 技术方案 +由于渲染框架采用的基本渲染器是基于 `markdown-it` 的,但是 `markdown-it` 无法支持渲染自定义的 Vue 组件,所以需要对 `markdown-it` 的渲染规则进行重写。NEU小站采用的方案是,先让 `markdown-it` 解析 Markdown 文本,生成 Token 流,然后遍历 Token 流,对自定义组件标签进行特殊处理,生成占位符 div,最后用 VNode 渲染这些占位符 div,然后用HTML原生方法`replaceChild`替换掉原来的占位符 div。如下图所示: + +## pipeline 概览 +```mermaid +graph TD + A["输入 Markdown 字符串"] --> B["markdown-it 解析器"]; + B --> C["生成 Token 流"]; + C --> D["遍历 Token"]; + + subgraph "renderMarkdown" + D -- "html_block / html_inline (自定义标签)" --> E["generatePlaceholder 函数"]; + E -- "识别标签类型" --> F["调用 create...Placeholder"]; + F --> G["生成占位符 Div (含 data-*)"]; + + D -- "text Token" --> H["重写的 text 规则"]; + H -- "Regex 查找内联自定义标签" --> I["调用 create...Placeholder"]; + I --> G; + H -- "未匹配/普通文本" --> J["默认 text 渲染"]; + J --> K["HTML 片段"]; + + D -- "fence (Mermaid)" --> L["自定义 fence 规则: 生成 Mermaid 容器 Div"]; + L --> K; + + D -- "其他 Token (标题, 列表等)" --> M["默认渲染规则"]; + M --> K; + end + + G --> N["HTML 字符串 (含占位符)"]; + K --> N; + + N --> O["Vue 使用 v-html 渲染"]; + O --> P["DOM 中包含占位符 Div"]; + + P --> Q["mounted - nextTick"]; + + subgraph "Vue 组件挂载" + Q --> R["querySelectorAll 查找占位符"]; + R --> S["遍历占位符"]; + S --> T["读取 data-* 属性"]; + T --> U["h(Component, props) 创建 VNode"]; + U --> V["render(VNode, tempContainer) 渲染组件"]; + V --> W["DOM: replaceChild(真实组件, 占位符)"]; + end + + W --> X["最终渲染: HTML + 交互式 Vue 组件"]; +``` +## renderMarkdown 实现 +`renderMarkdown` 方法是 Markdown 处理的核心,它在支持其他 markdown 原生功能的基础上,增加了对自定义组件标签的渲染支持。我们分成下面几个部分: + +### 自定义组件占位符生成 + +我们编写了两个方法`createAttachmentPlaceholder`和`createCourseCardPlaceholder`,分别处理附件和课程卡片。 +* **输入:** 一个预期是完整自定义组件标签(如 ``)的字符串。 +* **逻辑:** 使用正则表达式从输入字符串中提取必要的属性(`id`, `size`, `type`, `filename`, `coin`, `locked` 是Attachment的属性; `id` 是CourseCard的属性)。 +* **输出:** 如果成功提取必要属性,返回一个包含 `data-*` 属性的 `
` 占位符 HTML 字符串;否则返回 `null`。 +```js +const createAttachmentPlaceholder = (tagString) => { + // 基本检查确保是 Attachment 标签 + if (!tagString || !tagString.trim().startsWith('
`; + } + + return null; // 必要属性缺失 +}; + +const createCourseCardPlaceholder = (tagString) => { + // 基本检查确保是 CourseCard 标签 + if (!tagString || !tagString.trim().startsWith(']*)/); + const id = idWithQuotes ? idWithQuotes[1] : (idWithoutQuotes ? idWithoutQuotes[1] : null); + + if (id) { + return `
`; + } + + return null; // ID 缺失 +}; +``` +然后我们需要在两种情形下调用上面的方法:独立HTML块、内联TEXT。 + +### 独立HTML块 +我们用`generatePlaceholder`方法来处理被 `markdown-it` 识别为独立 `html_block` 或 `html_inline` Token 的情况。 + +它会首先检查 `content` (即 Token 的内容) 是否以 ` { + const trimmedContent = content.trim(); + // Attachment 标签 + if (trimmedContent.startsWith('/); + if (tagMatch) { + // 调用函数 + const placeholder = createAttachmentPlaceholder(tagMatch[0]); + if (placeholder) return placeholder; + } + } + // CourseCard 标签 + if (trimmedContent.startsWith('/); + if (tagMatch) { + // 调用函数 + const placeholder = createCourseCardPlaceholder(tagMatch[0]); + if (placeholder) return placeholder; + } + } + return null; // 不是自定义标签或创建失败 +}; +``` +然后覆写`markdown-it`的`html-block`和`html-inline`规则: +```js +// 存储原始规则 + const defaultRenderText = md.renderer.rules.text || function(tokens, idx, options, env, self) { + return self.renderToken(tokens, idx, options, env, self); +}; +const defaultRenderHtmlInline = md.renderer.rules.html_inline || function(tokens, idx, options, env, self) { + return self.renderToken(tokens, idx, options, env, self); +}; +const defaultRenderHtmlBlock = md.renderer.rules.html_block || function(tokens, idx, options, env, self) { + return self.renderToken(tokens, idx, options, env, self); +}; + +// 覆写 html_inline 规则 +md.renderer.rules.html_inline = (tokens, idx, options, env, self) => { + const content = tokens[idx].content; + const placeholder = generatePlaceholder(content); + if (placeholder) { + return placeholder; + } + return defaultRenderHtmlInline(tokens, idx, options, env, self); +}; + +// 覆写 html_block 规则 +md.renderer.rules.html_block = (tokens, idx, options, env, self) => { + const content = tokens[idx].content; + const placeholder = generatePlaceholder(content); + if (placeholder) { + return placeholder; + } + return defaultRenderHtmlBlock(tokens, idx, options, env, self); +}; +``` + +### 内联TEXT +内联的情况相比独立HTML块要复杂一些,比如`abc`,`markdown-it` 会识别为`text` Token,而我们不能直接把整个`text` Token 传递给`create...Placeholder`函数,因为不是一个完整的自定义组件标签字符串。 + +因此,我们需要先找到``或``的完整标签字符串,然后再调用`create...Placeholder`生成占位符。大致步骤: + +* 获取 `text` Token 的内容 `content`。 +* 使用正则表达式(`attachmentRegex`, `courseCardRegex`)在 `content` 字符串中查找所有匹配的自定义标签。 +* 对于**每一个匹配到的标签字符串 (`match`)**,调用相应的 `create...Placeholder` 函数。 +* 如果 `create...Placeholder` 成功返回占位符,则使用 `String.prototype.replace` 将原始标签替换为占位符。 +```js +// 覆写 text 规则(处理文本中的标签,现在用特定创建器) +md.renderer.rules.text = (tokens, idx, options, env, self) => { + const token = tokens[idx]; + let content = token.content; + let replaced = false; + + // 处理 Attachment 标签 + const attachmentRegex = //g; // 使斜杠可选 + content = content.replace(attachmentRegex, (match) => { + // 调用复用函数 + const placeholder = createAttachmentPlaceholder(match); + if (placeholder) { + replaced = true; + return placeholder; + } + return match; // 如果占位符创建失败,返回原始匹配 + }); + + // 处理 CourseCard 标签 + const courseCardRegex = //g; // 使斜杠可选 + content = content.replace(courseCardRegex, (match) => { + // 调用复用函数 + const placeholder = createCourseCardPlaceholder(match); + if (placeholder) { + replaced = true; + return placeholder; + } + return match; // 如果占位符创建失败,返回原始匹配 + }); + + return replaced ? content : defaultRenderText(tokens, idx, options, env, self); +}; +``` +注意,很重要的一点:这里如果发生了替换,我们要**直接返回修改后的 `content` 字符串(包含 HTML 占位符)**,而不是调用默认的 `text` 渲染器,以防止占位符被转义。 + +完成三个逻辑后,就可以调用 `md.render(this.content)` 生成最终的 HTML 字符串,赋值给 `this.renderContent`,供 `v-html` 使用。 + +## Vue 组件挂载实现 +我们编写了`processAttachments` / `processCourseCards`两个方法,负责将 DOM 中的占位符替换为功能齐全的 Vue 组件。这两个方法在 `mounted` 钩子的 `nextTick` 中调用,因为此时 DOM 已经更新,可以安全地进行替换。逻辑总共有6步: +1. **查找:** 使用 `this.$refs.articleContent.querySelectorAll('.attachment-wrapper / .course-card-wrapper')` 获取所有占位符元素。 +2. **遍历:** 循环处理每一个找到的占位符 `wrapper`。 +3. **提取 Props:** 从 `wrapper.dataset` 中读取之前存入的 `data-*` 属性值。 +4. **创建 VNode:** 用 `h(Attachment/CourseCard, { prop1: value1, ... })` 创建组件的虚拟节点,将提取的值作为 `props` 传入。注意这里要进行必要的类型转换(如 `parseInt` 变成 `coin`,`locked` 变成布尔值)。 +5. **渲染组件:** 我们创建一个临时 `div` 容器 (`container`),调用 `render(vnode, container)` 将 VNode 渲染到这个临时容器中。此时 `container.firstChild` 就是真实渲染好的组件根 DOM 元素。 +6. **替换 DOM:** 最后用HTML原生方法 `wrapper.parentNode.replaceChild(container.firstChild, wrapper)` 将 DOM 中的占位符 `wrapper` 替换为渲染好的组件 `container.firstChild`。 +```js +processAttachments() { + const attachmentWrappers = this.$refs.articleContent.querySelectorAll('.attachment-wrapper'); + if (attachmentWrappers.length === 0) return; + + attachmentWrappers.forEach(wrapper => { + const id = wrapper.dataset.id; + const size = wrapper.dataset.size; + const type = wrapper.dataset.type; + const filename = wrapper.dataset.filename; + const coin = wrapper.dataset.coin; + const locked = wrapper.dataset.locked; + // 创建一个临时容器 + const container = document.createElement('div'); + + // 使用Vue 3的方式创建和渲染组件 + const vnode = h(Attachment, { + id, + size, + type, + coin: coin ? parseInt(coin) : null, + locked: locked === '1', + filename: filename + }); + + render(vnode, container); + + // 替换原始占位符 + wrapper.parentNode.replaceChild(container.firstChild, wrapper); + }); +}, +processCourseCards() { + if (!this.$refs.articleContent) return; + + const courseCardWrappers = this.$refs.articleContent.querySelectorAll('.course-card-wrapper'); + if (courseCardWrappers.length === 0) return; + + courseCardWrappers.forEach(wrapper => { + const courseId = wrapper.dataset.courseId; + if (!courseId) return; + + const container = document.createElement('div'); + + const vnode = h(CourseCard, { courseId }); + + render(vnode, container); + + wrapper.parentNode.replaceChild(container.firstChild, wrapper); + }); +}, +``` +然后在 `mounted` 钩子中调用: +```js +mounted() { + this.$nextTick(() => { + this.processAttachments(); + this.processCourseCards(); + }); +} +``` +这样一来,只要在组件中引入`Attachment`和`CourseCard`组件,框架就支持在Markdown中渲染出对应的组件。 + +# 总结 +我们采用了一种基于 `markdown-it` 规则重写、生成 HTML 占位符、再通过 `v-html` 渲染后手动查找并替换为 Vue 组件实例的策略,成功地在 Markdown 内容中嵌入了交互式 Vue 组件。这种方案巧妙地结合了 `markdown-it` 的扩展能力和 Vue 的组件系统,实现了灵活、个性化的 Markdown 渲染。 + + + + diff --git a/content/post/奇技淫巧/md-editor-v3.md b/content/post/奇技淫巧/md-editor-v3.md index 7fed499..3ac86bd 100644 --- a/content/post/奇技淫巧/md-editor-v3.md +++ b/content/post/奇技淫巧/md-editor-v3.md @@ -9,7 +9,8 @@ tags: [ "md-editor-v3", "Markdown", "Vue", - "前端" + "前端", + "NEU小站" ] lastmod: 2025-04-16T23:56:00+08:00 diff --git a/layouts/_default/_markup/render-codeblock-mermaid.html b/layouts/_default/_markup/render-codeblock-mermaid.html new file mode 100644 index 0000000..ae9501a --- /dev/null +++ b/layouts/_default/_markup/render-codeblock-mermaid.html @@ -0,0 +1,4 @@ +
+    {{ .Inner | htmlEscape | safeHTML }}
+  
+ {{ .Page.Store.Set "hasMermaid" true }} \ No newline at end of file diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html new file mode 100644 index 0000000..6897bca --- /dev/null +++ b/layouts/_default/baseof.html @@ -0,0 +1,38 @@ + + + + {{- partial "head/head.html" . -}} + {{- block "head" . -}}{{ end }} + + + {{- partial "head/colorScheme" . -}} + + {{/* The container is wider when there's any activated widget */}} + {{- $hasWidget := false -}} + {{- range .Site.Params.widgets -}} + {{- if gt (len .) 0 -}} + {{- $hasWidget = true -}} + {{- end -}} + {{- end -}} +
+ {{- block "left-sidebar" . -}} + {{ partial "sidebar/left.html" . }} + {{- end -}} + {{- block "right-sidebar" . -}}{{ end }} +
+ {{- block "main" . }}{{- end }} +
+
+ {{ partial "footer/include.html" . }} + {{ if .Store.Get "hasMermaid" }} + + {{ end }} + + diff --git a/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.content b/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.content index 6b13943..ecb56ae 100644 --- a/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.content +++ b/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.content @@ -7,4 +7,4 @@ * @description Tasty CSS-animated hamburgers * @author Jonathan Suh @jonsuh * @site https://jonsuh.com/hamburgers -* @link https://github.com/jonsuh/hamburgers*/.hamburger{padding-top:10px;display:inline-block;cursor:pointer;transition-property:opacity,filter;transition-duration:.15s;transition-timing-function:linear;font:inherit;color:inherit;text-transform:none;background-color:transparent;border:0;margin:0;overflow:visible}.hamburger:hover{opacity:.7}.hamburger.is-active:hover{opacity:.7}.hamburger.is-active .hamburger-inner,.hamburger.is-active .hamburger-inner::before,.hamburger.is-active .hamburger-inner::after{background-color:#000}.hamburger-box{width:30px;height:24px;display:inline-block;position:relative}.hamburger-inner{display:block;top:50%;margin-top:-2px}.hamburger-inner,.hamburger-inner::before,.hamburger-inner::after{width:30px;height:2px;background-color:var(--card-text-color-main);border-radius:4px;position:absolute;transition-property:transform;transition-duration:.15s;transition-timing-function:ease}.hamburger-inner::before,.hamburger-inner::after{content:"";display:block}.hamburger-inner::before{top:-10px}.hamburger-inner::after{bottom:-10px}.hamburger--spin .hamburger-inner{transition-duration:.22s;transition-timing-function:cubic-bezier(.55,.055,.675,.19)}.hamburger--spin .hamburger-inner::before{transition:top .1s .25s ease-in,opacity .1s ease-in}.hamburger--spin .hamburger-inner::after{transition:bottom .1s .25s ease-in,transform .22s cubic-bezier(.55,.055,.675,.19)}.hamburger--spin.is-active .hamburger-inner{transform:rotate(225deg);transition-delay:.12s;transition-timing-function:cubic-bezier(.215,.61,.355,1)}.hamburger--spin.is-active .hamburger-inner::before{top:0;opacity:0;transition:top .1s ease-out,opacity .1s .12s ease-out}.hamburger--spin.is-active .hamburger-inner::after{bottom:0;transform:rotate(-90deg);transition:bottom .1s ease-out,transform .22s .12s cubic-bezier(.215,.61,.355,1)}#toggle-menu{background:0 0;border:none;position:absolute;right:0;top:0;z-index:2;cursor:pointer;outline:none}[dir=rtl] #toggle-menu{left:0;right:auto}@media(min-width:768px){#toggle-menu{display:none}}#toggle-menu.is-active .hamburger-inner,#toggle-menu.is-active .hamburger-inner::before,#toggle-menu.is-active .hamburger-inner::after{background-color:var(--accent-color)}#main-menu{list-style:none;overflow-y:auto;flex-grow:1;font-size:1.4rem;background-color:var(--card-background);box-shadow:var(--shadow-l1);display:none;margin:0 calc(var(--container-padding) * -1);padding:30px}@media(min-width:1280px){#main-menu{padding:15px 0}}#main-menu,#main-menu .menu-bottom-section ol{flex-direction:column;gap:30px}@media(min-width:1280px){#main-menu,#main-menu .menu-bottom-section ol{gap:25px}}#main-menu.show{display:flex}@media(min-width:768px){#main-menu{align-items:flex-end;display:flex;background-color:transparent;padding:0;box-shadow:none;margin:0}}#main-menu li{position:relative;vertical-align:middle;padding:0}@media(min-width:768px){#main-menu li{width:100%}}#main-menu li svg{stroke:currentColor;stroke-width:1.33;width:20px;height:20px}#main-menu li a{height:100%;display:inline-flex;align-items:center;color:var(--body-text-color);gap:var(--menu-icon-separation)}#main-menu li span{flex:1}#main-menu li.current a{color:var(--accent-color);font-weight:700}#main-menu li.menu-bottom-section{margin-top:auto}#main-menu li.menu-bottom-section ol{display:flex;padding-left:0}.menu-social{list-style:none;padding:0;margin:0;display:flex;flex-direction:row;gap:10px}.menu-social svg{width:24px;height:24px;stroke:var(--body-text-color);stroke-width:1.33}.article-list{display:flex;flex-direction:column;gap:var(--section-separation)}.article-list article{display:flex;flex-direction:column;background-color:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--card-border-radius);overflow:hidden;transition:box-shadow .3s ease}.article-list article:hover{box-shadow:var(--shadow-l2)}.article-list article .article-image img{width:100%;height:150px;object-fit:cover}@media(min-width:768px){.article-list article .article-image img{height:200px}}@media(min-width:1280px){.article-list article .article-image img{height:250px}}.article-list article:nth-child(5n+1) .article-category a{background:#8ea885;color:#fff}.article-list article:nth-child(5n+2) .article-category a{background:#df7988;color:#fff}.article-list article:nth-child(5n+3) .article-category a{background:#0177b8;color:#fff}.article-list article:nth-child(5n+4) .article-category a{background:#ffb900;color:#fff}.article-list article:nth-child(5n+5) .article-category a{background:#6b69d6;color:#fff}.article-details{display:flex;flex-direction:column;justify-content:center;padding:var(--card-padding);gap:15px}.article-title{font-family:var(--article-font-family);font-weight:600;margin:0;color:var(--card-text-color-main);font-size:2.2rem}@media(min-width:1280px){.article-title{font-size:2.4rem}}.article-title a{color:var(--card-text-color-main)}.article-title a:hover{color:var(--card-text-color-main)}.article-subtitle{font-weight:400;color:var(--card-text-color-secondary);line-height:1.5;margin:0;font-size:1.75rem}@media(min-width:1280px){.article-subtitle{font-size:2rem}}.article-title-wrapper{display:flex;flex-direction:column;gap:8px}.article-time,.article-translations{display:flex;color:var(--card-text-color-tertiary);gap:15px}.article-time svg,.article-translations svg{vertical-align:middle;width:20px;height:20px;stroke-width:1.33;flex-shrink:0}.article-time time,.article-time a,.article-translations time,.article-translations a{font-size:1.4rem;color:var(--card-text-color-tertiary)}.article-time>div,.article-translations>div{display:inline-flex;align-items:center;gap:15px}.article-time{flex-wrap:wrap}.article-translations>div{flex-wrap:wrap}.article-category,.article-tags{display:flex;gap:10px;flex-wrap:wrap}.article-category a,.article-tags a{color:var(--accent-color-text);background-color:var(--accent-color);padding:8px 16px;border-radius:var(--tag-border-radius);display:inline-block;font-size:1.4rem;transition:background-color .5s ease}.article-category a:hover,.article-tags a:hover{color:var(--accent-color-text);background-color:var(--accent-color-darker)}.article-list--compact{border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);background-color:var(--card-background);--image-size:50px}@media(min-width:768px){.article-list--compact{--image-size:60px}}.article-list--compact article>a{display:flex;align-items:center;padding:var(--small-card-padding);gap:15px}.article-list--compact article:not(:last-of-type){border-bottom:1.5px solid var(--card-separator-color)}.article-list--compact article .article-details{flex-grow:1;padding:0;min-height:var(--image-size);gap:10px}.article-list--compact article .article-title{margin:0;font-size:1.6rem}@media(min-width:768px){.article-list--compact article .article-title{font-size:1.8rem}}.article-list--compact article .article-image img{width:var(--image-size);height:var(--image-size);object-fit:cover}.article-list--compact article .article-time{font-size:1.4rem}.article-list--compact article .article-preview{font-size:1.4rem;color:var(--card-text-color-tertiary);margin-top:10px;line-height:1.5}.article-list--tile article{border-radius:var(--card-border-radius);overflow:hidden;position:relative;height:350px;width:250px;box-shadow:var(--shadow-l1);transition:box-shadow .3s ease;background-color:var(--card-background)}.article-list--tile article:hover{box-shadow:var(--shadow-l2)}.article-list--tile article.has-image .article-details{background-color:rgba(0,0,0,.25)}.article-list--tile article.has-image .article-title{color:#fff}.article-list--tile article .article-image{position:absolute;top:0;left:0;width:100%;height:100%}.article-list--tile article .article-image img{width:100%;height:100%;object-fit:cover}.article-list--tile article .article-details{border-radius:var(--card-border-radius);position:relative;height:100%;width:100%;display:flex;flex-direction:column;justify-content:flex-end;z-index:2;padding:15px}@media(min-width:640px){.article-list--tile article .article-details{padding:20px}}.article-list--tile article .article-title{font-size:2rem;font-weight:500;color:var(--card-text-color-main)}@media(min-width:640px){.article-list--tile article .article-title{font-size:2.2rem}}.widget{display:flex;flex-direction:column}.widget .widget-icon svg{width:32px;height:32px;stroke-width:1.6;color:var(--body-text-color)}.tagCloud .tagCloud-tags{display:flex;flex-wrap:wrap;gap:10px}.tagCloud .tagCloud-tags a{background:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--tag-border-radius);padding:8px 20px;color:var(--card-text-color-main);font-size:1.4rem;transition:box-shadow .3s ease}.tagCloud .tagCloud-tags a:hover{box-shadow:var(--shadow-l2)}.widget.archives .widget-archive--list{border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);background-color:var(--card-background)}.widget.archives .archives-year:not(:last-of-type){border-bottom:1.5px solid var(--card-separator-color)}.widget.archives .archives-year a{font-size:1.4rem;padding:18px 25px;display:flex}.widget.archives .archives-year a span.year{flex:1;color:var(--card-text-color-main);font-weight:700}.widget.archives .archives-year a span.count{color:var(--card-text-color-tertiary)}footer.site-footer{padding:20px 0 var(--section-separation);font-size:1.4rem;line-height:1.75}footer.site-footer:before{content:"";display:block;height:3px;width:50px;background:var(--body-text-color);margin-bottom:20px}footer.site-footer .copyright{color:var(--accent-color);font-weight:700;margin-bottom:5px}footer.site-footer .powerby{color:var(--body-text-color);font-weight:400;font-size:1.2rem}footer.site-footer .powerby a{color:var(--body-text-color)}.pagination{display:flex;background-color:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--card-border-radius);overflow:hidden;flex-wrap:wrap}.pagination .page-link{padding:16px 32px;display:inline-flex;color:var(--card-text-color-secondary)}.pagination .page-link.current{font-weight:700;background-color:var(--card-background-selected);color:var(--card-text-color-main)}@media(min-width:768px){.sidebar.sticky{position:sticky}}.left-sidebar{display:flex;flex-direction:column;flex-shrink:0;align-self:stretch;gap:var(--sidebar-element-separation);max-width:none;width:100%;position:relative;--sidebar-avatar-size:100px;--sidebar-element-separation:20px;--emoji-size:40px;--emoji-font-size:20px}@media(min-width:768px){.left-sidebar{width:auto;padding-top:var(--main-top-padding);padding-bottom:var(--main-top-padding);max-height:100vh}}@media(min-width:1536px){.left-sidebar{--sidebar-avatar-size:120px;--sidebar-element-separation:25px;--emoji-size:40px}}.left-sidebar.sticky{top:0}.left-sidebar.compact{--sidebar-avatar-size:80px;--emoji-size:30px;--emoji-font-size:15px}@media(min-width:1024px){.left-sidebar.compact header{flex-direction:row}}.left-sidebar.compact header .site-meta{gap:5px}.left-sidebar.compact header .site-name{font-size:1.4rem}@media(min-width:1536px){.left-sidebar.compact header .site-name{font-size:1.75rem}}.left-sidebar.compact header .site-description{font-size:1.4rem}.right-sidebar{width:100%;display:none;flex-direction:column;gap:var(--widget-separation)}.right-sidebar.sticky{top:0}@media(min-width:1024px){.right-sidebar{padding-top:var(--main-top-padding);padding-bottom:var(--main-top-padding)}}.sidebar header{z-index:1;transition:box-shadow .5s ease;display:flex;flex-direction:column;gap:var(--sidebar-element-separation)}@media(min-width:768px){.sidebar header{padding:0}}.sidebar header .site-avatar{position:relative;margin:0;width:var(--sidebar-avatar-size);height:var(--sidebar-avatar-size);flex-shrink:0}.sidebar header .site-avatar .site-logo{width:100%;height:100%;border-radius:100%;box-shadow:var(--shadow-l1)}.sidebar header .site-avatar .emoji{position:absolute;width:var(--emoji-size);height:var(--emoji-size);line-height:var(--emoji-size);border-radius:100%;bottom:0;right:0;text-align:center;font-size:var(--emoji-font-size);background-color:var(--card-background);box-shadow:var(--shadow-l2)}.sidebar header .site-meta{display:flex;flex-direction:column;gap:10px;justify-content:center}.sidebar header .site-name{color:var(--accent-color);margin:0;font-size:1.6rem}@media(min-width:1536px){.sidebar header .site-name{font-size:1.8rem}}.sidebar header .site-description{color:var(--body-text-color);font-weight:400;margin:0;font-size:1.4rem}@media(min-width:1536px){.sidebar header .site-description{font-size:1.6rem}}[data-scheme=dark] #dark-mode-toggle{color:var(--accent-color);font-weight:700}[data-scheme=dark] #dark-mode-toggle .icon-tabler-toggle-left{display:none}[data-scheme=dark] #dark-mode-toggle .icon-tabler-toggle-right{display:unset}#dark-mode-toggle{margin-top:auto;color:var(--body-text-color);display:flex;align-items:center;cursor:pointer;gap:var(--menu-icon-separation)}#dark-mode-toggle .icon-tabler-toggle-right{display:none}#i18n-switch{color:var(--body-text-color);display:inline-flex;align-content:center;gap:var(--menu-icon-separation)}#i18n-switch select{border:0;background-color:transparent;color:var(--body-text-color)}#i18n-switch select option{color:var(--card-text-color-main);background-color:var(--card-background)}html{font-size:62.5%;overflow-y:scroll}*{box-sizing:border-box}body{background:var(--body-background);margin:0;font-family:var(--base-font-family);font-size:1.6rem;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*{scrollbar-width:auto;scrollbar-color:var(--scrollbar-thumb)transparent}::-webkit-scrollbar{height:auto}::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb)}::-webkit-scrollbar-track{background-color:transparent}.article-page.hide-sidebar-sm .left-sidebar{display:none}@media(min-width:768px){.article-page.hide-sidebar-sm .left-sidebar{display:inherit}}.article-page .main-article{background:var(--card-background);border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);overflow:hidden}.article-page .main-article .article-header .article-image img{height:auto;width:100%;max-height:50vh;object-fit:cover}.article-page .main-article .article-header .article-details{padding:var(--card-padding);padding-bottom:0}.article-page .main-article .article-content{margin:var(--card-padding)0;color:var(--card-text-color-main)}.article-page .main-article .article-content .footnotes{font-family:var(--base-font-family)}.article-page .main-article .article-content img{max-width:100%;height:auto}.article-page .main-article .article-footer{margin:var(--card-padding);margin-top:0}.article-page .main-article .article-footer section:not(:first-child){margin-top:var(--card-padding)}.article-page .main-article .article-footer section{color:var(--card-text-color-tertiary);text-transform:uppercase;display:flex;align-items:center;font-size:1.4rem;gap:15px}.article-page .main-article .article-footer section svg{width:20px;height:20px;stroke-width:1.33}.article-page .main-article .article-footer .article-tags{text-transform:unset}.article-page .main-article .article-footer .article-copyright a,.article-page .main-article .article-footer .article-lastmod a{color:var(--body-text-color)}.article-page .main-article .article-footer .article-copyright a.link,.article-page .main-article .article-footer .article-lastmod a.link{box-shadow:unset}.widget--toc{background-color:var(--card-background);border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);display:flex;flex-direction:column;color:var(--card-text-color-main);overflow:hidden}.widget--toc ::-webkit-scrollbar-thumb{background-color:var(--card-separator-color)}.widget--toc #TableOfContents{overflow-x:auto;max-height:75vh}.widget--toc #TableOfContents ol,.widget--toc #TableOfContents ul{margin:0;padding:0}.widget--toc #TableOfContents ol{list-style-type:none;counter-reset:item}.widget--toc #TableOfContents ol li a:first-of-type::before{counter-increment:item;content:counters(item,".")". ";font-weight:700;margin-right:5px}.widget--toc #TableOfContents>ul{padding:0 1em}.widget--toc #TableOfContents li{margin:15px 0 15px 20px;padding:5px}.widget--toc #TableOfContents li>ol,.widget--toc #TableOfContents li>ul{margin-top:10px;padding-left:10px;margin-bottom:-5px}.widget--toc #TableOfContents li>ol>li:last-child,.widget--toc #TableOfContents li>ul>li:last-child{margin-bottom:0}.widget--toc #TableOfContents li.active-class>a{border-left:var(--heading-border-size)solid var(--accent-color);font-weight:700}.widget--toc #TableOfContents ul li.active-class>a{display:block}.widget--toc #TableOfContents>ul>li.active-class>a{margin-left:calc(-25px - 1em);padding-left:calc(25px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li.active-class>a{margin-left:calc(-9px - 1em);padding-left:calc(9px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li.active-class>a{margin-left:calc(-60px - 1em);padding-left:calc(60px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li.active-class>a{margin-left:calc(-44px - 1em);padding-left:calc(44px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li>ul>li.active-class>a{margin-left:calc(-95px - 1em);padding-left:calc(95px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li>ol>li.active-class>a{margin-left:calc(-79px - 1em);padding-left:calc(79px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li>ul>li>ul>li.active-class>a{margin-left:calc(-130px - 1em);padding-left:calc(130px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li>ol>li>ol>li.active-class>a{margin-left:calc(-114px - 1em);padding-left:calc(114px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li>ul>li>ul>li>ul>li.active-class>a{margin-left:calc(-165px - 1em);padding-left:calc(165px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li>ol>li>ol>li>ol>li.active-class>a{margin-left:calc(-149px - 1em);padding-left:calc(149px + 1em - var(--heading-border-size));display:block}.related-content{overflow-x:auto;padding-bottom:15px}.related-content>.flex{float:left}.related-content article{margin-right:15px;flex-shrink:0;overflow:hidden;width:250px;height:150px}.related-content article .article-title{font-size:1.8rem;margin:0}.related-content article.has-image .article-details{padding:20px;background:linear-gradient(0deg,rgba(0,0,0,.25) 0%,rgba(0,0,0,.75) 100%)}.article-content{font-family:var(--article-font-family);font-size:var(--article-font-size);padding:0 var(--card-padding);line-height:var(--article-line-height)}.article-content>p{margin:1.5em 0}.article-content h1,.article-content h2,.article-content h3,.article-content h4,.article-content h5,.article-content h6{margin-inline-start:calc((var(--card-padding)) * -1);padding-inline-start:calc(var(--card-padding) - var(--heading-border-size));border-inline-start:var(--heading-border-size)solid var(--accent-color);position:relative}.article-content h1 a.header-anchor,.article-content h2 a.header-anchor,.article-content h3 a.header-anchor,.article-content h4 a.header-anchor,.article-content h5 a.header-anchor,.article-content h6 a.header-anchor{transition:opacity .3s ease;opacity:0;position:absolute;left:0;width:var(--card-padding);text-align:center;color:var(--accent-color)}.article-content h1 a.header-anchor:before,.article-content h2 a.header-anchor:before,.article-content h3 a.header-anchor:before,.article-content h4 a.header-anchor:before,.article-content h5 a.header-anchor:before,.article-content h6 a.header-anchor:before{content:"#"}.article-content h1:hover a.header-anchor,.article-content h1:focus a.header-anchor,.article-content h2:hover a.header-anchor,.article-content h2:focus a.header-anchor,.article-content h3:hover a.header-anchor,.article-content h3:focus a.header-anchor,.article-content h4:hover a.header-anchor,.article-content h4:focus a.header-anchor,.article-content h5:hover a.header-anchor,.article-content h5:focus a.header-anchor,.article-content h6:hover a.header-anchor,.article-content h6:focus a.header-anchor{opacity:1}.article-content figure{text-align:center}.article-content figure figcaption{font-size:1.4rem;color:var(--card-text-color-secondary)}.article-content blockquote{position:relative;margin:1.5em 0;border-inline-start:var(--blockquote-border-size)solid var(--card-separator-color);padding:15px calc(var(--card-padding) - var(--blockquote-border-size));background-color:var(--blockquote-background-color)}.article-content blockquote .cite{display:block;text-align:right;font-size:.75em}.article-content blockquote .cite a{text-decoration:underline}.article-content hr{width:100px;margin:40px auto;background:var(--card-text-color-tertiary);height:2px;border:0;opacity:.55}.article-content code{color:var(--code-text-color);background-color:var(--code-background-color);padding:2px 4px;border-radius:var(--tag-border-radius);font-family:var(--code-font-family)}.article-content a,.article-content code{word-break:break-word}.article-content .gallery{position:relative;display:flex;flex-direction:row;justify-content:center;margin:1.5em 0;gap:10px}.article-content .gallery figure{margin:0}.article-content pre{overflow-x:auto;display:block;background-color:var(--pre-background-color);color:var(--pre-text-color);font-family:var(--code-font-family);line-height:1.428571429;word-break:break-all;padding:var(--card-padding)}[dir=rtl] .article-content pre{direction:ltr}.article-content pre code{color:unset;border:none;background:0 0;padding:0}.article-content .highlight{background-color:#272822;padding:var(--card-padding);position:relative}.article-content .highlight:hover .copyCodeButton{opacity:1}[dir=rtl] .article-content .highlight{direction:ltr}.article-content .highlight pre{margin:initial;padding:0;margin:0;width:auto}.article-content .copyCodeButton{position:absolute;top:calc(var(--card-padding));right:calc(var(--card-padding));background:var(--card-background);border:none;box-shadow:var(--shadow-l2);border-radius:var(--tag-border-radius);padding:8px 16px;color:var(--card-text-color-main);cursor:pointer;font-size:14px;opacity:0;transition:opacity .3s ease}.article-content .table-wrapper{padding:0 var(--card-padding);overflow-x:auto;display:block}.article-content table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:1.5em;font-size:.96em}.article-content th,.article-content td{text-align:left;padding:4px 8px 4px 10px;border:1px solid var(--table-border-color)}.article-content td{vertical-align:top}.article-content tr:nth-child(even){background-color:var(--tr-even-background-color)}.article-content .twitter-tweet{color:var(--card-text-color-main)}.article-content .video-wrapper{position:relative;width:100%;height:0;padding-bottom:56.25%;overflow:hidden}.article-content .video-wrapper>iframe,.article-content .video-wrapper>video{position:absolute;width:100%;height:100%;left:0;top:0;border:0}.article-content .gitlab-embed-snippets{margin:0!important}.article-content .gitlab-embed-snippets .file-holder.snippet-file-content{margin-block-end:0!important;margin-block-start:0!important;margin-left:calc((var(--card-padding)) * -1)!important;margin-right:calc((var(--card-padding)) * -1)!important;padding:0 var(--card-padding)!important}.article-content blockquote,.article-content figure,.article-content .highlight,.article-content pre,.article-content .gallery,.article-content .video-wrapper,.article-content .table-wrapper,.article-content .s_video_simple{margin-left:calc((var(--card-padding)) * -1);margin-right:calc((var(--card-padding)) * -1);width:calc(100% + var(--card-padding) * 2)}.article-content .katex-display>.katex{overflow-x:auto;overflow-y:hidden}.article-content kbd{border:1px solid var(--kbd-border-color);font-weight:700;font-size:.9em;line-height:1;padding:2px 4px;border-radius:4px;display:inline-block}.section-card{border-radius:var(--card-border-radius);background-color:var(--card-background);padding:var(--small-card-padding);box-shadow:var(--shadow-l1);display:flex;align-items:center;gap:20px;--separation:15px}.section-card .section-term{font-size:2.2rem;margin:0;color:var(--card-text-color-main)}.section-card .section-description{font-weight:400;color:var(--card-text-color-secondary);font-size:1.6rem;margin:0}.section-card .section-details{flex-grow:1;display:flex;flex-direction:column;gap:8px}.section-card .section-image img{width:60px;height:60px}.section-card .section-count{color:var(--card-text-color-tertiary);font-size:1.4rem;margin:0;font-weight:700;text-transform:uppercase}.subsection-list{overflow-x:auto}.subsection-list .article-list--tile{display:flex;padding-bottom:15px}.subsection-list .article-list--tile article{width:250px;height:150px;margin-right:20px;flex-shrink:0}.subsection-list .article-list--tile article .article-title{margin:0;font-size:1.8rem}.subsection-list .article-list--tile article .article-details{padding:20px}.not-found-card{background-color:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--card-border-radius);padding:var(--card-padding)}.search-form{position:relative;--button-size:80px}.search-form.widget{--button-size:60px}.search-form.widget label{font-size:1.3rem;top:10px}.search-form.widget input{font-size:1.5rem;padding:30px 20px 15px}.search-form p{position:relative;margin:0}.search-form label{position:absolute;top:15px;inset-inline-start:20px;font-size:1.4rem;color:var(--card-text-color-tertiary)}.search-form input{padding:40px 20px 20px;border-radius:var(--card-border-radius);background-color:var(--card-background);box-shadow:var(--shadow-l1);color:var(--card-text-color-main);width:100%;border:0;-webkit-appearance:none;transition:box-shadow .3s ease;font-size:1.8rem}.search-form input:focus{outline:0;box-shadow:var(--shadow-l2)}.search-form button{position:absolute;inset-inline-end:0;top:0;height:100%;width:var(--button-size);cursor:pointer;background-color:transparent;border:0;padding:0 10px}.search-form button:focus{outline:0}.search-form button:focus svg{stroke-width:2;color:var(--accent-color)}.search-form button svg{color:var(--card-text-color-secondary);stroke-width:1.33;transition:all .3s ease;width:20px;height:20px}a{text-decoration:none;color:var(--accent-color)}a:hover{color:var(--accent-color-darker)}a.link{box-shadow:0 -2px rgba(var(--link-background-color),var(--link-background-opacity))inset;transition:all .3s ease}a.link:hover{box-shadow:0 calc(-1rem * var(--article-line-height))rgba(var(--link-background-color),var(--link-background-opacity-hover))inset}.section-title{text-transform:uppercase;margin-top:0;margin-bottom:10px;display:block;font-size:1.6rem;font-weight:700;color:var(--body-text-color)}.section-title a{color:var(--body-text-color)}.wechat-container{position:relative;cursor:pointer;z-index:1000}.wechat-icon{display:inline-block}.qr-code{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#fff;padding:8px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.1);opacity:0;visibility:hidden;transition:all .3s ease}.qr-code img{width:150px;height:150px;display:block}.wechat-container:hover .qr-code{opacity:1;visibility:visible}[data-scheme=dark] .qr-code{background:#3b2b33;box-shadow:0 2px 10px rgba(0,0,0,.5)}.qr-code .qr-dark{display:none}.qr-code .qr-light{display:block}[data-scheme=dark] .qr-code .qr-dark{display:block}[data-scheme=dark] .qr-code .qr-light{display:none} \ No newline at end of file +* @link https://github.com/jonsuh/hamburgers*/.hamburger{padding-top:10px;display:inline-block;cursor:pointer;transition-property:opacity,filter;transition-duration:.15s;transition-timing-function:linear;font:inherit;color:inherit;text-transform:none;background-color:transparent;border:0;margin:0;overflow:visible}.hamburger:hover{opacity:.7}.hamburger.is-active:hover{opacity:.7}.hamburger.is-active .hamburger-inner,.hamburger.is-active .hamburger-inner::before,.hamburger.is-active .hamburger-inner::after{background-color:#000}.hamburger-box{width:30px;height:24px;display:inline-block;position:relative}.hamburger-inner{display:block;top:50%;margin-top:-2px}.hamburger-inner,.hamburger-inner::before,.hamburger-inner::after{width:30px;height:2px;background-color:var(--card-text-color-main);border-radius:4px;position:absolute;transition-property:transform;transition-duration:.15s;transition-timing-function:ease}.hamburger-inner::before,.hamburger-inner::after{content:"";display:block}.hamburger-inner::before{top:-10px}.hamburger-inner::after{bottom:-10px}.hamburger--spin .hamburger-inner{transition-duration:.22s;transition-timing-function:cubic-bezier(.55,.055,.675,.19)}.hamburger--spin .hamburger-inner::before{transition:top .1s .25s ease-in,opacity .1s ease-in}.hamburger--spin .hamburger-inner::after{transition:bottom .1s .25s ease-in,transform .22s cubic-bezier(.55,.055,.675,.19)}.hamburger--spin.is-active .hamburger-inner{transform:rotate(225deg);transition-delay:.12s;transition-timing-function:cubic-bezier(.215,.61,.355,1)}.hamburger--spin.is-active .hamburger-inner::before{top:0;opacity:0;transition:top .1s ease-out,opacity .1s .12s ease-out}.hamburger--spin.is-active .hamburger-inner::after{bottom:0;transform:rotate(-90deg);transition:bottom .1s ease-out,transform .22s .12s cubic-bezier(.215,.61,.355,1)}#toggle-menu{background:0 0;border:none;position:absolute;right:0;top:0;z-index:2;cursor:pointer;outline:none}[dir=rtl] #toggle-menu{left:0;right:auto}@media(min-width:768px){#toggle-menu{display:none}}#toggle-menu.is-active .hamburger-inner,#toggle-menu.is-active .hamburger-inner::before,#toggle-menu.is-active .hamburger-inner::after{background-color:var(--accent-color)}#main-menu{list-style:none;overflow-y:auto;flex-grow:1;font-size:1.4rem;background-color:var(--card-background);box-shadow:var(--shadow-l1);display:none;margin:0 calc(var(--container-padding) * -1);padding:30px}@media(min-width:1280px){#main-menu{padding:15px 0}}#main-menu,#main-menu .menu-bottom-section ol{flex-direction:column;gap:30px}@media(min-width:1280px){#main-menu,#main-menu .menu-bottom-section ol{gap:25px}}#main-menu.show{display:flex}@media(min-width:768px){#main-menu{align-items:flex-end;display:flex;background-color:transparent;padding:0;box-shadow:none;margin:0}}#main-menu li{position:relative;vertical-align:middle;padding:0}@media(min-width:768px){#main-menu li{width:100%}}#main-menu li svg{stroke:currentColor;stroke-width:1.33;width:20px;height:20px}#main-menu li a{height:100%;display:inline-flex;align-items:center;color:var(--body-text-color);gap:var(--menu-icon-separation)}#main-menu li span{flex:1}#main-menu li.current a{color:var(--accent-color);font-weight:700}#main-menu li.menu-bottom-section{margin-top:auto}#main-menu li.menu-bottom-section ol{display:flex;padding-left:0}.menu-social{list-style:none;padding:0;margin:0;display:flex;flex-direction:row;gap:10px}.menu-social svg{width:24px;height:24px;stroke:var(--body-text-color);stroke-width:1.33}.article-list{display:flex;flex-direction:column;gap:var(--section-separation)}.article-list article{display:flex;flex-direction:column;background-color:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--card-border-radius);overflow:hidden;transition:box-shadow .3s ease}.article-list article:hover{box-shadow:var(--shadow-l2)}.article-list article .article-image img{width:100%;height:150px;object-fit:cover}@media(min-width:768px){.article-list article .article-image img{height:200px}}@media(min-width:1280px){.article-list article .article-image img{height:250px}}.article-list article:nth-child(5n+1) .article-category a{background:#8ea885;color:#fff}.article-list article:nth-child(5n+2) .article-category a{background:#df7988;color:#fff}.article-list article:nth-child(5n+3) .article-category a{background:#0177b8;color:#fff}.article-list article:nth-child(5n+4) .article-category a{background:#ffb900;color:#fff}.article-list article:nth-child(5n+5) .article-category a{background:#6b69d6;color:#fff}.article-details{display:flex;flex-direction:column;justify-content:center;padding:var(--card-padding);gap:15px}.article-title{font-family:var(--article-font-family);font-weight:600;margin:0;color:var(--card-text-color-main);font-size:2.2rem}@media(min-width:1280px){.article-title{font-size:2.4rem}}.article-title a{color:var(--card-text-color-main)}.article-title a:hover{color:var(--card-text-color-main)}.article-subtitle{font-weight:400;color:var(--card-text-color-secondary);line-height:1.5;margin:0;font-size:1.75rem}@media(min-width:1280px){.article-subtitle{font-size:2rem}}.article-title-wrapper{display:flex;flex-direction:column;gap:8px}.article-time,.article-translations{display:flex;color:var(--card-text-color-tertiary);gap:15px}.article-time svg,.article-translations svg{vertical-align:middle;width:20px;height:20px;stroke-width:1.33;flex-shrink:0}.article-time time,.article-time a,.article-translations time,.article-translations a{font-size:1.4rem;color:var(--card-text-color-tertiary)}.article-time>div,.article-translations>div{display:inline-flex;align-items:center;gap:15px}.article-time{flex-wrap:wrap}.article-translations>div{flex-wrap:wrap}.article-category,.article-tags{display:flex;gap:10px;flex-wrap:wrap}.article-category a,.article-tags a{color:var(--accent-color-text);background-color:var(--accent-color);padding:8px 16px;border-radius:var(--tag-border-radius);display:inline-block;font-size:1.4rem;transition:background-color .5s ease}.article-category a:hover,.article-tags a:hover{color:var(--accent-color-text);background-color:var(--accent-color-darker)}.article-list--compact{border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);background-color:var(--card-background);--image-size:50px}@media(min-width:768px){.article-list--compact{--image-size:60px}}.article-list--compact article>a{display:flex;align-items:center;padding:var(--small-card-padding);gap:15px}.article-list--compact article:not(:last-of-type){border-bottom:1.5px solid var(--card-separator-color)}.article-list--compact article .article-details{flex-grow:1;padding:0;min-height:var(--image-size);gap:10px}.article-list--compact article .article-title{margin:0;font-size:1.6rem}@media(min-width:768px){.article-list--compact article .article-title{font-size:1.8rem}}.article-list--compact article .article-image img{width:var(--image-size);height:var(--image-size);object-fit:cover}.article-list--compact article .article-time{font-size:1.4rem}.article-list--compact article .article-preview{font-size:1.4rem;color:var(--card-text-color-tertiary);margin-top:10px;line-height:1.5}.article-list--tile article{border-radius:var(--card-border-radius);overflow:hidden;position:relative;height:350px;width:250px;box-shadow:var(--shadow-l1);transition:box-shadow .3s ease;background-color:var(--card-background)}.article-list--tile article:hover{box-shadow:var(--shadow-l2)}.article-list--tile article.has-image .article-details{background-color:rgba(0,0,0,.25)}.article-list--tile article.has-image .article-title{color:#fff}.article-list--tile article .article-image{position:absolute;top:0;left:0;width:100%;height:100%}.article-list--tile article .article-image img{width:100%;height:100%;object-fit:cover}.article-list--tile article .article-details{border-radius:var(--card-border-radius);position:relative;height:100%;width:100%;display:flex;flex-direction:column;justify-content:flex-end;z-index:2;padding:15px}@media(min-width:640px){.article-list--tile article .article-details{padding:20px}}.article-list--tile article .article-title{font-size:2rem;font-weight:500;color:var(--card-text-color-main)}@media(min-width:640px){.article-list--tile article .article-title{font-size:2.2rem}}.widget{display:flex;flex-direction:column}.widget .widget-icon svg{width:32px;height:32px;stroke-width:1.6;color:var(--body-text-color)}.tagCloud .tagCloud-tags{display:flex;flex-wrap:wrap;gap:10px}.tagCloud .tagCloud-tags a{background:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--tag-border-radius);padding:8px 20px;color:var(--card-text-color-main);font-size:1.4rem;transition:box-shadow .3s ease}.tagCloud .tagCloud-tags a:hover{box-shadow:var(--shadow-l2)}.widget.archives .widget-archive--list{border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);background-color:var(--card-background)}.widget.archives .archives-year:not(:last-of-type){border-bottom:1.5px solid var(--card-separator-color)}.widget.archives .archives-year a{font-size:1.4rem;padding:18px 25px;display:flex}.widget.archives .archives-year a span.year{flex:1;color:var(--card-text-color-main);font-weight:700}.widget.archives .archives-year a span.count{color:var(--card-text-color-tertiary)}footer.site-footer{padding:20px 0 var(--section-separation);font-size:1.4rem;line-height:1.75}footer.site-footer:before{content:"";display:block;height:3px;width:50px;background:var(--body-text-color);margin-bottom:20px}footer.site-footer .copyright{color:var(--accent-color);font-weight:700;margin-bottom:5px}footer.site-footer .powerby{color:var(--body-text-color);font-weight:400;font-size:1.2rem}footer.site-footer .powerby a{color:var(--body-text-color)}.pagination{display:flex;background-color:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--card-border-radius);overflow:hidden;flex-wrap:wrap}.pagination .page-link{padding:16px 32px;display:inline-flex;color:var(--card-text-color-secondary)}.pagination .page-link.current{font-weight:700;background-color:var(--card-background-selected);color:var(--card-text-color-main)}@media(min-width:768px){.sidebar.sticky{position:sticky}}.left-sidebar{display:flex;flex-direction:column;flex-shrink:0;align-self:stretch;gap:var(--sidebar-element-separation);max-width:none;width:100%;position:relative;--sidebar-avatar-size:100px;--sidebar-element-separation:20px;--emoji-size:40px;--emoji-font-size:20px}@media(min-width:768px){.left-sidebar{width:auto;padding-top:var(--main-top-padding);padding-bottom:var(--main-top-padding);max-height:100vh}}@media(min-width:1536px){.left-sidebar{--sidebar-avatar-size:120px;--sidebar-element-separation:25px;--emoji-size:40px}}.left-sidebar.sticky{top:0}.left-sidebar.compact{--sidebar-avatar-size:80px;--emoji-size:30px;--emoji-font-size:15px}@media(min-width:1024px){.left-sidebar.compact header{flex-direction:row}}.left-sidebar.compact header .site-meta{gap:5px}.left-sidebar.compact header .site-name{font-size:1.4rem}@media(min-width:1536px){.left-sidebar.compact header .site-name{font-size:1.75rem}}.left-sidebar.compact header .site-description{font-size:1.4rem}.right-sidebar{width:100%;display:none;flex-direction:column;gap:var(--widget-separation)}.right-sidebar.sticky{top:0}@media(min-width:1024px){.right-sidebar{padding-top:var(--main-top-padding);padding-bottom:var(--main-top-padding)}}.sidebar header{z-index:1;transition:box-shadow .5s ease;display:flex;flex-direction:column;gap:var(--sidebar-element-separation)}@media(min-width:768px){.sidebar header{padding:0}}.sidebar header .site-avatar{position:relative;margin:0;width:var(--sidebar-avatar-size);height:var(--sidebar-avatar-size);flex-shrink:0}.sidebar header .site-avatar .site-logo{width:100%;height:100%;border-radius:100%;box-shadow:var(--shadow-l1)}.sidebar header .site-avatar .emoji{position:absolute;width:var(--emoji-size);height:var(--emoji-size);line-height:var(--emoji-size);border-radius:100%;bottom:0;right:0;text-align:center;font-size:var(--emoji-font-size);background-color:var(--card-background);box-shadow:var(--shadow-l2)}.sidebar header .site-meta{display:flex;flex-direction:column;gap:10px;justify-content:center}.sidebar header .site-name{color:var(--accent-color);margin:0;font-size:1.6rem}@media(min-width:1536px){.sidebar header .site-name{font-size:1.8rem}}.sidebar header .site-description{color:var(--body-text-color);font-weight:400;margin:0;font-size:1.4rem}@media(min-width:1536px){.sidebar header .site-description{font-size:1.6rem}}[data-scheme=dark] #dark-mode-toggle{color:var(--accent-color);font-weight:700}[data-scheme=dark] #dark-mode-toggle .icon-tabler-toggle-left{display:none}[data-scheme=dark] #dark-mode-toggle .icon-tabler-toggle-right{display:unset}#dark-mode-toggle{margin-top:auto;color:var(--body-text-color);display:flex;align-items:center;cursor:pointer;gap:var(--menu-icon-separation)}#dark-mode-toggle .icon-tabler-toggle-right{display:none}#i18n-switch{color:var(--body-text-color);display:inline-flex;align-content:center;gap:var(--menu-icon-separation)}#i18n-switch select{border:0;background-color:transparent;color:var(--body-text-color)}#i18n-switch select option{color:var(--card-text-color-main);background-color:var(--card-background)}html{font-size:62.5%;overflow-y:scroll}*{box-sizing:border-box}body{background:var(--body-background);margin:0;font-family:var(--base-font-family);font-size:1.6rem;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*{scrollbar-width:auto;scrollbar-color:var(--scrollbar-thumb)transparent}::-webkit-scrollbar{height:auto}::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb)}::-webkit-scrollbar-track{background-color:transparent}.article-page.hide-sidebar-sm .left-sidebar{display:none}@media(min-width:768px){.article-page.hide-sidebar-sm .left-sidebar{display:inherit}}.article-page .main-article{background:var(--card-background);border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);overflow:hidden}.article-page .main-article .article-header .article-image img{height:auto;width:100%;max-height:50vh;object-fit:cover}.article-page .main-article .article-header .article-details{padding:var(--card-padding);padding-bottom:0}.article-page .main-article .article-content{margin:var(--card-padding)0;color:var(--card-text-color-main)}.article-page .main-article .article-content .footnotes{font-family:var(--base-font-family)}.article-page .main-article .article-content img{max-width:100%;height:auto}.article-page .main-article .article-footer{margin:var(--card-padding);margin-top:0}.article-page .main-article .article-footer section:not(:first-child){margin-top:var(--card-padding)}.article-page .main-article .article-footer section{color:var(--card-text-color-tertiary);text-transform:uppercase;display:flex;align-items:center;font-size:1.4rem;gap:15px}.article-page .main-article .article-footer section svg{width:20px;height:20px;stroke-width:1.33}.article-page .main-article .article-footer .article-tags{text-transform:unset}.article-page .main-article .article-footer .article-copyright a,.article-page .main-article .article-footer .article-lastmod a{color:var(--body-text-color)}.article-page .main-article .article-footer .article-copyright a.link,.article-page .main-article .article-footer .article-lastmod a.link{box-shadow:unset}.widget--toc{background-color:var(--card-background);border-radius:var(--card-border-radius);box-shadow:var(--shadow-l1);display:flex;flex-direction:column;color:var(--card-text-color-main);overflow:hidden}.widget--toc ::-webkit-scrollbar-thumb{background-color:var(--card-separator-color)}.widget--toc #TableOfContents{overflow-x:auto;max-height:75vh}.widget--toc #TableOfContents ol,.widget--toc #TableOfContents ul{margin:0;padding:0}.widget--toc #TableOfContents ol{list-style-type:none;counter-reset:item}.widget--toc #TableOfContents ol li a:first-of-type::before{counter-increment:item;content:counters(item,".")". ";font-weight:700;margin-right:5px}.widget--toc #TableOfContents>ul{padding:0 1em}.widget--toc #TableOfContents li{margin:15px 0 15px 20px;padding:5px}.widget--toc #TableOfContents li>ol,.widget--toc #TableOfContents li>ul{margin-top:10px;padding-left:10px;margin-bottom:-5px}.widget--toc #TableOfContents li>ol>li:last-child,.widget--toc #TableOfContents li>ul>li:last-child{margin-bottom:0}.widget--toc #TableOfContents li.active-class>a{border-left:var(--heading-border-size)solid var(--accent-color);font-weight:700}.widget--toc #TableOfContents ul li.active-class>a{display:block}.widget--toc #TableOfContents>ul>li.active-class>a{margin-left:calc(-25px - 1em);padding-left:calc(25px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li.active-class>a{margin-left:calc(-9px - 1em);padding-left:calc(9px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li.active-class>a{margin-left:calc(-60px - 1em);padding-left:calc(60px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li.active-class>a{margin-left:calc(-44px - 1em);padding-left:calc(44px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li>ul>li.active-class>a{margin-left:calc(-95px - 1em);padding-left:calc(95px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li>ol>li.active-class>a{margin-left:calc(-79px - 1em);padding-left:calc(79px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li>ul>li>ul>li.active-class>a{margin-left:calc(-130px - 1em);padding-left:calc(130px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li>ol>li>ol>li.active-class>a{margin-left:calc(-114px - 1em);padding-left:calc(114px + 1em - var(--heading-border-size));display:block}.widget--toc #TableOfContents>ul>li>ul>li>ul>li>ul>li>ul>li.active-class>a{margin-left:calc(-165px - 1em);padding-left:calc(165px + 1em - var(--heading-border-size))}.widget--toc #TableOfContents>ol>li>ol>li>ol>li>ol>li>ol>li.active-class>a{margin-left:calc(-149px - 1em);padding-left:calc(149px + 1em - var(--heading-border-size));display:block}.related-content{overflow-x:auto;padding-bottom:15px}.related-content>.flex{float:left}.related-content article{margin-right:15px;flex-shrink:0;overflow:hidden;width:250px;height:150px}.related-content article .article-title{font-size:1.8rem;margin:0}.related-content article.has-image .article-details{padding:20px;background:linear-gradient(0deg,rgba(0,0,0,.25) 0%,rgba(0,0,0,.75) 100%)}.article-content{font-family:var(--article-font-family);font-size:var(--article-font-size);padding:0 var(--card-padding);line-height:var(--article-line-height)}.article-content>p{margin:1.5em 0}.article-content h1,.article-content h2,.article-content h3,.article-content h4,.article-content h5,.article-content h6{margin-inline-start:calc((var(--card-padding)) * -1);padding-inline-start:calc(var(--card-padding) - var(--heading-border-size));border-inline-start:var(--heading-border-size)solid var(--accent-color);position:relative}.article-content h1 a.header-anchor,.article-content h2 a.header-anchor,.article-content h3 a.header-anchor,.article-content h4 a.header-anchor,.article-content h5 a.header-anchor,.article-content h6 a.header-anchor{transition:opacity .3s ease;opacity:0;position:absolute;left:0;width:var(--card-padding);text-align:center;color:var(--accent-color)}.article-content h1 a.header-anchor:before,.article-content h2 a.header-anchor:before,.article-content h3 a.header-anchor:before,.article-content h4 a.header-anchor:before,.article-content h5 a.header-anchor:before,.article-content h6 a.header-anchor:before{content:"#"}.article-content h1:hover a.header-anchor,.article-content h1:focus a.header-anchor,.article-content h2:hover a.header-anchor,.article-content h2:focus a.header-anchor,.article-content h3:hover a.header-anchor,.article-content h3:focus a.header-anchor,.article-content h4:hover a.header-anchor,.article-content h4:focus a.header-anchor,.article-content h5:hover a.header-anchor,.article-content h5:focus a.header-anchor,.article-content h6:hover a.header-anchor,.article-content h6:focus a.header-anchor{opacity:1}.article-content figure{text-align:center}.article-content figure figcaption{font-size:1.4rem;color:var(--card-text-color-secondary)}.article-content blockquote{position:relative;margin:1.5em 0;border-inline-start:var(--blockquote-border-size)solid var(--card-separator-color);padding:15px calc(var(--card-padding) - var(--blockquote-border-size));background-color:var(--blockquote-background-color)}.article-content blockquote .cite{display:block;text-align:right;font-size:.75em}.article-content blockquote .cite a{text-decoration:underline}.article-content hr{width:100px;margin:40px auto;background:var(--card-text-color-tertiary);height:2px;border:0;opacity:.55}.article-content code{color:var(--code-text-color);background-color:var(--code-background-color);padding:2px 4px;border-radius:var(--tag-border-radius);font-family:var(--code-font-family)}.article-content a,.article-content code{word-break:break-word}.article-content .gallery{position:relative;display:flex;flex-direction:row;justify-content:center;margin:1.5em 0;gap:10px}.article-content .gallery figure{margin:0}.article-content pre{overflow-x:auto;display:block;background-color:var(--pre-background-color);color:var(--pre-text-color);font-family:var(--code-font-family);line-height:1.428571429;word-break:break-all;padding:var(--card-padding)}[dir=rtl] .article-content pre{direction:ltr}.article-content pre code{color:unset;border:none;background:0 0;padding:0}.article-content .highlight{background-color:#272822;padding:var(--card-padding);position:relative}.article-content .highlight:hover .copyCodeButton{opacity:1}[dir=rtl] .article-content .highlight{direction:ltr}.article-content .highlight pre{margin:initial;padding:0;margin:0;width:auto}.article-content .copyCodeButton{position:absolute;top:calc(var(--card-padding));right:calc(var(--card-padding));background:var(--card-background);border:none;box-shadow:var(--shadow-l2);border-radius:var(--tag-border-radius);padding:8px 16px;color:var(--card-text-color-main);cursor:pointer;font-size:14px;opacity:0;transition:opacity .3s ease}.article-content .table-wrapper{padding:0 var(--card-padding);overflow-x:auto;display:block}.article-content table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:1.5em;font-size:.96em}.article-content th,.article-content td{text-align:left;padding:4px 8px 4px 10px;border:1px solid var(--table-border-color)}.article-content td{vertical-align:top}.article-content tr:nth-child(even){background-color:var(--tr-even-background-color)}.article-content .twitter-tweet{color:var(--card-text-color-main)}.article-content .video-wrapper{position:relative;width:100%;height:0;padding-bottom:56.25%;overflow:hidden}.article-content .video-wrapper>iframe,.article-content .video-wrapper>video{position:absolute;width:100%;height:100%;left:0;top:0;border:0}.article-content .gitlab-embed-snippets{margin:0!important}.article-content .gitlab-embed-snippets .file-holder.snippet-file-content{margin-block-end:0!important;margin-block-start:0!important;margin-left:calc((var(--card-padding)) * -1)!important;margin-right:calc((var(--card-padding)) * -1)!important;padding:0 var(--card-padding)!important}.article-content blockquote,.article-content figure,.article-content .highlight,.article-content pre,.article-content .gallery,.article-content .video-wrapper,.article-content .table-wrapper,.article-content .s_video_simple{margin-left:calc((var(--card-padding)) * -1);margin-right:calc((var(--card-padding)) * -1);width:calc(100% + var(--card-padding) * 2)}.article-content .katex-display>.katex{overflow-x:auto;overflow-y:hidden}.article-content kbd{border:1px solid var(--kbd-border-color);font-weight:700;font-size:.9em;line-height:1;padding:2px 4px;border-radius:4px;display:inline-block}.section-card{border-radius:var(--card-border-radius);background-color:var(--card-background);padding:var(--small-card-padding);box-shadow:var(--shadow-l1);display:flex;align-items:center;gap:20px;--separation:15px}.section-card .section-term{font-size:2.2rem;margin:0;color:var(--card-text-color-main)}.section-card .section-description{font-weight:400;color:var(--card-text-color-secondary);font-size:1.6rem;margin:0}.section-card .section-details{flex-grow:1;display:flex;flex-direction:column;gap:8px}.section-card .section-image img{width:60px;height:60px}.section-card .section-count{color:var(--card-text-color-tertiary);font-size:1.4rem;margin:0;font-weight:700;text-transform:uppercase}.subsection-list{overflow-x:auto}.subsection-list .article-list--tile{display:flex;padding-bottom:15px}.subsection-list .article-list--tile article{width:250px;height:150px;margin-right:20px;flex-shrink:0}.subsection-list .article-list--tile article .article-title{margin:0;font-size:1.8rem}.subsection-list .article-list--tile article .article-details{padding:20px}.not-found-card{background-color:var(--card-background);box-shadow:var(--shadow-l1);border-radius:var(--card-border-radius);padding:var(--card-padding)}.search-form{position:relative;--button-size:80px}.search-form.widget{--button-size:60px}.search-form.widget label{font-size:1.3rem;top:10px}.search-form.widget input{font-size:1.5rem;padding:30px 20px 15px}.search-form p{position:relative;margin:0}.search-form label{position:absolute;top:15px;inset-inline-start:20px;font-size:1.4rem;color:var(--card-text-color-tertiary)}.search-form input{padding:40px 20px 20px;border-radius:var(--card-border-radius);background-color:var(--card-background);box-shadow:var(--shadow-l1);color:var(--card-text-color-main);width:100%;border:0;-webkit-appearance:none;transition:box-shadow .3s ease;font-size:1.8rem}.search-form input:focus{outline:0;box-shadow:var(--shadow-l2)}.search-form button{position:absolute;inset-inline-end:0;top:0;height:100%;width:var(--button-size);cursor:pointer;background-color:transparent;border:0;padding:0 10px}.search-form button:focus{outline:0}.search-form button:focus svg{stroke-width:2;color:var(--accent-color)}.search-form button svg{color:var(--card-text-color-secondary);stroke-width:1.33;transition:all .3s ease;width:20px;height:20px}a{text-decoration:none;color:var(--accent-color)}a:hover{color:var(--accent-color-darker)}a.link{box-shadow:0 -2px rgba(var(--link-background-color),var(--link-background-opacity))inset;transition:all .3s ease}a.link:hover{box-shadow:0 calc(-1rem * var(--article-line-height))rgba(var(--link-background-color),var(--link-background-opacity-hover))inset}.section-title{text-transform:uppercase;margin-top:0;margin-bottom:10px;display:block;font-size:1.6rem;font-weight:700;color:var(--body-text-color)}.section-title a{color:var(--body-text-color)}.wechat-container{position:relative;cursor:pointer;z-index:1000}.wechat-icon{display:inline-block}.qr-code{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#fff;padding:8px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.1);opacity:0;visibility:hidden;transition:all .3s ease}.qr-code img{width:150px;height:150px;display:block}.wechat-container:hover .qr-code{opacity:1;visibility:visible}[data-scheme=dark] .qr-code{background:#3b2b33;box-shadow:0 2px 10px rgba(0,0,0,.5)}.qr-code .qr-dark{display:none}.qr-code .qr-light{display:block}[data-scheme=dark] .qr-code .qr-dark{display:block}[data-scheme=dark] .qr-code .qr-light{display:none}pre.mermaid{background-color:#272822!important;color:#f8f8f2!important} \ No newline at end of file diff --git a/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.json b/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.json index 8313c18..27addb6 100644 --- a/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.json +++ b/resources/_gen/assets/scss/style.scss_77b10c8e87ff110a62c52933fe3f7f11.json @@ -1 +1 @@ -{"Target":"/scss/style.min.40e8155bfa2ddbd9e7a0338c33847e7ec9ee952ac6ee30bee252df13a7ac714d.css","MediaType":"text/css","Data":{"Integrity":"sha256-QOgVW/ot29nnoDOMM4R+fsnulSrG7jC+4lLfE6escU0="}} \ No newline at end of file +{"Target":"/scss/style.min.a1cd0aa92bcdacc5606ab6113ea9b3fc8d223f6bb51ee5b385c5ea79581d28c0.css","MediaType":"text/css","Data":{"Integrity":"sha256-oc0KqSvNrMVgarYRPqmz/I0iP2u1HuWzhcXqeVgdKMA="}} \ No newline at end of file