diff --git a/components/content/ContentCode.vue b/components/content/ContentCode.vue index 942ef15a..b0647f53 100644 --- a/components/content/ContentCode.vue +++ b/components/content/ContentCode.vue @@ -4,7 +4,7 @@ const props = defineProps<{ lang: string }>() -const raw = computed(() => decodeURIComponent(props.code).replace(/'/g, '\'')) +const raw = $computed(() => decodeURIComponent(props.code).replace(/'/g, '\'')) const langMap: Record = { js: 'javascript', @@ -13,7 +13,7 @@ const langMap: Record = { } const hightlighted = computed(() => { - return highlightCode(raw.value, langMap[props.lang] || props.lang as any) + return props.lang ? highlightCode(raw, langMap[props.lang] || props.lang as any) : raw }) diff --git a/composables/content.ts b/composables/content.ts index d4857138..113ed3ef 100644 --- a/composables/content.ts +++ b/composables/content.ts @@ -4,6 +4,7 @@ import { parseFragment } from 'parse5' import type { Component, VNode } from 'vue' import { Fragment, h, isVNode } from 'vue' import { RouterLink } from 'vue-router' +import MarkdownIt from 'markdown-it' import ContentCode from '~/components/content/ContentCode.vue' type Node = DefaultTreeAdapterMap['childNode'] @@ -46,11 +47,17 @@ function handleNode(el: Element) { return handleBlocks(el) || handleMention(el) || el } +const md = new MarkdownIt() +md.renderer.rules.fence = (tokens, idx) => { + const token = tokens[idx] + return `\n` +} + export function contentToVNode( content: string, customEmojis: Record = {}, ): VNode { - content = content + content = md.render(htmlToText(content) .trim() // handle custom emojis .replace(/:([\w-]+?):/g, (_, name) => { @@ -58,13 +65,7 @@ export function contentToVNode( if (emoji) return `${name}` return `:${name}:` - }) - // handle code frames - .replace(/

(```|~~~)([\s\S]+?)\1/g, (_1, _2, raw) => { - const plain = htmlToText(`

${raw}

`).trim() - const [lang, ...rest] = plain.split(/\n/) - return `` - }) + })) const tree = parseFragment(content) return h(Fragment, tree.childNodes.map(n => treeToVNode(n))) diff --git a/package.json b/package.json index ce34d3d3..cf12ff64 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@tiptap/vue-3": "2.0.0-beta.203", "@types/fs-extra": "^9.0.13", "@types/js-yaml": "^4.0.5", + "@types/markdown-it": "^12.2.3", "@types/prettier": "^2.7.1", "@types/sanitize-html": "^2.6.2", "@types/wicg-file-system-access": "^2020.9.5", @@ -50,6 +51,7 @@ "fs-extra": "^10.1.0", "js-yaml": "^4.1.0", "lru-cache": "^7.14.1", + "markdown-it": "^13.0.1", "masto": "^4.6.8", "nuxt": "^3.0.0", "parse5": "^7.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc602de4..68e390f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,7 @@ specifiers: '@tiptap/vue-3': 2.0.0-beta.203 '@types/fs-extra': ^9.0.13 '@types/js-yaml': ^4.0.5 + '@types/markdown-it': ^12.2.3 '@types/prettier': ^2.7.1 '@types/sanitize-html': ^2.6.2 '@types/wicg-file-system-access': ^2020.9.5 @@ -35,6 +36,7 @@ specifiers: fs-extra: ^10.1.0 js-yaml: ^4.1.0 lru-cache: ^7.14.1 + markdown-it: ^13.0.1 masto: ^4.6.8 nuxt: ^3.0.0 parse5: ^7.1.2 @@ -70,6 +72,7 @@ devDependencies: '@tiptap/vue-3': 2.0.0-beta.203 '@types/fs-extra': 9.0.13 '@types/js-yaml': 4.0.5 + '@types/markdown-it': 12.2.3 '@types/prettier': 2.7.1 '@types/sanitize-html': 2.6.2 '@types/wicg-file-system-access': 2020.9.5 @@ -86,6 +89,7 @@ devDependencies: fs-extra: 10.1.0 js-yaml: 4.1.0 lru-cache: 7.14.1 + markdown-it: 13.0.1 masto: 4.6.8 nuxt: 3.0.0_hsf322ms6xhhd4b5ne6lb74y4a parse5: 7.1.2 @@ -1404,12 +1408,27 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/linkify-it/3.0.2: + resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==} + dev: true + + /@types/markdown-it/12.2.3: + resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==} + dependencies: + '@types/linkify-it': 3.0.2 + '@types/mdurl': 1.0.2 + dev: true + /@types/mdast/3.0.10: resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} dependencies: '@types/unist': 2.0.6 dev: true + /@types/mdurl/1.0.2: + resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} + dev: true + /@types/node/18.11.9: resolution: {integrity: sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==} dev: true @@ -3286,6 +3305,11 @@ packages: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} dev: true + /entities/3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + dev: true + /entities/4.4.0: resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} engines: {node: '>=0.12'} @@ -4968,6 +4992,12 @@ packages: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true + /linkify-it/4.0.1: + resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==} + dependencies: + uc.micro: 1.0.6 + dev: true + /listhen/1.0.0: resolution: {integrity: sha512-frdf7TVqT/JSHzRjEuo/vWIgbBYzEuY3oeTq8Yv1XkQVTKDPs2M4yotXICqYZYj2QxbkqKssSo8Wa6QCtBnFhg==} dependencies: @@ -5117,6 +5147,17 @@ packages: semver: 6.3.0 dev: true + /markdown-it/13.0.1: + resolution: {integrity: sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==} + hasBin: true + dependencies: + argparse: 2.0.1 + entities: 3.0.1 + linkify-it: 4.0.1 + mdurl: 1.0.1 + uc.micro: 1.0.6 + dev: true + /masto/4.6.8: resolution: {integrity: sha512-GCfOQX95WVzTuFPFXq+QTM8oD5et2Mh9veE5UmpwiD7kkMw7aLl1iXDQCDtgbSiyPmOONcs6UWKoFYp0k5hQjw==} dependencies: @@ -5157,6 +5198,10 @@ packages: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} dev: true + /mdurl/1.0.1: + resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + dev: true + /memory-fs/0.5.0: resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==} engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} @@ -7242,6 +7287,10 @@ packages: hasBin: true dev: true + /uc.micro/1.0.6: + resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + dev: true + /ufo/0.8.6: resolution: {integrity: sha512-fk6CmUgwKCfX79EzcDQQpSCMxrHstvbLswFChHS0Vump+kFkw7nJBfTZoC1j0bOGoY9I7R3n2DGek5ajbcYnOw==} dev: true