import { fromAsyncCodeToHtml } from '@shikijs/markdown-it/async'; import { h } from 'hastscript'; import MarkdownItAsync from 'markdown-it-async'; import { codeToHtml } from 'shiki'; import DOMPurify from 'isomorphic-dompurify'; const md = MarkdownItAsync(); md.use( fromAsyncCodeToHtml( // Pass the codeToHtml function codeToHtml, { themes: { light: 'github-light-default', dark: 'github-dark-default', }, transformers: [ { name: 'shiki-transformer-copy-button', pre(node) { const copyIcon = h( 'svg', { width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', 'stroke-width': '2', 'stroke-linecap': 'round', 'stroke-linejoin': 'round', }, [ h('rect', { width: '14', height: '14', x: '8', y: '8', rx: '2', ry: '2' }), h('path', { d: 'M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2', }), ] ); const checkIcon = h( 'svg', { width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', 'stroke-width': '2', 'stroke-linecap': 'round', 'stroke-linejoin': 'round', }, [h('path', { d: 'M20 6 9 17l-5-5' })] ); const button = h( 'button', { class: 'copy', 'data-code': this.source, onclick: ` navigator.clipboard.writeText(this.dataset.code); this.classList.add('copied'); setTimeout(() => this.classList.remove('copied'), ${3000}) `, }, [ h('span', { class: 'ready', style: 'background-color: transparent !important;' }, [ copyIcon, ]), h( 'span', { class: 'success', style: 'background-color: transparent !important;' }, [checkIcon] ), ] ); node.children.push(button); }, }, ], } ) ); function sanitizeHtml(html: string) { return DOMPurify.sanitize(html); } export { md, sanitizeHtml };