Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ const config = {
],
copyright: `Copyright © ${new Date().getFullYear()} ByteBardOrg.`,
},
prism: {theme: prismThemes.github, darkTheme: prismThemes.dracula, additionalLanguages: ['csharp']},
// Code is highlighted with Shiki (src/theme/CodeBlock/Content); these Prism themes only color the code block
// around it, and match the background of Shiki's Visual Studio Code themes.
prism: {theme: prismThemes.vsLight, darkTheme: prismThemes.vsDark},
},
};

Expand Down
186 changes: 185 additions & 1 deletion website/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"clsx": "^2.1.1",
"prism-react-renderer": "^2.4.1",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"shiki": "^4.5.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.8.1",
Expand Down
15 changes: 15 additions & 0 deletions website/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,18 @@ html[data-theme='dark'] .navbar__items--right .navbar__link:hover {color: #a87ef
html:not([data-theme='dark']) .navbar-sidebar .menu__link--active,
html[data-theme='dark'] .navbar-sidebar .menu__link--active {color: #a87efc}
}

/* Code tokens carry both color modes' styles as CSS variables (src/theme/CodeBlock/Content/shiki.js). */
.shiki-token {
color: var(--shiki-light);
font-style: var(--shiki-light-font-style);
font-weight: var(--shiki-light-font-weight);
text-decoration: var(--shiki-light-text-decoration);
}

html[data-theme='dark'] .shiki-token {
color: var(--shiki-dark);
font-style: var(--shiki-dark-font-style);
font-weight: var(--shiki-dark-font-weight);
text-decoration: var(--shiki-dark-text-decoration);
}
74 changes: 74 additions & 0 deletions website/src/theme/CodeBlock/Content/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Swizzled from @docusaurus/theme-classic to highlight code with Shiki instead of Prism. The Prism-shaped
* line and token props are kept, so the theme's Line component still renders line numbers and highlighted lines.
*/
import React, {useMemo} from 'react';
import clsx from 'clsx';
import {useCodeBlockContext} from '@docusaurus/theme-common/internal';
import Line from '@theme/CodeBlock/Line';
import {highlight} from './shiki';
import styles from './styles.module.css';

const Pre = React.forwardRef((props, ref) => {
return (
<pre
ref={ref}
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
tabIndex={0}
{...props}
className={clsx(props.className, styles.codeBlock, 'thin-scrollbar')}
/>
);
});

function Code(props) {
const {metadata} = useCodeBlockContext();
return (
<code
{...props}
className={clsx(
props.className,
styles.codeBlockLines,
metadata.lineNumbersStart !== undefined && styles.codeBlockLinesWithNumbering,
)}
style={{
...props.style,
counterReset: metadata.lineNumbersStart === undefined ? undefined : `line-count ${metadata.lineNumbersStart - 1}`,
}}
/>
);
}

function getLineProps({className}) {
return {className: clsx('token-line', className)};
}

function getTokenProps({token}) {
return {className: 'token shiki-token', style: token.style, children: token.content};
}

export default function CodeBlockContent({className}) {
const {metadata, wordWrap} = useCodeBlockContext();
const {code, language, lineNumbersStart, lineClassNames} = metadata;
const lines = useMemo(
() => highlight(code, language).map((line) => line.map((token) => ({content: token.content, style: token.htmlStyle}))),
[code, language],
);

return (
<Pre ref={wordWrap.codeBlockRef} className={clsx(className, `language-${language}`)}>
<Code>
{lines.map((line, i) => (
<Line
key={i}
line={line}
getLineProps={getLineProps}
getTokenProps={getTokenProps}
classNames={lineClassNames[i]}
showLineNumbers={lineNumbersStart !== undefined}
/>
))}
</Code>
</Pre>
);
}
28 changes: 28 additions & 0 deletions website/src/theme/CodeBlock/Content/shiki.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {createHighlighterCoreSync} from 'shiki/core';
import {createJavaScriptRegexEngine} from 'shiki/engine/javascript';
import csharp from '@shikijs/langs/csharp';
import json from '@shikijs/langs/json';
import shellscript from '@shikijs/langs/shellscript';
import yaml from '@shikijs/langs/yaml';
import darkPlus from '@shikijs/themes/dark-plus';
import lightPlus from '@shikijs/themes/light-plus';

// The Visual Studio Code themes, matching prismThemes.vsLight and prismThemes.vsDark in docusaurus.config.js,
// which style the rest of the code block.
const themes = {light: 'light-plus', dark: 'dark-plus'};

// Synchronous, so code blocks render the same on the server and in the browser.
const highlighter = createHighlighterCoreSync({
themes: [lightPlus, darkPlus],
langs: [csharp, json, shellscript, yaml],
engine: createJavaScriptRegexEngine(),
});

/**
* Tokenizes code into lines of tokens, each styled with both themes' colors as CSS variables
* (--shiki-light and --shiki-dark), which custom.css applies for the current color mode.
*/
export function highlight(code, language) {
const lang = highlighter.getLoadedLanguages().includes(language) ? language : 'text';
return highlighter.codeToTokens(code, {lang, themes, defaultColor: false}).tokens;
}
Loading
Loading