Skip to content

Commit

Permalink
Core: Fix remarkAdmonition missing some types from Docusaurus
Browse files Browse the repository at this point in the history
  • Loading branch information
fuma-nama committed Jan 27, 2025
1 parent f2f9c3d commit bc62449
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 42 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-stingrays-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'fumadocs-core': patch
---

Fix `remarkAdmonition` missing some types from Docusaurus
71 changes: 36 additions & 35 deletions packages/core/src/mdx-plugins/remark-admonition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { flattenNode } from '@/mdx-plugins/remark-utils';

export interface RemarkAdmonitionOptions {
tag?: string;
types?: string[];

/**
* Map type to another type
Expand All @@ -21,78 +20,80 @@ export interface RemarkAdmonitionOptions {
export function remarkAdmonition(
options: RemarkAdmonitionOptions = {},
): Transformer<Root, Root> {
const types = options.types ?? ['warn', 'info', 'error'];
const tag = options.tag ?? ':::';
// compatible with Docusaurus
const typeMap = options.typeMap ?? {
info: 'info',
warn: 'warn',

note: 'info',
tip: 'info',
warning: 'warn',
danger: 'error',
};

function replaceNodes(nodes: RootContent[]): RootContent[] {
if (nodes.length === 0) return nodes;
let open = -1,
end = -1;
function replaceNodes(nodes: RootContent[]) {
if (nodes.length === 0) return;

const attributes = [];
let open = -1;
let attributes = [];
// if children contain nested admonitions
let hasIntercept = false;

for (let i = 0; i < nodes.length; i++) {
if (nodes[i].type !== 'paragraph') continue;

const text = flattenNode(nodes[i]);
const start = types.find((type) => text.startsWith(`${tag}${type}`));
const typeName = Object.keys(typeMap).find((type) =>
text.startsWith(`${tag}${type}`),
);

if (typeName) {
if (open !== -1) {
hasIntercept = true;
continue;
}

if (start) {
if (open !== -1) throw new Error('Nested callout is not supported');
open = i;

attributes.push({
type: 'mdxJsxAttribute',
name: 'type',
value: start in typeMap ? typeMap[start] : start,
value: typeMap[typeName],
});

const rest = text.slice(`${tag}${start}`.length);
if (rest.startsWith('[') && rest.endsWith(']')) {
const meta = text.slice(`${tag}${typeName}`.length);
if (meta.startsWith('[') && meta.endsWith(']')) {
attributes.push({
type: 'mdxJsxAttribute',
name: 'title',
value: rest.slice(1, -1),
value: meta.slice(1, -1),
});
}
}

if (open !== -1 && text === tag) {
end = i;
break;
const children = nodes.slice(open + 1, i);

nodes.splice(open, i - open + 1, {
type: 'mdxJsxFlowElement',
name: 'Callout',
attributes,
children: hasIntercept ? replaceNodes(children) : children,
} as RootContent);
open = -1;
hasIntercept = false;
attributes = [];
i = open + 1;
}
}

if (open === -1 || end === -1) return nodes;

return [
...nodes.slice(0, open),
{
type: 'mdxJsxFlowElement',
name: 'Callout',
attributes,
children: nodes.slice(open + 1, end),
} as RootContent,
...replaceNodes(nodes.slice(end + 1)),
];
}

return (tree) => {
visit(tree, (node) => {
if (!('children' in node)) return 'skip';

const result = replaceNodes(node.children);
if (result === node.children) return;
if (!('children' in node)) return;

node.children = result;
return 'skip';
replaceNodes(node.children);
});
};
}
2 changes: 1 addition & 1 deletion packages/core/test/fixtures/remark-admonition.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
:::info
:::tip

Hello World

Expand Down
13 changes: 7 additions & 6 deletions packages/ui/src/layouts/docs/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ interface InternalContext {
}

const itemVariants = cva(
'relative flex flex-row items-center gap-2 rounded-md p-2 text-start text-fd-muted-foreground [overflow-wrap:anywhere] md:py-1.5 [&_svg]:size-4 [&_svg]:shrink-0',
'relative flex flex-row items-center gap-2 rounded-md px-2 text-start text-fd-muted-foreground [overflow-wrap:anywhere] py-1.5 [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
active: {
Expand Down Expand Up @@ -359,7 +359,11 @@ export function SidebarFolderLink({
}

export function SidebarFolderContent(props: CollapsibleContentProps) {
return <CollapsibleContent {...props}>{props.children}</CollapsibleContent>;
return (
<CollapsibleContent {...props}>
<div className="pt-1">{props.children}</div>
</CollapsibleContent>
);
}

export function SidebarCollapseTrigger(
Expand Down Expand Up @@ -519,12 +523,9 @@ function Border({ depth, active }: { depth: number; active?: boolean }) {
return (
<div
className={cn(
'absolute w-px inset-y-0 bg-fd-border z-[2]',
'absolute w-px inset-y-0 bg-fd-border z-[2] start-3',
active && 'bg-fd-primary',
)}
style={{
insetInlineStart: `calc(var(--spacing) * 2 + 1px)`,
}}
/>
);
}

0 comments on commit bc62449

Please sign in to comment.