Core & UI: Support Shiki diff transformer

This commit is contained in:
fuma-nama
2024-10-05 19:51:06 +08:00
parent 185a98136f
commit f949520193
6 changed files with 79 additions and 16 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'fumadocs-core': patch
'fumadocs-ui': patch
---
Support Shiki diff transformer
+16 -2
View File
@@ -205,7 +205,7 @@ See [Page Conventions](/docs/ui/page-conventions#frontmatter) for a list of prop
## Codeblock
Syntax Highlighting is done with [Rehype Code](/docs/headless/mdx/rehype-code) automatically.
Syntax Highlighting is supported by default using [Rehype Code](/docs/headless/mdx/rehype-code).
````mdx
```js
@@ -223,7 +223,7 @@ console.log('Hello World');
### Highlight Lines
You spectify highlighted lines by adding `[!code highlight]`.
You can highlight specific lines by adding `[!code highlight]`.
````md
```tsx
@@ -247,6 +247,20 @@ const config = {
```
````
### Diffs
````mdx
```ts
console.log('hewwo'); // [\!code --]
console.log('hello'); // [\!code ++]
```
````
```ts
console.log('hewwo'); // [!code --]
console.log('hello'); // [!code ++]
```
### As Tab
You can use code block as a `<Tab />` component.
+17 -2
View File
@@ -16,7 +16,6 @@ import {
} from 'fumadocs-docgen';
import rehypeKatex from 'rehype-katex';
import { z } from 'zod';
import { transformerRemoveNotationEscape } from '@shikijs/transformers';
export const { docs, meta } = defineDocs({
docs: {
@@ -57,7 +56,23 @@ export default defineConfig({
transformers: [
...(rehypeCodeDefaultOptions.transformers ?? []),
transformerTwoslash(),
transformerRemoveNotationEscape(),
{
name: 'transformers:remove-notation-escape',
code(hast) {
for (const line of hast.children) {
if (line.type !== 'element') continue;
const lastSpan = line.children.findLast(
(v) => v.type === 'element',
);
const head = lastSpan?.children[0];
if (head?.type !== 'text') return;
head.value = head.value.replace(/\[\\!code/g, '[!code');
}
},
},
],
},
remarkPlugins: [
@@ -2,6 +2,7 @@ import type { Root } from 'hast';
import type { RehypeShikiOptions } from '@shikijs/rehype';
import rehypeShikiFromHighlighter from '@shikijs/rehype/core';
import {
transformerNotationDiff,
transformerNotationHighlight,
transformerNotationWordHighlight,
} from '@shikijs/transformers';
@@ -52,6 +53,7 @@ export const rehypeCodeDefaultOptions: RehypeCodeOptions = {
transformers: [
transformerNotationHighlight(),
transformerNotationWordHighlight(),
transformerNotationDiff(),
],
parseMetaString(meta) {
const map: Record<string, string> = {};
+2 -1
View File
@@ -84,7 +84,8 @@ export const CodeBlock = forwardRef<HTMLElement, CodeBlockProps>(
ref={ref}
className={cn(
'not-prose group fd-codeblock relative my-6 overflow-hidden rounded-lg border bg-fd-secondary/50 text-sm',
keepBackground && 'fd-codeblock-keep-bg',
keepBackground &&
'bg-[var(--shiki-light-bg)] dark:bg-[var(--shiki-dark-bg)]',
className,
)}
{...props}
+36 -11
View File
@@ -133,6 +133,11 @@ export const docsUi = plugin.withOptions<DocsUIOptions>(
'--fd-doc':
'calc(min(100vw, var(--fd-layout-width)) - var(--fd-toc-width) - var(--fd-sidebar-width))',
'--fd-c-sidebar': 'var(--fd-sidebar-width)',
'--fd-diff-remove-color': 'rgba(200,10,100,0.12)',
'--fd-diff-remove-symbol-color': 'rgb(200,10,100)',
'--fd-diff-add-color': 'rgba(14,180,100,0.12)',
'--fd-diff-add-symbol-color': 'rgb(10,200,100)',
},
'.dark': getThemeStyles(cssPrefix, dark),
'*': {
@@ -162,7 +167,8 @@ export const docsUi = plugin.withOptions<DocsUIOptions>(
if (css) addComponents(css);
addComponents({
// Shiki styles
addBase({
'.shiki code span': {
color: 'var(--shiki-light)',
},
@@ -173,24 +179,43 @@ export const docsUi = plugin.withOptions<DocsUIOptions>(
display: 'grid',
'font-size': '13px',
},
'.shiki code .diff.remove': {
backgroundColor: 'var(--fd-diff-remove-color)',
opacity: '0.7',
},
'.shiki code .diff::before': {
position: 'absolute',
left: '6px',
},
'.shiki code .diff.remove::before': {
content: "'-'",
color: 'var(--fd-diff-remove-symbol-color)',
},
'.shiki code .diff.add': {
backgroundColor: 'var(--fd-diff-add-color)',
},
'.shiki code .diff.add::before': {
content: "'+'",
color: 'var(--fd-diff-add-symbol-color)',
},
'.shiki code .diff': {
margin: '0 -16px',
padding: '0 16px',
display: 'inline-block',
},
'.shiki .highlighted': {
margin: '0 -16px',
padding: '0 16px',
'background-color': `theme('colors.fd-primary.DEFAULT / 10%')`,
backgroundColor: `theme('colors.fd-primary.DEFAULT / 10%')`,
},
'.shiki .highlighted-word': {
padding: '1px 2px',
margin: '-1px -3px',
border: '1px solid',
'border-color': `theme('colors.fd-primary.DEFAULT / 50%')`,
'background-color': `theme('colors.fd-primary.DEFAULT / 10%')`,
'border-radius': '2px',
},
'.fd-codeblock-keep-bg': {
'background-color': 'var(--shiki-light-bg)',
},
'.dark .fd-codeblock-keep-bg': {
'background-color': 'var(--shiki-dark-bg)',
borderColor: `theme('colors.fd-primary.DEFAULT / 50%')`,
backgroundColor: `theme('colors.fd-primary.DEFAULT / 10%')`,
borderRadius: '2px',
},
});