mirror of
https://github.com/elk-zone/elk.git
synced 2024-11-21 17:05:22 +03:00
feat: support codeblock
This commit is contained in:
parent
4885b165df
commit
0a8841f4f4
13 changed files with 201 additions and 52 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,3 +4,5 @@ dist
|
|||
.output
|
||||
.nuxt
|
||||
.env
|
||||
|
||||
public/shiki
|
||||
|
|
|
@ -18,7 +18,7 @@ export default defineComponent({
|
|||
return () => h(
|
||||
'div',
|
||||
{ class: 'rich-content' },
|
||||
contentToVNode(props.content, undefined, emojiObject),
|
||||
contentToVNode(props.content, emojiObject),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
|
22
components/content/ContentCode.vue
Normal file
22
components/content/ContentCode.vue
Normal file
|
@ -0,0 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
code: string
|
||||
lang: string
|
||||
}>()
|
||||
|
||||
const raw = computed(() => decodeURIComponent(props.code).replace(/'/g, '\''))
|
||||
|
||||
const langMap: Record<string, string> = {
|
||||
js: 'javascript',
|
||||
ts: 'typescript',
|
||||
vue: 'html',
|
||||
}
|
||||
|
||||
const hightlighted = computed(() => {
|
||||
return highlightCode(raw.value, langMap[props.lang] || props.lang as any)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<pre class="code-block" v-html="hightlighted" />
|
||||
</template>
|
|
@ -1,14 +1,19 @@
|
|||
import type { Emoji } from 'masto'
|
||||
import type { DefaultTreeAdapterMap } from 'parse5'
|
||||
import { parseFragment } from 'parse5'
|
||||
import type { VNode } from 'vue'
|
||||
import { Fragment, h } from 'vue'
|
||||
import type { Component, VNode } from 'vue'
|
||||
import { Fragment, h, isVNode } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import ContentCode from '~/components/content/ContentCode.vue'
|
||||
|
||||
type Node = DefaultTreeAdapterMap['childNode']
|
||||
type Element = DefaultTreeAdapterMap['element']
|
||||
|
||||
export function defaultHandle(el: Element) {
|
||||
const CUSTOM_BLOCKS: Record<string, Component> = {
|
||||
'custom-code': ContentCode,
|
||||
}
|
||||
|
||||
function handleMention(el: Element) {
|
||||
// Redirect mentions to the user page
|
||||
if (el.tagName === 'a' && el.attrs.find(i => i.name === 'class' && i.value.includes('mention'))) {
|
||||
const href = el.attrs.find(i => i.name === 'href')
|
||||
|
@ -26,36 +31,58 @@ export function defaultHandle(el: Element) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return el
|
||||
return undefined
|
||||
}
|
||||
|
||||
function handleBlocks(el: Element) {
|
||||
if (el.tagName in CUSTOM_BLOCKS) {
|
||||
const block = CUSTOM_BLOCKS[el.tagName]
|
||||
const attrs = Object.fromEntries(el.attrs.map(i => [i.name, i.value]))
|
||||
return h(block, attrs, () => el.childNodes.map(treeToVNode))
|
||||
}
|
||||
}
|
||||
|
||||
function handleNode(el: Element) {
|
||||
return handleBlocks(el) || handleMention(el) || el
|
||||
}
|
||||
|
||||
export function contentToVNode(
|
||||
content: string,
|
||||
handle: (node: Element) => Element | undefined | null | void = defaultHandle,
|
||||
customEmojis: Record<string, Emoji> = {},
|
||||
): VNode {
|
||||
content = content.trim().replace(/:([\w-]+?):/g, (_, name) => {
|
||||
const emoji = customEmojis[name]
|
||||
if (emoji)
|
||||
return `<img src="${emoji.url}" alt="${name}" class="custom-emoji" />`
|
||||
return `:${name}:`
|
||||
})
|
||||
content = content
|
||||
.trim()
|
||||
// handle custom emojis
|
||||
.replace(/:([\w-]+?):/g, (_, name) => {
|
||||
const emoji = customEmojis[name]
|
||||
if (emoji)
|
||||
return `<img src="${emoji.url}" alt="${name}" class="custom-emoji" />`
|
||||
return `:${name}:`
|
||||
})
|
||||
// handle codeblocks
|
||||
.replace(/<p>(```|~~~)([\s\S]+?)\1(\s|<br\s?\/?>)*<\/p>/g, (_1, _2, raw) => {
|
||||
const plain = htmlToText(`<p>${raw}</p>`).trim()
|
||||
const [lang, ...rest] = plain.split(/\n/)
|
||||
return `<custom-code lang="${lang || ''}" code="${encodeURIComponent(rest.join('\n'))}" />`
|
||||
})
|
||||
|
||||
const tree = parseFragment(content)
|
||||
return h(Fragment, tree.childNodes.map(n => treeToVNode(n, handle)))
|
||||
return h(Fragment, tree.childNodes.map(n => treeToVNode(n)))
|
||||
}
|
||||
|
||||
export function treeToVNode(
|
||||
input: Node,
|
||||
handle: (node: Element) => Element | undefined | null | void = defaultHandle,
|
||||
): VNode | string | null {
|
||||
if (input.nodeName === '#text')
|
||||
// @ts-expect-error casing
|
||||
return input.value
|
||||
|
||||
if ('childNodes' in input) {
|
||||
const node = handle(input)
|
||||
const node = handleNode(input)
|
||||
if (node == null)
|
||||
return null
|
||||
if (isVNode(node))
|
||||
return node
|
||||
|
||||
const attrs = Object.fromEntries(node.attrs.map(i => [i.name, i.value]))
|
||||
if (node.nodeName === 'a' && (attrs.href?.startsWith('/') || attrs.href?.startsWith('.'))) {
|
||||
|
@ -65,14 +92,38 @@ export function treeToVNode(
|
|||
return h(
|
||||
RouterLink as any,
|
||||
attrs,
|
||||
() => node.childNodes.map(n => treeToVNode(n, handle)),
|
||||
() => node.childNodes.map(treeToVNode),
|
||||
)
|
||||
}
|
||||
return h(
|
||||
node.nodeName,
|
||||
attrs,
|
||||
node.childNodes.map(n => treeToVNode(n, handle)),
|
||||
node.childNodes.map(treeToVNode),
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function htmlToText(html: string) {
|
||||
const tree = parseFragment(html)
|
||||
return tree.childNodes.map(n => treeToText(n)).join('')
|
||||
}
|
||||
|
||||
function treeToText(input: Node): string {
|
||||
let pre = ''
|
||||
|
||||
if (input.nodeName === '#text')
|
||||
// @ts-expect-error casing
|
||||
return input.value
|
||||
|
||||
if (input.nodeName === 'br')
|
||||
return '\n'
|
||||
|
||||
if (input.nodeName === 'p')
|
||||
pre = '\n'
|
||||
|
||||
if ('childNodes' in input)
|
||||
return pre + input.childNodes.map(n => treeToText(n)).join('')
|
||||
|
||||
return pre
|
||||
}
|
||||
|
|
37
composables/shiki.ts
Normal file
37
composables/shiki.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import type { Highlighter, Lang } from 'shiki'
|
||||
|
||||
export const shiki = ref<Highlighter>()
|
||||
|
||||
const registeredLang = ref(new Map<string, boolean>())
|
||||
let shikiImport: Promise<void> | undefined
|
||||
|
||||
export function highlightCode(code: string, lang: Lang) {
|
||||
if (!shikiImport) {
|
||||
shikiImport = import('shiki')
|
||||
.then(async (r) => {
|
||||
r.setCDN('/shiki/')
|
||||
shiki.value = await r.getHighlighter({
|
||||
themes: [
|
||||
'vitesse-dark',
|
||||
'vitesse-light',
|
||||
],
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (!shiki.value)
|
||||
return code
|
||||
|
||||
if (!registeredLang.value.get(lang)) {
|
||||
shiki.value.loadLanguage(lang)
|
||||
.then(() => {
|
||||
registeredLang.value.set(lang, true)
|
||||
})
|
||||
return code
|
||||
}
|
||||
|
||||
return shiki.value.codeToHtml(code, {
|
||||
lang,
|
||||
theme: isDark.value ? 'vitesse-dark' : 'vitesse-light',
|
||||
})
|
||||
}
|
|
@ -23,3 +23,4 @@ export function getDataUrlFromArr(arr: Uint8ClampedArray, w: number, h: number)
|
|||
export function emojisArrayToObject(emojis: Emoji[]) {
|
||||
return Object.fromEntries(emojis.map(i => [i.shortcode, i]))
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,12 @@ export default defineNuxtConfig({
|
|||
},
|
||||
vite: {
|
||||
define: {
|
||||
__BUILD_TIME__: JSON.stringify(new Date().toISOString()),
|
||||
'__BUILD_TIME__': JSON.stringify(new Date().toISOString()),
|
||||
'process.env.VSCODE_TEXTMATE_DEBUG': 'false',
|
||||
},
|
||||
build: {
|
||||
target: 'esnext',
|
||||
},
|
||||
|
||||
},
|
||||
postcss: {
|
||||
plugins: {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"start": "node .output/server/index.mjs",
|
||||
"lint": "eslint .",
|
||||
"postinstall": "nuxi prepare",
|
||||
"prepare": "esno scripts/prepare.ts",
|
||||
"generate": "nuxi generate"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -18,6 +19,7 @@
|
|||
"@iconify-json/twemoji": "^1.1.5",
|
||||
"@pinia/nuxt": "^0.4.3",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/sanitize-html": "^2.6.2",
|
||||
"@types/wicg-file-system-access": "^2020.9.5",
|
||||
"@unocss/nuxt": "^0.46.5",
|
||||
|
@ -28,6 +30,7 @@
|
|||
"esno": "^0.16.3",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"masto": "^4.6.6",
|
||||
"nuxt": "^3.0.0",
|
||||
"parse5": "^7.1.1",
|
||||
|
@ -35,6 +38,8 @@
|
|||
"postcss-nested": "^6.0.0",
|
||||
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||
"sanitize-html": "^2.7.3",
|
||||
"shiki": "^0.11.1",
|
||||
"theme-vitesse": "^0.6.0",
|
||||
"typescript": "^4.9.3",
|
||||
"ufo": "^1.0.0"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
lockfileVersion: 5.4
|
||||
|
||||
overrides:
|
||||
debug: 4.3.4
|
||||
|
||||
specifiers:
|
||||
'@antfu/eslint-config': ^0.30.1
|
||||
'@iconify-json/carbon': ^1.1.10
|
||||
|
@ -8,6 +11,7 @@ specifiers:
|
|||
'@iconify-json/twemoji': ^1.1.5
|
||||
'@pinia/nuxt': ^0.4.3
|
||||
'@types/fs-extra': ^9.0.13
|
||||
'@types/js-yaml': ^4.0.5
|
||||
'@types/sanitize-html': ^2.6.2
|
||||
'@types/wicg-file-system-access': ^2020.9.5
|
||||
'@unocss/nuxt': ^0.46.5
|
||||
|
@ -18,6 +22,7 @@ specifiers:
|
|||
esno: ^0.16.3
|
||||
form-data: ^4.0.0
|
||||
fs-extra: ^10.1.0
|
||||
js-yaml: ^4.1.0
|
||||
masto: ^4.6.6
|
||||
nuxt: ^3.0.0
|
||||
parse5: ^7.1.1
|
||||
|
@ -25,6 +30,8 @@ specifiers:
|
|||
postcss-nested: ^6.0.0
|
||||
rollup-plugin-node-polyfills: ^0.2.1
|
||||
sanitize-html: ^2.7.3
|
||||
shiki: ^0.11.1
|
||||
theme-vitesse: ^0.6.0
|
||||
typescript: ^4.9.3
|
||||
ufo: ^1.0.0
|
||||
|
||||
|
@ -36,6 +43,7 @@ devDependencies:
|
|||
'@iconify-json/twemoji': 1.1.5
|
||||
'@pinia/nuxt': 0.4.3_typescript@4.9.3
|
||||
'@types/fs-extra': 9.0.13
|
||||
'@types/js-yaml': 4.0.5
|
||||
'@types/sanitize-html': 2.6.2
|
||||
'@types/wicg-file-system-access': 2020.9.5
|
||||
'@unocss/nuxt': 0.46.5
|
||||
|
@ -46,6 +54,7 @@ devDependencies:
|
|||
esno: 0.16.3
|
||||
form-data: 4.0.0
|
||||
fs-extra: 10.1.0
|
||||
js-yaml: 4.1.0
|
||||
masto: 4.6.6
|
||||
nuxt: 3.0.0_e3uo4sehh4zr4i6m57mkkxxv7y
|
||||
parse5: 7.1.1
|
||||
|
@ -53,6 +62,8 @@ devDependencies:
|
|||
postcss-nested: 6.0.0
|
||||
rollup-plugin-node-polyfills: 0.2.1
|
||||
sanitize-html: 2.7.3
|
||||
shiki: 0.11.1
|
||||
theme-vitesse: 0.6.0
|
||||
typescript: 4.9.3
|
||||
ufo: 1.0.0
|
||||
|
||||
|
@ -1255,6 +1266,10 @@ packages:
|
|||
'@types/node': 18.7.23
|
||||
dev: true
|
||||
|
||||
/@types/js-yaml/4.0.5:
|
||||
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
|
||||
dev: true
|
||||
|
||||
/@types/json-schema/7.0.11:
|
||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||
dev: true
|
||||
|
@ -2883,28 +2898,6 @@ packages:
|
|||
engines: {node: '>= 12'}
|
||||
dev: true
|
||||
|
||||
/debug/2.6.9:
|
||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
dev: true
|
||||
|
||||
/debug/3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
dev: true
|
||||
|
||||
/debug/4.3.4:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
|
@ -3432,7 +3425,7 @@ packages:
|
|||
/eslint-import-resolver-node/0.3.6:
|
||||
resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==}
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
debug: 4.3.4
|
||||
resolve: 1.22.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -3460,7 +3453,7 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.42.1_e3uo4sehh4zr4i6m57mkkxxv7y
|
||||
debug: 3.2.7
|
||||
debug: 4.3.4
|
||||
eslint: 8.27.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
transitivePeerDependencies:
|
||||
|
@ -3518,7 +3511,7 @@ packages:
|
|||
'@typescript-eslint/parser': 5.42.1_e3uo4sehh4zr4i6m57mkkxxv7y
|
||||
array-includes: 3.1.5
|
||||
array.prototype.flat: 1.3.0
|
||||
debug: 2.6.9
|
||||
debug: 4.3.4
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.27.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
|
@ -5160,10 +5153,6 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/ms/2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
dev: true
|
||||
|
||||
/ms/2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
dev: true
|
||||
|
@ -6497,7 +6486,7 @@ packages:
|
|||
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dependencies:
|
||||
debug: 2.6.9
|
||||
debug: 4.3.4
|
||||
depd: 2.0.0
|
||||
destroy: 1.2.0
|
||||
encodeurl: 1.0.2
|
||||
|
@ -6566,6 +6555,14 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/shiki/0.11.1:
|
||||
resolution: {integrity: sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==}
|
||||
dependencies:
|
||||
jsonc-parser: 3.2.0
|
||||
vscode-oniguruma: 1.6.2
|
||||
vscode-textmate: 6.0.0
|
||||
dev: true
|
||||
|
||||
/side-channel/1.0.4:
|
||||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
||||
dependencies:
|
||||
|
@ -6882,6 +6879,11 @@ packages:
|
|||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||
dev: true
|
||||
|
||||
/theme-vitesse/0.6.0:
|
||||
resolution: {integrity: sha512-/XEZFGXLTK/AlWSe9t+NIXB1tP3yqdzugcSJJ2Fg0KYM1PcoL/zWs5AuaEcCFt1pfi/9Og++tzOdiU2aKf/+Xw==}
|
||||
engines: {vscode: ^1.43.0}
|
||||
dev: true
|
||||
|
||||
/through/2.3.8:
|
||||
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
|
||||
dev: true
|
||||
|
@ -7502,6 +7504,14 @@ packages:
|
|||
vscode-languageserver-protocol: 3.16.0
|
||||
dev: true
|
||||
|
||||
/vscode-oniguruma/1.6.2:
|
||||
resolution: {integrity: sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==}
|
||||
dev: true
|
||||
|
||||
/vscode-textmate/6.0.0:
|
||||
resolution: {integrity: sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==}
|
||||
dev: true
|
||||
|
||||
/vscode-uri/3.0.6:
|
||||
resolution: {integrity: sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==}
|
||||
dev: true
|
||||
|
|
10
scripts/prepare.ts
Normal file
10
scripts/prepare.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { copy } from 'fs-extra'
|
||||
|
||||
const dereference = process.platform === 'win32' ? true : undefined
|
||||
|
||||
await copy('node_modules/shiki/', 'public/shiki/', {
|
||||
dereference,
|
||||
filter: src => src === 'node_modules/shiki/' || src.includes('languages') || src.includes('dist'),
|
||||
})
|
||||
await copy('node_modules/theme-vitesse/themes', 'public/shiki/themes', { dereference })
|
||||
await copy('node_modules/theme-vitesse/themes', 'node_modules/shiki/themes', { overwrite: true, dereference })
|
|
@ -1,5 +1,5 @@
|
|||
* {
|
||||
scrollbar-color: #5555 var(--c-border);
|
||||
scrollbar-color: #8885 var(--c-border);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
|
@ -16,12 +16,12 @@
|
|||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #555;
|
||||
background: #8885;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #666;
|
||||
background: #8886;
|
||||
}
|
||||
|
||||
/* Force vertical scrollbar to be always visible to avoid layout shift while loading the content */
|
||||
|
@ -52,4 +52,12 @@ html {
|
|||
p {
|
||||
--at-apply: my-2;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
--at-apply: bg-code text-0.9rem p3 rounded overflow-auto leading-1.6em;
|
||||
|
||||
.shiki {
|
||||
background: transparent !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
--c-border: #88888820;
|
||||
--c-bg-base: #fff;
|
||||
--c-bg-active: #f6f6f6;
|
||||
--c-bg-code: #00000006;
|
||||
--c-text-base: #222;
|
||||
--c-text-secondary: #888;
|
||||
}
|
||||
|
@ -11,5 +12,6 @@
|
|||
.dark {
|
||||
--c-bg-base: #111;
|
||||
--c-bg-active: #151515;
|
||||
--c-bg-code: #ffffff06;
|
||||
--c-text-base: #fff;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ export default defineConfig({
|
|||
'border-base': 'border-$c-border',
|
||||
'bg-base': 'bg-$c-bg-base',
|
||||
'bg-active': 'bg-$c-bg-active',
|
||||
'bg-code': 'bg-$c-bg-code',
|
||||
'text-base': 'text-$c-text-base',
|
||||
'text-secondary': 'text-$c-text-secondary',
|
||||
'interact-disabled': 'disabled:opacity-50 disabled:pointer-events-none disabled:saturate-0',
|
||||
|
|
Loading…
Reference in a new issue