feat(docs): highlight code block

This commit is contained in:
zhangmo8 2024-10-25 17:58:52 +08:00
parent d143272fb8
commit c9b5dc14db
7 changed files with 112 additions and 30 deletions

View File

@ -4,7 +4,6 @@ import autoprefixer from 'autoprefixer'
import tailwind from 'tailwindcss' import tailwind from 'tailwindcss'
import Icons from 'unplugin-icons/vite' import Icons from 'unplugin-icons/vite'
import { defineConfig } from 'vitepress' import { defineConfig } from 'vitepress'
import { cssVariables } from './theme/config/shiki'
import { siteConfig } from './theme/config/site' import { siteConfig } from './theme/config/site'
import CodeWrapperPlugin from './theme/plugins/codewrapper' import CodeWrapperPlugin from './theme/plugins/codewrapper'
@ -31,7 +30,6 @@ export default defineConfig({
['meta', { name: 'og:site_name', content: siteConfig.name }], ['meta', { name: 'og:site_name', content: siteConfig.name }],
['meta', { name: 'og:image', content: siteConfig.ogImage }], ['meta', { name: 'og:image', content: siteConfig.ogImage }],
['meta', { name: 'twitter:image', content: siteConfig.ogImage }], ['meta', { name: 'twitter:image', content: siteConfig.ogImage }],
], ],
sitemap: { sitemap: {
@ -58,7 +56,6 @@ export default defineConfig({
srcDir: path.resolve(__dirname, '../src'), srcDir: path.resolve(__dirname, '../src'),
markdown: { markdown: {
theme: cssVariables,
codeTransformers: [ codeTransformers: [
transformerMetaWordHighlight(), transformerMetaWordHighlight(),
], ],

View File

@ -2,10 +2,9 @@
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { CircleHelp, Info, Monitor, Smartphone, Tablet } from 'lucide-vue-next' import { CircleHelp, Info, Monitor, Smartphone, Tablet } from 'lucide-vue-next'
import MagicString from 'magic-string' import MagicString from 'magic-string'
import { codeToHtml } from 'shiki'
import { reactive, ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { compileScript, parse, walk } from 'vue/compiler-sfc' import { compileScript, parse, walk } from 'vue/compiler-sfc'
import { cssVariables } from '../config/shiki' import { highlight } from '../config/shiki'
import BlockCopyButton from './BlockCopyButton.vue' import BlockCopyButton from './BlockCopyButton.vue'
import Spinner from './Spinner.vue' import Spinner from './Spinner.vue'
import StyleSwitcher from './StyleSwitcher.vue' import StyleSwitcher from './StyleSwitcher.vue'
@ -79,10 +78,7 @@ watch([style, codeConfig], async () => {
}) })
} }
codeHtml.value = await codeToHtml(rawString.value, { codeHtml.value = highlight(rawString.value, 'vue')
lang: 'vue',
theme: cssVariables,
})
} }
catch (err) { catch (err) {
console.error(err) console.error(err)

View File

@ -4,9 +4,8 @@ import { cn } from '@/lib/utils'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { useClipboard } from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import MagicString from 'magic-string' import MagicString from 'magic-string'
import { codeToHtml } from 'shiki'
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { cssVariables } from '../config/shiki' import { highlight } from '../config/shiki'
import CodeSandbox from './CodeSandbox.vue' import CodeSandbox from './CodeSandbox.vue'
import ComponentLoader from './ComponentLoader.vue' import ComponentLoader from './ComponentLoader.vue'
import Stackblitz from './Stackblitz.vue' import Stackblitz from './Stackblitz.vue'
@ -37,10 +36,7 @@ function transformImportPath(code: string) {
watch([style, codeConfig], async () => { watch([style, codeConfig], async () => {
try { try {
rawString.value = await import(`../../../src/lib/registry/${style.value}/example/${props.name}.vue?raw`).then(res => res.default.trim()) rawString.value = await import(`../../../src/lib/registry/${style.value}/example/${props.name}.vue?raw`).then(res => res.default.trim())
codeHtml.value = await codeToHtml(transformedRawString.value, { codeHtml.value = highlight(transformedRawString.value, 'vue')
lang: 'vue',
theme: cssVariables,
})
} }
catch (err) { catch (err) {
console.error(err) console.error(err)

View File

@ -1,6 +1,41 @@
import { createCssVariablesTheme } from 'shiki' import type { HighlighterCore } from 'shiki/core'
import type { ThemeOptions } from 'vitepress'
import { computedAsync } from '@vueuse/core'
import { createHighlighterCore } from 'shiki/core'
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript'
export const cssVariables = createCssVariablesTheme({ export const shikiThemes: ThemeOptions = {
variablePrefix: '--shiki-', light: 'vitesse-light',
variableDefaults: {}, dark: 'vitesse-dark',
}
export const highlighter = computedAsync<HighlighterCore>(async (onCancel) => {
const shiki = await createHighlighterCore({
engine: createJavaScriptRegexEngine(),
themes: [
() => import('shiki/themes/vitesse-dark.mjs'),
() => import('shiki/themes/vitesse-light.mjs'),
],
langs: [
() => import('shiki/langs/javascript.mjs'),
() => import('shiki/langs/vue.mjs'),
],
})
onCancel(() => shiki?.dispose())
return shiki
}) })
export function highlight(code: string, lang: string) {
if (!highlighter.value)
return code
return highlighter.value.codeToHtml(code, {
lang,
defaultColor: false,
themes: {
dark: 'vitesse-dark',
light: 'vitesse-light',
},
})
}

View File

@ -121,6 +121,15 @@
scrollbar-color: hsl(215.4 16.3% 56.9% / 0.3); scrollbar-color: hsl(215.4 16.3% 56.9% / 0.3);
} }
html.dark .shiki,
html.dark .shiki span {
color: var(--shiki-dark);
}
html:not(.dark) .shiki,
html:not(.dark) .shiki span {
color: var(--shiki-light);
}
.hide-scrollbar::-webkit-scrollbar { .hide-scrollbar::-webkit-scrollbar {
display: none; display: none;
} }
@ -157,7 +166,7 @@
} }
div[class^="language-"] { div[class^="language-"] {
@apply mb-4 mt-6 max-h-[650px] overflow-x-auto md:rounded-lg border !bg-secondary-foreground dark:!bg-secondary @apply mb-4 mt-6 max-h-[650px] overflow-x-auto md:rounded-lg border
} }
pre { pre {
@apply py-4; @apply py-4;

View File

@ -68,7 +68,7 @@
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"pathe": "^1.1.2", "pathe": "^1.1.2",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"shiki": "^1.17.7", "shiki": "^1.22.1",
"tailwind-merge": "^2.5.2", "tailwind-merge": "^2.5.2",
"tailwindcss": "^3.4.12", "tailwindcss": "^3.4.12",
"tsx": "^4.19.1", "tsx": "^4.19.1",

View File

@ -214,8 +214,8 @@ importers:
specifier: ^6.0.1 specifier: ^6.0.1
version: 6.0.1 version: 6.0.1
shiki: shiki:
specifier: ^1.17.7 specifier: ^1.22.1
version: 1.22.0 version: 1.22.1
tailwind-merge: tailwind-merge:
specifier: ^2.5.2 specifier: ^2.5.2
version: 2.5.3 version: 2.5.3
@ -2137,18 +2137,30 @@ packages:
'@shikijs/core@1.22.0': '@shikijs/core@1.22.0':
resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==} resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==}
'@shikijs/core@1.22.1':
resolution: {integrity: sha512-bqAhT/Ri5ixV4oYsvJNH8UJjpjbINWlWyXY6tBTsP4OmD6XnFv43nRJ+lTdxd2rmG5pgam/x+zGR6kLRXrpEKA==}
'@shikijs/engine-javascript@1.22.0': '@shikijs/engine-javascript@1.22.0':
resolution: {integrity: sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==} resolution: {integrity: sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==}
'@shikijs/engine-javascript@1.22.1':
resolution: {integrity: sha512-540pyoy0LWe4jj2BVbgELwOFu1uFvRI7lg4hdsExrSXA9x7gqfzZ/Nnh4RfX86aDAgJ647gx4TCmRwACbnQSvw==}
'@shikijs/engine-oniguruma@1.22.0': '@shikijs/engine-oniguruma@1.22.0':
resolution: {integrity: sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==} resolution: {integrity: sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==}
'@shikijs/engine-oniguruma@1.22.1':
resolution: {integrity: sha512-L+1Vmd+a2kk8HtogUFymQS6BjUfJnzcWoUp1BUgxoDiklbKSMvrsMuLZGevTOP1m0rEjgnC5MsDmsr8lX1lC+Q==}
'@shikijs/transformers@1.22.0': '@shikijs/transformers@1.22.0':
resolution: {integrity: sha512-k7iMOYuGQA62KwAuJOQBgH2IQb5vP8uiB3lMvAMGUgAMMurePOx3Z7oNqJdcpxqZP6I9cc7nc4DNqSKduCxmdg==} resolution: {integrity: sha512-k7iMOYuGQA62KwAuJOQBgH2IQb5vP8uiB3lMvAMGUgAMMurePOx3Z7oNqJdcpxqZP6I9cc7nc4DNqSKduCxmdg==}
'@shikijs/types@1.22.0': '@shikijs/types@1.22.0':
resolution: {integrity: sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==} resolution: {integrity: sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==}
'@shikijs/types@1.22.1':
resolution: {integrity: sha512-+45f8mu/Hxqs6Kyhfm98Nld5n7Q7lwhjU8UtdQwrOPs7BnM4VAb929O3IQ2ce+4D7SlNFlZGd8CnKRSnwbQreQ==}
'@shikijs/vscode-textmate@9.3.0': '@shikijs/vscode-textmate@9.3.0':
resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==}
@ -3305,7 +3317,7 @@ packages:
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
concat-map@0.0.1: concat-map@0.0.1:
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
concat-stream@1.6.2: concat-stream@1.6.2:
resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
@ -3885,7 +3897,7 @@ packages:
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
ee-first@1.1.1: ee-first@1.1.1:
resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=} resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
electron-to-chromium@1.5.36: electron-to-chromium@1.5.36:
resolution: {integrity: sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw==} resolution: {integrity: sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw==}
@ -5347,7 +5359,7 @@ packages:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
media-typer@0.3.0: media-typer@0.3.0:
resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=} resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
meow@12.1.1: meow@12.1.1:
@ -6672,6 +6684,9 @@ packages:
shiki@1.22.0: shiki@1.22.0:
resolution: {integrity: sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==} resolution: {integrity: sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==}
shiki@1.22.1:
resolution: {integrity: sha512-PbJ6XxrWLMwB2rm3qdjIHNm3zq4SfFnOx0B3rEoi4AN8AUngsdyZ1tRe5slMPtn6jQkbUURLNZPpLR7Do3k78g==}
shortid@2.2.16: shortid@2.2.16:
resolution: {integrity: sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==} resolution: {integrity: sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
@ -9686,17 +9701,37 @@ snapshots:
'@types/hast': 3.0.4 '@types/hast': 3.0.4
hast-util-to-html: 9.0.3 hast-util-to-html: 9.0.3
'@shikijs/core@1.22.1':
dependencies:
'@shikijs/engine-javascript': 1.22.1
'@shikijs/engine-oniguruma': 1.22.1
'@shikijs/types': 1.22.1
'@shikijs/vscode-textmate': 9.3.0
'@types/hast': 3.0.4
hast-util-to-html: 9.0.3
'@shikijs/engine-javascript@1.22.0': '@shikijs/engine-javascript@1.22.0':
dependencies: dependencies:
'@shikijs/types': 1.22.0 '@shikijs/types': 1.22.0
'@shikijs/vscode-textmate': 9.3.0 '@shikijs/vscode-textmate': 9.3.0
oniguruma-to-js: 0.4.3 oniguruma-to-js: 0.4.3
'@shikijs/engine-javascript@1.22.1':
dependencies:
'@shikijs/types': 1.22.1
'@shikijs/vscode-textmate': 9.3.0
oniguruma-to-js: 0.4.3
'@shikijs/engine-oniguruma@1.22.0': '@shikijs/engine-oniguruma@1.22.0':
dependencies: dependencies:
'@shikijs/types': 1.22.0 '@shikijs/types': 1.22.0
'@shikijs/vscode-textmate': 9.3.0 '@shikijs/vscode-textmate': 9.3.0
'@shikijs/engine-oniguruma@1.22.1':
dependencies:
'@shikijs/types': 1.22.1
'@shikijs/vscode-textmate': 9.3.0
'@shikijs/transformers@1.22.0': '@shikijs/transformers@1.22.0':
dependencies: dependencies:
shiki: 1.22.0 shiki: 1.22.0
@ -9706,6 +9741,11 @@ snapshots:
'@shikijs/vscode-textmate': 9.3.0 '@shikijs/vscode-textmate': 9.3.0
'@types/hast': 3.0.4 '@types/hast': 3.0.4
'@shikijs/types@1.22.1':
dependencies:
'@shikijs/vscode-textmate': 9.3.0
'@types/hast': 3.0.4
'@shikijs/vscode-textmate@9.3.0': {} '@shikijs/vscode-textmate@9.3.0': {}
'@sindresorhus/merge-streams@2.3.0': {} '@sindresorhus/merge-streams@2.3.0': {}
@ -15177,6 +15217,15 @@ snapshots:
'@shikijs/vscode-textmate': 9.3.0 '@shikijs/vscode-textmate': 9.3.0
'@types/hast': 3.0.4 '@types/hast': 3.0.4
shiki@1.22.1:
dependencies:
'@shikijs/core': 1.22.1
'@shikijs/engine-javascript': 1.22.1
'@shikijs/engine-oniguruma': 1.22.1
'@shikijs/types': 1.22.1
'@shikijs/vscode-textmate': 9.3.0
'@types/hast': 3.0.4
shortid@2.2.16: shortid@2.2.16:
dependencies: dependencies:
nanoid: 2.1.11 nanoid: 2.1.11
@ -16215,7 +16264,7 @@ snapshots:
focus-trap: 7.6.0 focus-trap: 7.6.0
mark.js: 8.11.1 mark.js: 8.11.1
minisearch: 7.1.0 minisearch: 7.1.0
shiki: 1.22.0 shiki: 1.22.1
vite: 5.4.8(@types/node@22.7.5)(stylus@0.57.0)(terser@5.34.1) vite: 5.4.8(@types/node@22.7.5)(stylus@0.57.0)(terser@5.34.1)
vue: 3.5.11(typescript@5.6.3) vue: 3.5.11(typescript@5.6.3)
optionalDependencies: optionalDependencies: