kopia lustrzana https://github.com/elk-zone/elk
				
				
				
			feat: code highlight for tiptap
							rodzic
							
								
									854d861766
								
							
						
					
					
						commit
						75f49461de
					
				| 
						 | 
				
			
			@ -4,8 +4,24 @@ import { NodeViewContent, NodeViewWrapper, nodeViewProps } from '@tiptap/vue-3'
 | 
			
		|||
const props = defineProps(nodeViewProps)
 | 
			
		||||
 | 
			
		||||
const languages = [
 | 
			
		||||
  'js',
 | 
			
		||||
  'ts',
 | 
			
		||||
  'c',
 | 
			
		||||
  'cpp',
 | 
			
		||||
  'csharp',
 | 
			
		||||
  'css',
 | 
			
		||||
  'dart',
 | 
			
		||||
  'go',
 | 
			
		||||
  'html',
 | 
			
		||||
  'java',
 | 
			
		||||
  'javascript',
 | 
			
		||||
  'jsx',
 | 
			
		||||
  'kotlin',
 | 
			
		||||
  'python',
 | 
			
		||||
  'rust',
 | 
			
		||||
  'svelte',
 | 
			
		||||
  'swift',
 | 
			
		||||
  'tsx',
 | 
			
		||||
  'typescript',
 | 
			
		||||
  'vue',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
const selectedLanguage = computed({
 | 
			
		||||
| 
						 | 
				
			
			@ -20,8 +36,13 @@ const selectedLanguage = computed({
 | 
			
		|||
 | 
			
		||||
<template>
 | 
			
		||||
  <NodeViewWrapper>
 | 
			
		||||
    <div relative my2 class="code-block">
 | 
			
		||||
      <select v-model="selectedLanguage" contenteditable="false" absolute top-1 right-1 rounded px2 op0 hover:op100 focus:op100 transition>
 | 
			
		||||
    <div relative my2>
 | 
			
		||||
      <select
 | 
			
		||||
        v-model="selectedLanguage"
 | 
			
		||||
        contenteditable="false"
 | 
			
		||||
        absolute top-1 right-1 rounded px2 op0 hover:op100 focus:op100 transition
 | 
			
		||||
        outline-none border="~ base"
 | 
			
		||||
      >
 | 
			
		||||
        <option :value="null">
 | 
			
		||||
          plain
 | 
			
		||||
        </option>
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +50,7 @@ const selectedLanguage = computed({
 | 
			
		|||
          {{ language }}
 | 
			
		||||
        </option>
 | 
			
		||||
      </select>
 | 
			
		||||
      <pre><code><NodeViewContent /></code></pre>
 | 
			
		||||
      <pre class="code-block"><code><NodeViewContent /></code></pre>
 | 
			
		||||
    </div>
 | 
			
		||||
  </NodeViewWrapper>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
import type { Highlighter, Lang } from 'shiki-es'
 | 
			
		||||
 | 
			
		||||
export const shiki = ref<Highlighter>()
 | 
			
		||||
const shiki = ref<Highlighter>()
 | 
			
		||||
 | 
			
		||||
const registeredLang = ref(new Map<string, boolean>())
 | 
			
		||||
let shikiImport: Promise<void> | undefined
 | 
			
		||||
 | 
			
		||||
export function highlightCode(code: string, lang: Lang) {
 | 
			
		||||
export function useHightlighter(lang: Lang) {
 | 
			
		||||
  if (!shikiImport) {
 | 
			
		||||
    shikiImport = import('shiki-es')
 | 
			
		||||
      .then(async (r) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ export function highlightCode(code: string, lang: Lang) {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  if (!shiki.value)
 | 
			
		||||
    return code
 | 
			
		||||
    return undefined
 | 
			
		||||
 | 
			
		||||
  if (!registeredLang.value.get(lang)) {
 | 
			
		||||
    shiki.value.loadLanguage(lang)
 | 
			
		||||
| 
						 | 
				
			
			@ -37,11 +37,27 @@ export function highlightCode(code: string, lang: Lang) {
 | 
			
		|||
        console.error(e)
 | 
			
		||||
        registeredLang.value.set(lang, false)
 | 
			
		||||
      })
 | 
			
		||||
    return code
 | 
			
		||||
    return undefined
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return shiki.value.codeToHtml(code, {
 | 
			
		||||
  return shiki.value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useShikiTheme() {
 | 
			
		||||
  return isDark.value ? 'vitesse-dark' : 'vitesse-light'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function highlightCode(code: string, lang: Lang) {
 | 
			
		||||
  const shiki = useHightlighter(lang)
 | 
			
		||||
  if (!shiki)
 | 
			
		||||
    return code
 | 
			
		||||
 | 
			
		||||
  return shiki.codeToHtml(code, {
 | 
			
		||||
    lang,
 | 
			
		||||
    theme: isDark.value ? 'vitesse-dark' : 'vitesse-light',
 | 
			
		||||
    theme: useShikiTheme(),
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useShiki() {
 | 
			
		||||
  return shiki
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { Extension, VueNodeViewRenderer, useEditor } from '@tiptap/vue-3'
 | 
			
		||||
import { Extension, useEditor } from '@tiptap/vue-3'
 | 
			
		||||
import Placeholder from '@tiptap/extension-placeholder'
 | 
			
		||||
import Document from '@tiptap/extension-document'
 | 
			
		||||
import Paragraph from '@tiptap/extension-paragraph'
 | 
			
		||||
| 
						 | 
				
			
			@ -10,11 +10,10 @@ import Bold from '@tiptap/extension-bold'
 | 
			
		|||
import Italic from '@tiptap/extension-italic'
 | 
			
		||||
import Code from '@tiptap/extension-code'
 | 
			
		||||
import { Plugin } from 'prosemirror-state'
 | 
			
		||||
import CodeBlock from '@tiptap/extension-code-block'
 | 
			
		||||
 | 
			
		||||
import type { Ref } from 'vue'
 | 
			
		||||
import { HashSuggestion, MentionSuggestion } from './tiptap/suggestion'
 | 
			
		||||
import TiptapCodeBlock from '~/components/tiptap/TiptapCodeBlock.vue'
 | 
			
		||||
import { CodeBlockShiki } from './tiptap/shiki'
 | 
			
		||||
 | 
			
		||||
export interface UseTiptapOptions {
 | 
			
		||||
  content: Ref<string | undefined>
 | 
			
		||||
| 
						 | 
				
			
			@ -56,12 +55,7 @@ export function useTiptap(options: UseTiptapOptions) {
 | 
			
		|||
      CharacterCount.configure({
 | 
			
		||||
        limit: characterLimit.value,
 | 
			
		||||
      }),
 | 
			
		||||
      CodeBlock
 | 
			
		||||
        .extend({
 | 
			
		||||
          addNodeView() {
 | 
			
		||||
            return VueNodeViewRenderer(TiptapCodeBlock)
 | 
			
		||||
          },
 | 
			
		||||
        }),
 | 
			
		||||
      CodeBlockShiki,
 | 
			
		||||
      Extension.create({
 | 
			
		||||
        name: 'api',
 | 
			
		||||
        addKeyboardShortcuts() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,129 @@
 | 
			
		|||
import type { CodeBlockOptions } from '@tiptap/extension-code-block'
 | 
			
		||||
import CodeBlock from '@tiptap/extension-code-block'
 | 
			
		||||
import { VueNodeViewRenderer } from '@tiptap/vue-3'
 | 
			
		||||
 | 
			
		||||
import { findChildren } from '@tiptap/core'
 | 
			
		||||
import type { Node as ProsemirrorNode } from 'prosemirror-model'
 | 
			
		||||
import { Plugin, PluginKey } from 'prosemirror-state'
 | 
			
		||||
import { Decoration, DecorationSet } from 'prosemirror-view'
 | 
			
		||||
import TiptapCodeBlock from '~/components/tiptap/TiptapCodeBlock.vue'
 | 
			
		||||
 | 
			
		||||
export interface CodeBlockShikiOptions extends CodeBlockOptions {
 | 
			
		||||
  defaultLanguage: string | null | undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CodeBlockShiki = CodeBlock.extend<CodeBlockShikiOptions>({
 | 
			
		||||
  addOptions() {
 | 
			
		||||
    return {
 | 
			
		||||
      ...this.parent?.(),
 | 
			
		||||
      defaultLanguage: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  addProseMirrorPlugins() {
 | 
			
		||||
    return [
 | 
			
		||||
      ...this.parent?.() || [],
 | 
			
		||||
      ProseMirrorShikiPlugin({
 | 
			
		||||
        name: this.name,
 | 
			
		||||
      }),
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  addNodeView() {
 | 
			
		||||
    return VueNodeViewRenderer(TiptapCodeBlock)
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
function getDecorations({
 | 
			
		||||
  doc,
 | 
			
		||||
  name,
 | 
			
		||||
}: { doc: ProsemirrorNode; name: string }) {
 | 
			
		||||
  const decorations: Decoration[] = []
 | 
			
		||||
 | 
			
		||||
  findChildren(doc, node => node.type.name === name)
 | 
			
		||||
    .forEach((block) => {
 | 
			
		||||
      let from = block.pos + 1
 | 
			
		||||
      const language = block.node.attrs.language || 'text'
 | 
			
		||||
 | 
			
		||||
      const shiki = useHightlighter(language)
 | 
			
		||||
 | 
			
		||||
      if (!shiki)
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
      const lines = shiki.codeToThemedTokens(block.node.textContent, language, useShikiTheme())
 | 
			
		||||
 | 
			
		||||
      lines.forEach((line) => {
 | 
			
		||||
        line.forEach((token) => {
 | 
			
		||||
          const decoration = Decoration.inline(from, from + token.content.length, {
 | 
			
		||||
            style: `color: ${token.color}`,
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          decorations.push(decoration)
 | 
			
		||||
          from += token.content.length
 | 
			
		||||
        })
 | 
			
		||||
        from += 1
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
  return DecorationSet.create(doc, decorations)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ProseMirrorShikiPlugin({ name }: { name: string }) {
 | 
			
		||||
  const plugin: Plugin<any> = new Plugin({
 | 
			
		||||
    key: new PluginKey('shiki'),
 | 
			
		||||
 | 
			
		||||
    state: {
 | 
			
		||||
      init: (_, { doc }) => getDecorations({
 | 
			
		||||
        doc,
 | 
			
		||||
        name,
 | 
			
		||||
      }),
 | 
			
		||||
      apply: (transaction, decorationSet, oldState, newState) => {
 | 
			
		||||
        const oldNodeName = oldState.selection.$head.parent.type.name
 | 
			
		||||
        const newNodeName = newState.selection.$head.parent.type.name
 | 
			
		||||
        const oldNodes = findChildren(oldState.doc, node => node.type.name === name)
 | 
			
		||||
        const newNodes = findChildren(newState.doc, node => node.type.name === name)
 | 
			
		||||
 | 
			
		||||
        if (
 | 
			
		||||
          transaction.docChanged
 | 
			
		||||
          // Apply decorations if:
 | 
			
		||||
          && (
 | 
			
		||||
            // selection includes named node,
 | 
			
		||||
            [oldNodeName, newNodeName].includes(name)
 | 
			
		||||
            // OR transaction adds/removes named node,
 | 
			
		||||
            || newNodes.length !== oldNodes.length
 | 
			
		||||
            // OR transaction has changes that completely encapsulte a node
 | 
			
		||||
            // (for example, a transaction that affects the entire document).
 | 
			
		||||
            // Such transactions can happen during collab syncing via y-prosemirror, for example.
 | 
			
		||||
            || transaction.steps.some((step) => {
 | 
			
		||||
              // @ts-expect-error cast
 | 
			
		||||
              return step.from !== undefined
 | 
			
		||||
                // @ts-expect-error cast
 | 
			
		||||
                && step.to !== undefined
 | 
			
		||||
                && oldNodes.some((node) => {
 | 
			
		||||
                  // @ts-expect-error cast
 | 
			
		||||
                  return node.pos >= step.from
 | 
			
		||||
                    // @ts-expect-error cast
 | 
			
		||||
                    && node.pos + node.node.nodeSize <= step.to
 | 
			
		||||
                })
 | 
			
		||||
            })
 | 
			
		||||
          )
 | 
			
		||||
        ) {
 | 
			
		||||
          return getDecorations({
 | 
			
		||||
            doc: transaction.doc,
 | 
			
		||||
            name,
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return decorationSet.map(transaction.mapping, transaction.doc)
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    props: {
 | 
			
		||||
      decorations(state) {
 | 
			
		||||
        return plugin.getState(state)
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  return plugin
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,6 @@
 | 
			
		|||
    "@pinia/nuxt": "^0.4.6",
 | 
			
		||||
    "@tiptap/extension-character-count": "2.0.0-beta.204",
 | 
			
		||||
    "@tiptap/extension-code-block": "2.0.0-beta.204",
 | 
			
		||||
    "@tiptap/extension-code-block-lowlight": "2.0.0-beta.204",
 | 
			
		||||
    "@tiptap/extension-mention": "2.0.0-beta.204",
 | 
			
		||||
    "@tiptap/extension-paragraph": "2.0.0-beta.204",
 | 
			
		||||
    "@tiptap/extension-placeholder": "2.0.0-beta.204",
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +63,6 @@
 | 
			
		|||
    "js-yaml": "^4.1.0",
 | 
			
		||||
    "jsdom": "^20.0.3",
 | 
			
		||||
    "lint-staged": "^13.0.4",
 | 
			
		||||
    "lowlight": "^2.8.0",
 | 
			
		||||
    "lru-cache": "^7.14.1",
 | 
			
		||||
    "masto": "^4.7.5",
 | 
			
		||||
    "nuxt": "^3.0.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,6 @@ specifiers:
 | 
			
		|||
  '@pinia/nuxt': ^0.4.6
 | 
			
		||||
  '@tiptap/extension-character-count': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-code-block': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-code-block-lowlight': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-mention': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-paragraph': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-placeholder': 2.0.0-beta.204
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +43,6 @@ specifiers:
 | 
			
		|||
  js-yaml: ^4.1.0
 | 
			
		||||
  jsdom: ^20.0.3
 | 
			
		||||
  lint-staged: ^13.0.4
 | 
			
		||||
  lowlight: ^2.8.0
 | 
			
		||||
  lru-cache: ^7.14.1
 | 
			
		||||
  masto: ^4.7.5
 | 
			
		||||
  nuxt: ^3.0.0
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +84,6 @@ devDependencies:
 | 
			
		|||
  '@pinia/nuxt': 0.4.6_typescript@4.9.3
 | 
			
		||||
  '@tiptap/extension-character-count': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-code-block': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-code-block-lowlight': 2.0.0-beta.204_czakdrv4w4d5ggkubz4l2tz4ny
 | 
			
		||||
  '@tiptap/extension-mention': 2.0.0-beta.204_ggkstofzpnfxkp3gzsos4mewvi
 | 
			
		||||
  '@tiptap/extension-paragraph': 2.0.0-beta.204
 | 
			
		||||
  '@tiptap/extension-placeholder': 2.0.0-beta.204
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +113,6 @@ devDependencies:
 | 
			
		|||
  js-yaml: 4.1.0
 | 
			
		||||
  jsdom: 20.0.3
 | 
			
		||||
  lint-staged: 13.0.4
 | 
			
		||||
  lowlight: 2.8.0
 | 
			
		||||
  lru-cache: 7.14.1
 | 
			
		||||
  masto: 4.7.5
 | 
			
		||||
  nuxt: 3.0.0_s5ps7njkmjlaqajutnox5ntcla
 | 
			
		||||
| 
						 | 
				
			
			@ -1376,18 +1372,6 @@ packages:
 | 
			
		|||
      prosemirror-state: 1.4.2
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /@tiptap/extension-code-block-lowlight/2.0.0-beta.204_czakdrv4w4d5ggkubz4l2tz4ny:
 | 
			
		||||
    resolution: {integrity: sha512-6n2RWlMv7V3NANK+5UfxOMaK83ps8BucleQ/XdNcZuj/glTZco8Z+2E+kazW92c4IFrSgteriYg5ZqC2NBYXrg==}
 | 
			
		||||
    peerDependencies:
 | 
			
		||||
      '@tiptap/core': ^2.0.0-beta.193
 | 
			
		||||
      '@tiptap/extension-code-block': ^2.0.0-beta.193
 | 
			
		||||
    dependencies:
 | 
			
		||||
      '@tiptap/extension-code-block': 2.0.0-beta.204
 | 
			
		||||
      prosemirror-model: 1.18.3
 | 
			
		||||
      prosemirror-state: 1.4.2
 | 
			
		||||
      prosemirror-view: 1.29.1
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /@tiptap/extension-code-block/2.0.0-beta.204:
 | 
			
		||||
    resolution: {integrity: sha512-IIkZsBT7rxhK7yHnM2LRQfS6i+HNQxU+E6tRtPYF40YSg1xMZSC/xDy0k+NEU/xM6ZVesRofW3voB6svFPPDtw==}
 | 
			
		||||
    peerDependencies:
 | 
			
		||||
| 
						 | 
				
			
			@ -1644,12 +1628,6 @@ packages:
 | 
			
		|||
      '@types/node': 18.11.10
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /@types/hast/2.3.4:
 | 
			
		||||
    resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==}
 | 
			
		||||
    dependencies:
 | 
			
		||||
      '@types/unist': 2.0.6
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /@types/js-yaml/4.0.5:
 | 
			
		||||
    resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
 | 
			
		||||
    dev: true
 | 
			
		||||
| 
						 | 
				
			
			@ -4508,12 +4486,6 @@ packages:
 | 
			
		|||
      reusify: 1.0.4
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /fault/2.0.1:
 | 
			
		||||
    resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==}
 | 
			
		||||
    dependencies:
 | 
			
		||||
      format: 0.2.2
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /fetch-blob/3.2.0:
 | 
			
		||||
    resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
 | 
			
		||||
    engines: {node: ^12.20 || >= 14.13}
 | 
			
		||||
| 
						 | 
				
			
			@ -4624,11 +4596,6 @@ packages:
 | 
			
		|||
      mime-types: 2.1.35
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /format/0.2.2:
 | 
			
		||||
    resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
 | 
			
		||||
    engines: {node: '>=0.4.x'}
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /formdata-polyfill/4.0.10:
 | 
			
		||||
    resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
 | 
			
		||||
    engines: {node: '>=12.20.0'}
 | 
			
		||||
| 
						 | 
				
			
			@ -4966,11 +4933,6 @@ packages:
 | 
			
		|||
      tslib: 2.4.1
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /highlight.js/11.7.0:
 | 
			
		||||
    resolution: {integrity: sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==}
 | 
			
		||||
    engines: {node: '>=12.0.0'}
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /hookable/5.4.2:
 | 
			
		||||
    resolution: {integrity: sha512-6rOvaUiNKy9lET1X0ECnyZ5O5kSV0PJbtA5yZUgdEF7fGJEVwSLSislltyt7nFwVVALYHQJtfGeAR2Y0A0uJkg==}
 | 
			
		||||
    dev: true
 | 
			
		||||
| 
						 | 
				
			
			@ -5771,14 +5733,6 @@ packages:
 | 
			
		|||
      tslib: 2.4.1
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /lowlight/2.8.0:
 | 
			
		||||
    resolution: {integrity: sha512-WeExw1IKEkel9ZcYwzpvcFzORIB0IlleTcxJYoEuUgHASuYe/OBYbV6ym/AetG7unNVCBU/SXpgTgs2nT93mhg==}
 | 
			
		||||
    dependencies:
 | 
			
		||||
      '@types/hast': 2.3.4
 | 
			
		||||
      fault: 2.0.1
 | 
			
		||||
      highlight.js: 11.7.0
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /lru-cache/6.0.0:
 | 
			
		||||
    resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
 | 
			
		||||
    engines: {node: '>=10'}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ body {
 | 
			
		|||
    --at-apply: bg-code text-code px1 py0.5 rounded text-0.9em leading-0.8em;
 | 
			
		||||
  }
 | 
			
		||||
  pre code {
 | 
			
		||||
    --at-apply: bg-transparent px0 py0 rounded-none;
 | 
			
		||||
    --at-apply: bg-transparent px0 py0 rounded-none leading-1.6em;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .code-block {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue