diff --git a/package-lock.json b/package-lock.json
index 0d0d333..d5ed463 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
"csstype": "^3.1.3",
"es-toolkit": "^1.27.0",
"form-data": "4.0.1",
+ "front-matter": "^4.0.2",
"highlight.js": "^11.10.0",
"juice": "^11.0.0",
"lucide-vue-next": "^0.462.0",
@@ -9217,6 +9218,19 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/esquery": {
"version": "1.6.0",
"resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.6.0.tgz",
@@ -9704,6 +9718,37 @@
"url": "https://github.com/sponsors/rawify"
}
},
+ "node_modules/front-matter": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz",
+ "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==",
+ "license": "MIT",
+ "dependencies": {
+ "js-yaml": "^3.13.1"
+ }
+ },
+ "node_modules/front-matter/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/front-matter/node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/fs-extra": {
"version": "11.2.0",
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.2.0.tgz",
@@ -16856,6 +16901,12 @@
"node": ">=6"
}
},
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/stable-hash": {
"version": "0.0.4",
"resolved": "https://registry.npmmirror.com/stable-hash/-/stable-hash-0.0.4.tgz",
diff --git a/package.json b/package.json
index 2091a78..9d6ec78 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
"csstype": "^3.1.3",
"es-toolkit": "^1.27.0",
"form-data": "4.0.1",
+ "front-matter": "^4.0.2",
"highlight.js": "^11.10.0",
"juice": "^11.0.0",
"lucide-vue-next": "^0.462.0",
diff --git a/src/config/theme.ts b/src/config/theme.ts
index a19583c..fe77818 100644
--- a/src/config/theme.ts
+++ b/src/config/theme.ts
@@ -206,12 +206,14 @@ const defaultTheme: Theme = {
hr: {
'border-style': `solid`,
- 'border-width': `1px 0 0`,
+ 'border-width': `2px 0 0`,
'border-color': `rgba(0,0,0,0.1)`,
'-webkit-transform-origin': `0 0`,
'-webkit-transform': `scale(1, 0.5)`,
'transform-origin': `0 0`,
'transform': `scale(1, 0.5)`,
+ 'height': `0.4em`,
+ 'margin': `1.5em 0`,
},
},
inline: {
diff --git a/src/stores/index.ts b/src/stores/index.ts
index 75b97d2..14351c5 100644
--- a/src/stores/index.ts
+++ b/src/stores/index.ts
@@ -179,7 +179,8 @@ export const useStore = defineStore(`store`, () => {
codeThemeChange()
renderer.reset({ citeStatus: isCiteStatus.value, legend: legend.value, isUseIndent: isUseIndent.value })
- let outputTemp = marked.parse(editor.value!.getValue()) as string
+ const { markdownContent } = renderer.parseFrontMatterAndContent(editor.value!.getValue())
+ let outputTemp = marked.parse(markdownContent) as string
// 去除第一行的 margin-top
outputTemp = outputTemp.replace(/(style=".*?)"/, `$1;margin-top: 0"`)
diff --git a/src/utils/renderer.ts b/src/utils/renderer.ts
index d461b36..75fa8d7 100644
--- a/src/utils/renderer.ts
+++ b/src/utils/renderer.ts
@@ -2,14 +2,18 @@ import type { ExtendedProperties, IOpts, ThemeStyles } from '@/types'
import type { PropertiesHyphen } from 'csstype'
import type { Renderer, RendererObject, Tokens } from 'marked'
import { cloneDeep, toMerged } from 'es-toolkit'
-import hljs from 'highlight.js'
+import frontMatter from 'front-matter'
+import hljs from 'highlight.js'
import { marked } from 'marked'
import mermaid from 'mermaid'
import { getStyleString } from '.'
import markedAlert from './MDAlert'
import { MDKatex } from './MDKatex'
+marked.setOptions({
+ breaks: true,
+})
marked.use(MDKatex({ nonStandard: true }))
function buildTheme({ theme: _theme, fonts, size, isUseIndent }: IOpts): ThemeStyles {
@@ -107,6 +111,19 @@ export function initRenderer(opts: IOpts) {
return getStyles(styleMapping, tag, addition)
}
+ function parseFrontMatterAndContent(markdownText: string) {
+ try {
+ const parsed = frontMatter(markdownText)
+ const yamlData = parsed.attributes
+ const markdownContent = parsed.body
+ return { yamlData, markdownContent }
+ }
+ catch (error) {
+ console.error(`Error parsing front-matter:`, error)
+ return { yamlData: {}, markdownContent: markdownText }
+ }
+ }
+
function styledContent(styleLabel: string, content: string, tagName?: string): string {
const tag = tagName ?? styleLabel
return `<${tag} ${styles(styleLabel)}>${content}${tag}>`
@@ -175,7 +192,7 @@ export function initRenderer(opts: IOpts) {
const language = hljs.getLanguage(langText) ? langText : `plaintext`
let highlighted = hljs.highlight(text, { language }).value
// tab to 4 spaces
- highlighted = highlighted.replace(/\t/g, ' ')
+ highlighted = highlighted.replace(/\t/g, ` `)
highlighted = highlighted
.replace(/\r\n/g, `
`)
.replace(/\n/g, `
`)
@@ -186,7 +203,8 @@ export function initRenderer(opts: IOpts) {
},
codespan({ text }: Tokens.Codespan): string {
- return styledContent(`codespan`, text, `code`)
+ const escapedText = text.replace(//g, `>`)
+ return styledContent(`codespan`, escapedText, `code`)
},
listitem(item: Tokens.ListItem): string {
@@ -276,6 +294,7 @@ export function initRenderer(opts: IOpts) {
buildFootnotes,
setOptions,
reset,
+ parseFrontMatterAndContent,
createContainer(content: string) {
return styledContent(`container`, content, `section`)
},