mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
Core: Support remarkCodeTab plugin
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
'fumadocs-ui': major
|
||||
---
|
||||
|
||||
### Migrate to Tailwind CSS v4
|
||||
**Migrate to Tailwind CSS v4**
|
||||
|
||||
**migrate:**
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
'fumadocs-core': minor
|
||||
---
|
||||
|
||||
**Support code block tabs without hardcoding `<Tabs />` items**
|
||||
|
||||
**migrate:** Use the `remarkCodeTab` plugin.
|
||||
|
||||
**before:**
|
||||
|
||||
````mdx
|
||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
|
||||
<Tabs items={["Tab 1", "Tab 2"]}>
|
||||
|
||||
```ts tab
|
||||
console.log('A');
|
||||
```
|
||||
|
||||
```ts tab
|
||||
console.log('B');
|
||||
```
|
||||
|
||||
</Tabs>
|
||||
````
|
||||
|
||||
**after:**
|
||||
|
||||
````mdx
|
||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
|
||||
```ts tab="Tab 1"
|
||||
console.log('A');
|
||||
```
|
||||
|
||||
```ts tab="Tab 2"
|
||||
console.log('B');
|
||||
```
|
||||
````
|
||||
@@ -170,7 +170,7 @@ You can specify the type of callout.
|
||||
Hello World
|
||||
</Callout>
|
||||
|
||||
### Customisation
|
||||
### Customise Components
|
||||
|
||||
See [all MDX components and available options](/docs/ui/mdx).
|
||||
|
||||
@@ -261,38 +261,32 @@ console.log('hewwo'); // [!code --]
|
||||
console.log('hello'); // [!code ++]
|
||||
```
|
||||
|
||||
### As Tab
|
||||
### Tab Groups
|
||||
|
||||
You can use code block as a `<Tab />` component.
|
||||
You can use code blocks with the `<Tab />` component.
|
||||
|
||||
````mdx
|
||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
|
||||
<Tabs items={["Tab 1", "Tab 2"]}>
|
||||
|
||||
```ts tab
|
||||
```ts tab="Tab 1"
|
||||
console.log('A');
|
||||
```
|
||||
|
||||
```ts tab
|
||||
```ts tab="Tab 2"
|
||||
console.log('B');
|
||||
```
|
||||
|
||||
</Tabs>
|
||||
````
|
||||
|
||||
<Tabs items={["Tab 1", "Tab 2"]}>
|
||||
> Note that you can add MDX components instead of importing them in MDX files.
|
||||
|
||||
```ts tab
|
||||
```ts tab="Tab 1"
|
||||
console.log('A');
|
||||
```
|
||||
|
||||
```ts tab
|
||||
```ts tab="Tab 2"
|
||||
console.log('B');
|
||||
```
|
||||
|
||||
</Tabs>
|
||||
|
||||
### Using Typescript Twoslash
|
||||
|
||||
Write Typescript codeblocks with hover type information and detected types errors.
|
||||
|
||||
@@ -8,6 +8,11 @@ const withAnalyzer = createBundleAnalyzer({
|
||||
|
||||
const config: NextConfig = {
|
||||
reactStrictMode: true,
|
||||
logging: {
|
||||
fetches: {
|
||||
fullUrl: true,
|
||||
},
|
||||
},
|
||||
eslint: {
|
||||
// Replaced by root workspace command
|
||||
ignoreDuringBuilds: true,
|
||||
|
||||
@@ -56,7 +56,7 @@ export default defineConfig({
|
||||
return {
|
||||
rehypeCodeOptions: {
|
||||
lazy: true,
|
||||
langs: ['ts', 'js', 'html'],
|
||||
langs: ['ts', 'js', 'html', 'tsx', 'mdx'],
|
||||
inline: 'tailing-curly-colon',
|
||||
themes: {
|
||||
light: 'catppuccin-latte',
|
||||
|
||||
@@ -8,3 +8,4 @@ export * from './remark-structure';
|
||||
export * from './remark-heading';
|
||||
export * from './remark-admonition';
|
||||
export * from './rehype-toc';
|
||||
export * from './remark-code-tab';
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { Transformer } from 'unified';
|
||||
import type { Code, Root, RootContent } from 'mdast';
|
||||
import { visit } from 'unist-util-visit';
|
||||
|
||||
const TabRegex = /tab="(.+?)"/;
|
||||
|
||||
function toTab(nodes: Code[]) {
|
||||
const names = nodes.map((node, i) => {
|
||||
let title = `Tab ${i + 1}`;
|
||||
|
||||
node.meta = node.meta?.replace(TabRegex, (_, value) => {
|
||||
title = value;
|
||||
return '';
|
||||
});
|
||||
|
||||
return title;
|
||||
});
|
||||
|
||||
const itemsArr = {
|
||||
type: 'ExpressionStatement',
|
||||
expression: {
|
||||
type: 'ArrayExpression',
|
||||
elements: names.map((name) => ({
|
||||
type: 'Literal',
|
||||
value: name,
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'Tabs',
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'items',
|
||||
value: {
|
||||
type: 'mdxJsxAttributeValueExpression',
|
||||
data: {
|
||||
estree: {
|
||||
type: 'Program',
|
||||
sourceType: 'module',
|
||||
comments: [],
|
||||
body: [itemsArr],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
children: nodes.map((node, i) => {
|
||||
return {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'Tab',
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'value',
|
||||
value: names[i],
|
||||
},
|
||||
],
|
||||
children: [node],
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function remarkCodeTab(): Transformer<Root, Root> {
|
||||
return (tree) => {
|
||||
visit(tree, (node) => {
|
||||
if (node.type === 'mdxJsxFlowElement' && node.name === 'Tabs') return;
|
||||
if ('children' in node) {
|
||||
let start = -1;
|
||||
let i = 0;
|
||||
|
||||
while (i < node.children.length) {
|
||||
const child = node.children[i];
|
||||
const isSwitcher =
|
||||
child.type === 'code' && child.meta && child.meta.match(TabRegex);
|
||||
|
||||
if (isSwitcher && start === -1) {
|
||||
start = i;
|
||||
}
|
||||
|
||||
// if switcher code blocks terminated, convert them to tabs
|
||||
const isLast = i === node.children.length - 1;
|
||||
if (start !== -1 && (isLast || !isSwitcher)) {
|
||||
const end = isSwitcher ? i + 1 : i;
|
||||
const targets = node.children.slice(start, end);
|
||||
|
||||
node.children.splice(
|
||||
start,
|
||||
end - start,
|
||||
toTab(targets as Code[]) as RootContent,
|
||||
);
|
||||
|
||||
if (isLast) break;
|
||||
i = start;
|
||||
start = -1;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
rehypeCode,
|
||||
type RehypeCodeOptions,
|
||||
rehypeToc,
|
||||
remarkCodeTab,
|
||||
remarkGfm,
|
||||
remarkHeading,
|
||||
type RemarkHeadingOptions,
|
||||
@@ -31,6 +32,7 @@ export type DefaultMDXOptions = Omit<
|
||||
remarkStructureOptions?: StructureOptions | false;
|
||||
remarkHeadingOptions?: RemarkHeadingOptions;
|
||||
remarkImageOptions?: RemarkImageOptions | false;
|
||||
remarkCodeTabOptions?: false;
|
||||
rehypeCodeOptions?: Partial<RehypeCodeOptions> | false;
|
||||
};
|
||||
|
||||
@@ -55,6 +57,7 @@ export function getDefaultMDXOptions({
|
||||
remarkImageOptions,
|
||||
remarkHeadingOptions,
|
||||
remarkStructureOptions,
|
||||
remarkCodeTabOptions,
|
||||
...mdxOptions
|
||||
}: DefaultMDXOptions): ProcessorOptions {
|
||||
const mdxExports = [
|
||||
@@ -75,6 +78,7 @@ export function getDefaultMDXOptions({
|
||||
},
|
||||
],
|
||||
remarkImageOptions !== false && [remarkImage, remarkImageOptions],
|
||||
remarkCodeTabOptions !== false && remarkCodeTab,
|
||||
...v,
|
||||
remarkStructureOptions !== false && [
|
||||
remarkStructure,
|
||||
|
||||
@@ -313,7 +313,10 @@ export function TagsList({
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn('flex flex-row items-center gap-1 flex-wrap', props.className)}
|
||||
className={cn(
|
||||
'flex flex-row items-center gap-1 flex-wrap',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<button
|
||||
|
||||
@@ -77,7 +77,7 @@ export function DocsLayout({
|
||||
|
||||
const tabs = getSidebarTabsFromOptions(tabOptions, props.tree) ?? [];
|
||||
const variables = cn(
|
||||
'[--fd-tocnav-height:36px] md:[--fd-sidebar-width:268px] xl:[--fd-toc-width:268px] xl:[--fd-tocnav-height:0px]',
|
||||
'[--fd-tocnav-height:36px] md:[--fd-sidebar-width:268px] xl:md:[--fd-sidebar-width:286px] xl:[--fd-toc-width:286px] xl:[--fd-tocnav-height:0px]',
|
||||
!navReplace && navEnabled
|
||||
? '[--fd-nav-height:3.5rem] md:[--fd-nav-height:0px]'
|
||||
: undefined,
|
||||
|
||||
@@ -63,7 +63,7 @@ const itemVariants = cva(
|
||||
{
|
||||
variants: {
|
||||
active: {
|
||||
true: 'bg-fd-primary/10 font-medium text-fd-primary',
|
||||
true: 'bg-fd-primary/10 text-fd-primary',
|
||||
false:
|
||||
'transition-colors hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user