mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(site): tabs (#144)
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import type { SharedProps } from './Shared';
|
||||
import css from 'shiki/langs/css.mjs';
|
||||
import html from 'shiki/langs/html.mjs';
|
||||
import javascript from 'shiki/langs/javascript.mjs';
|
||||
import tsx from 'shiki/langs/tsx.mjs';
|
||||
|
||||
import createHighlighter from './createHighlighter';
|
||||
import Shared from './Shared';
|
||||
|
||||
// eslint-disable-next-line antfu/no-top-level-await
|
||||
const clientHighlighter = await createHighlighter({
|
||||
langs: [html, tsx, css, javascript],
|
||||
});
|
||||
|
||||
/**
|
||||
* Renders HTML, TSX, CSS, and JavaScript. A strict subset, for lighter-weight client shipping
|
||||
*
|
||||
* Renders with top-level await, so, it's safe for ssr (client:idle or client:load)
|
||||
* However, if you try importing more than one island with ClientCode in it,
|
||||
* Safari MAY throw a hydration error because of this top-level await.
|
||||
* https://github.com/withastro/astro/issues/10055
|
||||
* consolidate the ClientCodes into a single island to work around... for now :(
|
||||
*/
|
||||
export default function ClientCode(props: Omit<SharedProps, 'highlighter'>) {
|
||||
return <Shared {...props} highlighter={clientHighlighter} />;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
import type { SharedProps } from './Shared';
|
||||
import Shared from './Shared';
|
||||
import serverHighlighter from './serverHighlighter';
|
||||
|
||||
type Props = Omit<SharedProps, 'highlighter'>;
|
||||
const props = Astro.props;
|
||||
---
|
||||
|
||||
<Shared {...props} highlighter={serverHighlighter} />
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { BundledLanguage, Highlighter } from 'shiki';
|
||||
import clsx from 'clsx';
|
||||
import { hastToHtml } from 'shiki';
|
||||
|
||||
export interface SharedProps {
|
||||
code: string;
|
||||
lang: BundledLanguage;
|
||||
highlighter: Highlighter;
|
||||
}
|
||||
|
||||
export default function Shared({ code, lang, highlighter }: SharedProps) {
|
||||
const hast = highlighter.codeToHast(code, {
|
||||
lang,
|
||||
themes: {
|
||||
light: 'gruvbox-light-hard',
|
||||
dark: 'gruvbox-dark-soft',
|
||||
},
|
||||
});
|
||||
|
||||
// shiki gives us a root > pre > code > text structure
|
||||
// since we want to define pre and code ourselves, let's extract the text
|
||||
let preProps: Record<string, any> = {};
|
||||
let codeProps: Record<string, any> = {};
|
||||
if (hast.type === 'root') {
|
||||
const pre = hast.children[0];
|
||||
if (pre && pre.type === 'element' && pre.tagName === 'pre') {
|
||||
preProps = pre.properties;
|
||||
const code = pre.children[0];
|
||||
if (code && code.type === 'element' && code.tagName === 'code') {
|
||||
codeProps = code.properties;
|
||||
// everything looked as expected! Let's use the code's children as the new root
|
||||
hast.children = code.children;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const html = hastToHtml(hast);
|
||||
const { class: preClassName } = preProps;
|
||||
const { class: codeClassName } = codeProps;
|
||||
|
||||
return (
|
||||
<pre className={clsx('shiki', preClassName)}>
|
||||
<code
|
||||
className={clsx('font-mono text-code', codeClassName)}
|
||||
// eslint-disable-next-line react-dom/no-dangerously-set-innerhtml
|
||||
dangerouslySetInnerHTML={{ __html: html }}
|
||||
/>
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { createHighlighter as libCreateHighlighter } from 'shiki';
|
||||
import gruvboxDarkSoft from 'shiki/themes/gruvbox-dark-soft.mjs';
|
||||
import gruvboxLightHard from 'shiki/themes/gruvbox-light-hard.mjs';
|
||||
|
||||
export default function createHighlighter(
|
||||
config: Omit<Parameters<typeof libCreateHighlighter>[0], 'themes'>,
|
||||
) {
|
||||
return libCreateHighlighter(
|
||||
{
|
||||
...config,
|
||||
themes: [gruvboxLightHard, gruvboxDarkSoft],
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { bundledLanguages } from 'shiki';
|
||||
import createHighlighter from './createHighlighter';
|
||||
|
||||
// eslint-disable-next-line antfu/no-top-level-await
|
||||
const serverHighlighter = await createHighlighter({
|
||||
langs: Object.values(bundledLanguages),
|
||||
});
|
||||
// TODO memory leak?
|
||||
export default serverHighlighter;
|
||||
Reference in New Issue
Block a user