@terrafirmagreg-team/mdx 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -4
- package/src/components/mdx-components.tsx +6 -4
- package/src/components/mdx-story.tsx +8 -0
- package/src/components/story-panel.tsx +1 -1
- package/src/lib/md-plugins.ts +11 -23
- package/src/lib/mdx/accordions.ts +14 -3
- package/src/lib/mdx/banner.ts +0 -1
- package/src/lib/mdx/callouts.ts +153 -0
- package/src/lib/mdx/directive-fallback.ts +87 -0
- package/src/lib/mdx/directive-utils.ts +1 -1
- package/src/lib/mdx/directives.ts +59 -118
- package/src/lib/mdx/entries/block.ts +6 -0
- package/src/lib/mdx/entries/entity.ts +6 -0
- package/src/lib/mdx/entries/factory.ts +102 -0
- package/src/lib/mdx/entries/fluid.ts +6 -0
- package/src/lib/mdx/entries/guide.ts +6 -0
- package/src/lib/mdx/entries/image.ts +9 -0
- package/src/lib/mdx/entries/index.ts +45 -0
- package/src/lib/mdx/entries/item.ts +6 -0
- package/src/lib/mdx/entries/multiblock.ts +16 -0
- package/src/lib/mdx/entries/quest.ts +6 -0
- package/src/lib/mdx/entries/recipe.ts +6 -0
- package/src/lib/mdx/entries/story.ts +6 -0
- package/src/lib/mdx/entries/tag.ts +6 -0
- package/src/lib/mdx/files.ts +129 -0
- package/src/lib/mdx/{references.ts → github-autolinks.ts} +16 -5
- package/src/lib/mdx/tabs.ts +0 -1
- package/src/lib/story-remark.ts +97 -31
- package/src/lib/story.ts +22 -1
- package/src/lib/mdx/game-export.ts +0 -110
- package/src/lib/mdx/html-style.ts +0 -136
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
contentChildren,
|
|
3
|
+
extractDirectiveLabel,
|
|
4
|
+
extractLeafLabel,
|
|
5
|
+
estreeBoolean,
|
|
6
|
+
estreeString,
|
|
7
|
+
jsxAttr,
|
|
8
|
+
jsxExpression,
|
|
9
|
+
walkDirectives,
|
|
10
|
+
type DirectiveNode,
|
|
11
|
+
type JsxAttribute,
|
|
12
|
+
type MdastNode,
|
|
13
|
+
} from '../directive-utils.ts';
|
|
14
|
+
|
|
15
|
+
export type EntrySpec = {
|
|
16
|
+
directive: string;
|
|
17
|
+
component: string;
|
|
18
|
+
leafKey?: string;
|
|
19
|
+
labelAttr?: string;
|
|
20
|
+
usePagePack?: boolean;
|
|
21
|
+
transform?: (ctx: {
|
|
22
|
+
directive: DirectiveNode;
|
|
23
|
+
attrs: JsxAttribute[];
|
|
24
|
+
children: MdastNode[];
|
|
25
|
+
isLeaf: boolean;
|
|
26
|
+
file: { path?: string };
|
|
27
|
+
}) => MdastNode[] | void;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function pageDataset(file: { path?: string }): string | undefined {
|
|
31
|
+
return file.path
|
|
32
|
+
?.replaceAll('\\', '/')
|
|
33
|
+
.match(/content\/docs\/([^/]+)\/[^/]+\//)?.[1];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function toAttributes(directive: DirectiveNode): JsxAttribute[] {
|
|
37
|
+
return Object.entries(directive.attributes ?? {}).map(([name, value]) => ({
|
|
38
|
+
type: 'mdxJsxAttribute' as const,
|
|
39
|
+
name,
|
|
40
|
+
value:
|
|
41
|
+
value == null || value === ''
|
|
42
|
+
? jsxExpression(estreeBoolean(true))
|
|
43
|
+
: typeof value === 'string'
|
|
44
|
+
? value
|
|
45
|
+
: jsxExpression(estreeString(String(value))),
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function createEntryRemark(spec: EntrySpec) {
|
|
50
|
+
const {
|
|
51
|
+
directive: name,
|
|
52
|
+
component,
|
|
53
|
+
leafKey = 'id',
|
|
54
|
+
labelAttr = 'label',
|
|
55
|
+
usePagePack = false,
|
|
56
|
+
transform,
|
|
57
|
+
} = spec;
|
|
58
|
+
|
|
59
|
+
return function remark() {
|
|
60
|
+
return (tree: MdastNode, file: { path?: string }) => {
|
|
61
|
+
walkDirectives(tree, (directive) => {
|
|
62
|
+
if (directive.name !== name) return;
|
|
63
|
+
if (
|
|
64
|
+
directive.type !== 'leafDirective' &&
|
|
65
|
+
directive.type !== 'containerDirective'
|
|
66
|
+
)
|
|
67
|
+
return;
|
|
68
|
+
|
|
69
|
+
const attrs = toAttributes(directive);
|
|
70
|
+
const pack = usePagePack ? pageDataset(file) : undefined;
|
|
71
|
+
if (
|
|
72
|
+
pack &&
|
|
73
|
+
directive.attributes?.pack == null &&
|
|
74
|
+
directive.attributes?.defaultPack == null
|
|
75
|
+
) {
|
|
76
|
+
attrs.push(jsxAttr('defaultPack', pack));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const isLeaf = directive.type === 'leafDirective';
|
|
80
|
+
const label = (
|
|
81
|
+
isLeaf
|
|
82
|
+
? extractLeafLabel(directive)
|
|
83
|
+
: extractDirectiveLabel(directive)
|
|
84
|
+
).trim();
|
|
85
|
+
const key = isLeaf ? leafKey : labelAttr;
|
|
86
|
+
if (label && key) attrs.unshift(jsxAttr(key, label));
|
|
87
|
+
|
|
88
|
+
const children = isLeaf ? [] : contentChildren(directive);
|
|
89
|
+
const out =
|
|
90
|
+
transform?.({ directive, attrs, children, isLeaf, file }) ??
|
|
91
|
+
children;
|
|
92
|
+
|
|
93
|
+
Object.assign(directive, {
|
|
94
|
+
type: 'mdxJsxFlowElement',
|
|
95
|
+
name: component,
|
|
96
|
+
attributes: attrs,
|
|
97
|
+
children: out,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { MdastNode } from '../directive-utils.ts';
|
|
2
|
+
import { remarkBlockEntry } from './block.ts';
|
|
3
|
+
import { remarkEntityEntry } from './entity.ts';
|
|
4
|
+
import { remarkFluidEntry } from './fluid.ts';
|
|
5
|
+
import { remarkGuideEntry } from './guide.ts';
|
|
6
|
+
import { remarkImageEntry } from './image.ts';
|
|
7
|
+
import { remarkItemEntry } from './item.ts';
|
|
8
|
+
import { remarkMultiblockEntry } from './multiblock.ts';
|
|
9
|
+
import { remarkQuestEntry } from './quest.ts';
|
|
10
|
+
import { remarkRecipeEntry } from './recipe.ts';
|
|
11
|
+
import { remarkStoryEntry } from './story.ts';
|
|
12
|
+
import { remarkTagEntry } from './tag.ts';
|
|
13
|
+
|
|
14
|
+
export { remarkBlockEntry } from './block.ts';
|
|
15
|
+
export { remarkEntityEntry } from './entity.ts';
|
|
16
|
+
export { remarkFluidEntry } from './fluid.ts';
|
|
17
|
+
export { remarkGuideEntry } from './guide.ts';
|
|
18
|
+
export { remarkImageEntry } from './image.ts';
|
|
19
|
+
export { remarkItemEntry } from './item.ts';
|
|
20
|
+
export { remarkMultiblockEntry } from './multiblock.ts';
|
|
21
|
+
export { remarkQuestEntry } from './quest.ts';
|
|
22
|
+
export { remarkRecipeEntry } from './recipe.ts';
|
|
23
|
+
export { remarkStoryEntry } from './story.ts';
|
|
24
|
+
export { remarkTagEntry } from './tag.ts';
|
|
25
|
+
|
|
26
|
+
const ALL = [
|
|
27
|
+
remarkItemEntry,
|
|
28
|
+
remarkBlockEntry,
|
|
29
|
+
remarkFluidEntry,
|
|
30
|
+
remarkEntityEntry,
|
|
31
|
+
remarkTagEntry,
|
|
32
|
+
remarkQuestEntry,
|
|
33
|
+
remarkGuideEntry,
|
|
34
|
+
remarkMultiblockEntry,
|
|
35
|
+
remarkImageEntry,
|
|
36
|
+
remarkStoryEntry,
|
|
37
|
+
remarkRecipeEntry,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
export function remarkEntries() {
|
|
41
|
+
const plugins = ALL.map((factory) => factory());
|
|
42
|
+
return (tree: MdastNode, file: { path?: string }) => {
|
|
43
|
+
for (const plugin of plugins) plugin(tree, file);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsxAttr, type MdastNode } from '../directive-utils.ts';
|
|
2
|
+
import { createEntryRemark } from './factory.ts';
|
|
3
|
+
|
|
4
|
+
export const remarkMultiblockEntry = createEntryRemark({
|
|
5
|
+
directive: 'multiblock',
|
|
6
|
+
component: 'Multiblock',
|
|
7
|
+
transform({ directive, attrs, isLeaf }) {
|
|
8
|
+
if (isLeaf) return;
|
|
9
|
+
const code = directive.children?.find(
|
|
10
|
+
(child) => child.type === 'code',
|
|
11
|
+
) as { value?: string } | undefined;
|
|
12
|
+
if (!code?.value) return;
|
|
13
|
+
attrs.unshift(jsxAttr('spec', code.value));
|
|
14
|
+
return [] as MdastNode[];
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FileNode,
|
|
3
|
+
FolderNode,
|
|
4
|
+
ToMdxOptions,
|
|
5
|
+
} from 'fumadocs-core/mdx-plugins/remark-mdx-files';
|
|
6
|
+
import { toString } from 'mdast-util-to-string';
|
|
7
|
+
import { visit } from 'unist-util-visit';
|
|
8
|
+
import type { DirectiveNode } from './directive-utils.ts';
|
|
9
|
+
import type { JsxAttribute, JsxElement, MdastNode } from '../../types/mdx';
|
|
10
|
+
|
|
11
|
+
type TreeNode = FileNode | FolderNode;
|
|
12
|
+
|
|
13
|
+
const LINK_RE = /^\[([^\]]+)\]\((\S+?)(?:\s+"([^"]*)")?\)$/;
|
|
14
|
+
|
|
15
|
+
type TreeName = { name: string; href?: string; description?: string };
|
|
16
|
+
|
|
17
|
+
function parseName(raw: string): TreeName {
|
|
18
|
+
const match = LINK_RE.exec(raw.trim());
|
|
19
|
+
if (!match) return { name: raw };
|
|
20
|
+
const [, text, href, description] = match;
|
|
21
|
+
const out: TreeName = { name: text, href };
|
|
22
|
+
if (description) out.description = description;
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function attributes(parsed: TreeName): JsxAttribute[] {
|
|
27
|
+
const attrs: JsxAttribute[] = [
|
|
28
|
+
{ type: 'mdxJsxAttribute', name: 'name', value: parsed.name },
|
|
29
|
+
];
|
|
30
|
+
if (parsed.href)
|
|
31
|
+
attrs.push({ type: 'mdxJsxAttribute', name: 'href', value: parsed.href });
|
|
32
|
+
if (parsed.description)
|
|
33
|
+
attrs.push({
|
|
34
|
+
type: 'mdxJsxAttribute',
|
|
35
|
+
name: 'description',
|
|
36
|
+
value: parsed.description,
|
|
37
|
+
});
|
|
38
|
+
return attrs;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function nodeToMdx(node: TreeNode, options: ToMdxOptions): JsxElement {
|
|
42
|
+
const parsed = parseName(node.name);
|
|
43
|
+
const attrs = attributes(parsed);
|
|
44
|
+
const isFolder = node.type === 'folder' || parsed.name.endsWith('/');
|
|
45
|
+
if (!isFolder)
|
|
46
|
+
return {
|
|
47
|
+
type: 'mdxJsxFlowElement',
|
|
48
|
+
name: 'File',
|
|
49
|
+
attributes: attrs,
|
|
50
|
+
children: [],
|
|
51
|
+
};
|
|
52
|
+
if (options.defaultOpenAll)
|
|
53
|
+
attrs.push({ type: 'mdxJsxAttribute', name: 'defaultOpen', value: true });
|
|
54
|
+
const children =
|
|
55
|
+
node.type === 'folder'
|
|
56
|
+
? node.children.map((item) => nodeToMdx(item, options) as unknown as MdastNode)
|
|
57
|
+
: [];
|
|
58
|
+
return {
|
|
59
|
+
type: 'mdxJsxFlowElement',
|
|
60
|
+
name: 'Folder',
|
|
61
|
+
attributes: attrs,
|
|
62
|
+
children,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function filesToMdx(node: TreeNode, options: ToMdxOptions): JsxElement {
|
|
67
|
+
return {
|
|
68
|
+
type: 'mdxJsxFlowElement',
|
|
69
|
+
name: 'Files',
|
|
70
|
+
attributes: [],
|
|
71
|
+
children:
|
|
72
|
+
node.type === 'folder' && node.name === ''
|
|
73
|
+
? node.children.map((item) => nodeToMdx(item, options) as unknown as MdastNode)
|
|
74
|
+
: [nodeToMdx(node, options) as unknown as MdastNode],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type ListNode = MdastNode & { children?: MdastNode[] };
|
|
79
|
+
|
|
80
|
+
function itemToTree(item: ListNode): TreeNode {
|
|
81
|
+
const paragraph = item.children?.find((c) => c.type === 'paragraph');
|
|
82
|
+
const nested = item.children?.find((c) => c.type === 'list');
|
|
83
|
+
const link =
|
|
84
|
+
paragraph?.children?.length === 1 &&
|
|
85
|
+
paragraph.children[0].type === 'link'
|
|
86
|
+
? (paragraph.children[0] as unknown as {
|
|
87
|
+
url: string;
|
|
88
|
+
title?: string | null;
|
|
89
|
+
children: { value: string }[];
|
|
90
|
+
})
|
|
91
|
+
: undefined;
|
|
92
|
+
let name = link ? toString(link.children[0] as never) : toString(paragraph as never);
|
|
93
|
+
const href = link?.url;
|
|
94
|
+
const description = link?.title ?? undefined;
|
|
95
|
+
const annotated = href ? `[${name}](${href}${description ? ` "${description}"` : ''})` : name;
|
|
96
|
+
const isFolder = !!nested || name.endsWith('/');
|
|
97
|
+
if (isFolder) name = name.replace(/\/+$/, '') || name;
|
|
98
|
+
if (!isFolder) return { type: 'file', name: annotated } as FileNode;
|
|
99
|
+
const children = (nested?.children ?? []).map(
|
|
100
|
+
(child) => itemToTree(child as ListNode) as TreeNode,
|
|
101
|
+
);
|
|
102
|
+
return {
|
|
103
|
+
type: 'folder',
|
|
104
|
+
name: href ? `[${name}/](${href}${description ? ` "${description}"` : ''})` : name,
|
|
105
|
+
children,
|
|
106
|
+
} as FolderNode;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function remarkFilesDirective() {
|
|
110
|
+
return (tree: MdastNode) => {
|
|
111
|
+
visit(tree as never, 'containerDirective', (node) => {
|
|
112
|
+
const directive = node as DirectiveNode;
|
|
113
|
+
if (directive.name !== 'files') return;
|
|
114
|
+
const children = (directive.children ?? []).flatMap((child) =>
|
|
115
|
+
child.type === 'list' ? (child.children ?? []) : [],
|
|
116
|
+
);
|
|
117
|
+
if (!children.length) return;
|
|
118
|
+
const root: FolderNode = {
|
|
119
|
+
type: 'folder',
|
|
120
|
+
name: '',
|
|
121
|
+
children: children.map((item) => itemToTree(item as ListNode)),
|
|
122
|
+
} as FolderNode;
|
|
123
|
+
Object.assign(
|
|
124
|
+
directive,
|
|
125
|
+
filesToMdx(root, { defaultOpenAll: true }),
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
}
|
|
@@ -3,6 +3,7 @@ type MdastNode = {
|
|
|
3
3
|
value?: string;
|
|
4
4
|
url?: string;
|
|
5
5
|
children?: MdastNode[];
|
|
6
|
+
data?: { hProperties?: Record<string, unknown> };
|
|
6
7
|
};
|
|
7
8
|
|
|
8
9
|
const ISSUE_REF = /^#\d+$/;
|
|
@@ -18,12 +19,21 @@ const SKIP = new Set([
|
|
|
18
19
|
'html',
|
|
19
20
|
]);
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
+
const DEFAULT_PATHS = [
|
|
23
|
+
/[/\\]changelog[/\\]([^/\\]+)[/\\]/,
|
|
24
|
+
/[/\\]docs[/\\]([^/\\]+)[/\\][^/\\]+[/\\]major-changelogs[/\\]/,
|
|
25
|
+
];
|
|
22
26
|
|
|
23
|
-
export function
|
|
24
|
-
|
|
27
|
+
export function remarkGithubAutolinks(options: {
|
|
28
|
+
datasetConfig?: Record<string, { repo?: string }>;
|
|
29
|
+
paths?: RegExp[];
|
|
30
|
+
} = {}) {
|
|
31
|
+
const { datasetConfig = {}, paths = DEFAULT_PATHS } = options;
|
|
25
32
|
return (tree: MdastNode, file: { path?: string }) => {
|
|
26
|
-
const
|
|
33
|
+
const filePath = file.path ?? '';
|
|
34
|
+
const pack = paths
|
|
35
|
+
.map((pattern) => pattern.exec(filePath)?.[1])
|
|
36
|
+
.find(Boolean);
|
|
27
37
|
const repo = pack ? datasetConfig[pack]?.repo : undefined;
|
|
28
38
|
if (!repo) return;
|
|
29
39
|
const repoUrl = `https://github.com/${repo}`;
|
|
@@ -40,12 +50,14 @@ export function remarkChangelogReferences(options: { datasetConfig?: Record<stri
|
|
|
40
50
|
type: 'link',
|
|
41
51
|
url: `${repoUrl}/issues/${part.slice(1)}`,
|
|
42
52
|
children: [{ type: 'text', value: part }],
|
|
53
|
+
data: { hProperties: { className: 'gh-issue' } },
|
|
43
54
|
}
|
|
44
55
|
: USER_REF.test(part)
|
|
45
56
|
? {
|
|
46
57
|
type: 'link',
|
|
47
58
|
url: `https://github.com/${part.slice(1)}`,
|
|
48
59
|
children: [{ type: 'text', value: part }],
|
|
60
|
+
data: { hProperties: { className: 'gh-mention' } },
|
|
49
61
|
}
|
|
50
62
|
: { type: 'text', value: part },
|
|
51
63
|
);
|
|
@@ -54,4 +66,3 @@ export function remarkChangelogReferences(options: { datasetConfig?: Record<stri
|
|
|
54
66
|
visit(tree);
|
|
55
67
|
};
|
|
56
68
|
}
|
|
57
|
-
|
package/src/lib/mdx/tabs.ts
CHANGED
package/src/lib/story-remark.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type DirectiveMeta = {
|
|
|
12
12
|
multiline?: string[];
|
|
13
13
|
props?: string[];
|
|
14
14
|
solo?: boolean;
|
|
15
|
+
paired?: boolean;
|
|
15
16
|
descriptions?: Record<string, string>;
|
|
16
17
|
raw?: string;
|
|
17
18
|
variants?: Record<string, Partial<DirectiveMeta>>;
|
|
@@ -89,30 +90,25 @@ const DIRECTIVE_META: Record<string, DirectiveMeta> = {
|
|
|
89
90
|
strokeWidth: 'Lucide stroke width, default 2',
|
|
90
91
|
},
|
|
91
92
|
},
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
props: ['from', 'to', 'image', 'children', 'className'],
|
|
93
|
+
gradient: {
|
|
94
|
+
colon: 2,
|
|
95
|
+
paired: true,
|
|
96
|
+
multiline: ['children'],
|
|
97
|
+
props: ['from', 'to', 'dir', 'image', 'children', 'className'],
|
|
97
98
|
descriptions: {
|
|
98
99
|
from: 'Gradient start color',
|
|
99
100
|
to: 'Gradient end color',
|
|
101
|
+
dir: 'CSS gradient direction (to right, 135deg, …)',
|
|
100
102
|
image: 'CSS image overriding the gradient',
|
|
101
|
-
children: '
|
|
103
|
+
children: 'Body markdown inside the ::gradient … :: block',
|
|
102
104
|
},
|
|
103
105
|
},
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
colon: 1,
|
|
108
|
-
props: ['from', 'to', 'image', 'gradient', 'fade', 'children', 'className'],
|
|
106
|
+
video: {
|
|
107
|
+
colon: 2,
|
|
108
|
+
props: ['src', 'title', 'className'],
|
|
109
109
|
descriptions: {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
image: 'CSS image overriding the gradient',
|
|
113
|
-
gradient: 'Also tint the background box with the gradient',
|
|
114
|
-
fade: 'Gradient border along the bottom edge',
|
|
115
|
-
children: 'Header text, the directive label',
|
|
110
|
+
src: 'Embed URL (e.g. youtube-nocookie embed)',
|
|
111
|
+
title: 'Accessible frame title',
|
|
116
112
|
},
|
|
117
113
|
},
|
|
118
114
|
callout: {
|
|
@@ -126,11 +122,20 @@ const DIRECTIVE_META: Record<string, DirectiveMeta> = {
|
|
|
126
122
|
title: 'Overrides the default localized title',
|
|
127
123
|
children: 'Body markdown',
|
|
128
124
|
},
|
|
125
|
+
variants: {
|
|
126
|
+
Alert: {
|
|
127
|
+
raw: '> [!TIP]\nA GitHub alert blockquote.',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
129
130
|
},
|
|
130
131
|
banner: {
|
|
131
132
|
colon: 3,
|
|
132
133
|
multiline: ['children'],
|
|
133
|
-
props: ['id', 'height', 'variant', 'rainbowColors', 'changeLayout', 'children', 'className'],
|
|
134
|
+
props: ['id', 'height', 'variant', 'gradient', 'from', 'to', 'dir', 'image', 'rainbowColors', 'changeLayout', 'children', 'className'],
|
|
135
|
+
descriptions: {
|
|
136
|
+
variant: 'normal | rainbow | fade (gradient ring, fades down) | glow (radial bg + shadow)',
|
|
137
|
+
gradient: 'Gradient-fill the title text',
|
|
138
|
+
},
|
|
134
139
|
},
|
|
135
140
|
tabs: {
|
|
136
141
|
colon: 3,
|
|
@@ -147,7 +152,25 @@ const DIRECTIVE_META: Record<string, DirectiveMeta> = {
|
|
|
147
152
|
},
|
|
148
153
|
accordions: {
|
|
149
154
|
colon: 3,
|
|
150
|
-
props: ['multiple', 'defaultValue', 'children', 'className'],
|
|
155
|
+
props: ['format', 'multiple', 'defaultValue', 'children', 'className'],
|
|
156
|
+
descriptions: {
|
|
157
|
+
format:
|
|
158
|
+
'Input format — details: single :::details[Title] block; accordions: :::accordions group with ::accordion[Title] items; jsx: raw <Accordions>/<Accordion> markup',
|
|
159
|
+
},
|
|
160
|
+
variants: {
|
|
161
|
+
Details: {
|
|
162
|
+
raw: ':::details[Summary]\nHidden content.\n:::',
|
|
163
|
+
},
|
|
164
|
+
Open: {
|
|
165
|
+
raw: ':::details[Summary]{open}\nHidden content.\n:::',
|
|
166
|
+
},
|
|
167
|
+
'Multiple': {
|
|
168
|
+
raw: ':::accordions{multiple}\n::accordion[First]\nContent one.\n::accordion[Second]\nContent two.\n:::',
|
|
169
|
+
},
|
|
170
|
+
'Nested': {
|
|
171
|
+
raw: '::::details[Outer]{open}\nBefore.\n:::accordions\n::accordion[Inner one]\nNested answer one.\n::accordion[Inner two]\nNested answer two.\n:::\n::::',
|
|
172
|
+
},
|
|
173
|
+
},
|
|
151
174
|
},
|
|
152
175
|
image: {
|
|
153
176
|
label: 'alt',
|
|
@@ -171,7 +194,33 @@ const DIRECTIVE_META: Record<string, DirectiveMeta> = {
|
|
|
171
194
|
├── mods
|
|
172
195
|
└── config
|
|
173
196
|
`,
|
|
174
|
-
props: ['children'],
|
|
197
|
+
props: ['format', 'children'],
|
|
198
|
+
descriptions: {
|
|
199
|
+
format:
|
|
200
|
+
'Input format — list: :::files markdown list; fenced: ```files code block',
|
|
201
|
+
name: 'Entry name — file or folder label',
|
|
202
|
+
icon: 'Custom icon name or path',
|
|
203
|
+
href: 'Link target — renders the entry as an anchor',
|
|
204
|
+
description: 'Muted description line under the entry',
|
|
205
|
+
disabled: 'Folder only — renders the entry as non-interactive',
|
|
206
|
+
defaultOpen: 'Folder only — starts expanded',
|
|
207
|
+
children:
|
|
208
|
+
'Tree body — a ```files code fence or a :::files markdown list; items: [name](href "description"), trailing / or a nested list = folder',
|
|
209
|
+
},
|
|
210
|
+
variants: {
|
|
211
|
+
List: {
|
|
212
|
+
raw: ':::files\n- app/\n - layout.tsx\n - page.tsx\n- package.json\n:::',
|
|
213
|
+
},
|
|
214
|
+
Links: {
|
|
215
|
+
raw: ':::files\n- [modpack/](/docs/modern/modpack "Modpack guides")\n - [optional-mods.md](/docs/modern/modpack/optional-mods "Extra compatible mods")\n - kubejs/\n - server_scripts\n - startup_scripts\n- [pakku.json](https://pakku.readthedocs.io "Pakku config")\n:::',
|
|
216
|
+
},
|
|
217
|
+
Deep: {
|
|
218
|
+
raw: ':::files\n- content/\n - docs/\n - dev/\n - components/\n - index.md\n - item.md\n - meta.json\n - meta.json\n - index.mdx\n:::',
|
|
219
|
+
},
|
|
220
|
+
Fenced: {
|
|
221
|
+
raw: '```files\nTerraFirmaGreg\n├── mods\n└── config\n```',
|
|
222
|
+
},
|
|
223
|
+
},
|
|
175
224
|
},
|
|
176
225
|
code: {
|
|
177
226
|
fence: 'ts',
|
|
@@ -322,12 +371,30 @@ const DIRECTIVE_META: Record<string, DirectiveMeta> = {
|
|
|
322
371
|
},
|
|
323
372
|
},
|
|
324
373
|
math: {
|
|
325
|
-
|
|
326
|
-
props: ['children', 'block'],
|
|
374
|
+
props: ['format', 'children', 'block'],
|
|
327
375
|
multiline: ['children'],
|
|
328
376
|
descriptions: {
|
|
329
|
-
|
|
330
|
-
|
|
377
|
+
format:
|
|
378
|
+
'Input syntax — inline: :math[…] or $…$; block: ::math[…] leaf, :::math container, ```math fence or $$…$$',
|
|
379
|
+
children: 'KaTeX source',
|
|
380
|
+
block: 'Display block instead of inline',
|
|
381
|
+
},
|
|
382
|
+
variants: {
|
|
383
|
+
Inline: { raw: ':math[e = mc^2]' },
|
|
384
|
+
Dollar: { raw: '$e = mc^2$' },
|
|
385
|
+
Leaf: {
|
|
386
|
+
raw: '::math[\\int_0^\\infty e^{-x^2}\\,dx = \\frac{\\sqrt{\\pi}}{2}]',
|
|
387
|
+
},
|
|
388
|
+
Block: {
|
|
389
|
+
raw: ':::math\n\\int_0^\\infty e^{-x^2}\\,dx = \\frac{\\sqrt{\\pi}}{2}\n:::',
|
|
390
|
+
},
|
|
391
|
+
Fenced: {
|
|
392
|
+
raw: '```math\n\\int_0^\\infty e^{-x^2}\\,dx = \\frac{\\sqrt{\\pi}}{2}\n```',
|
|
393
|
+
},
|
|
394
|
+
Aligned: {
|
|
395
|
+
raw: ':::math\n\\begin{aligned}\n\\nabla \\cdot \\vec{E} &= \\frac{\\rho}{\\varepsilon_0} \\\\\n\\nabla \\times \\vec{B} &= \\mu_0 \\vec{J}\n\\end{aligned}\n:::',
|
|
396
|
+
},
|
|
397
|
+
Display: { raw: '$$e = mc^2$$' },
|
|
331
398
|
},
|
|
332
399
|
},
|
|
333
400
|
};
|
|
@@ -401,11 +468,10 @@ export function remarkFor(
|
|
|
401
468
|
if (key === 'accordions') {
|
|
402
469
|
return md`
|
|
403
470
|
:::accordions${args.multiple ? '{multiple}' : ''}
|
|
404
|
-
::accordion[
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
…
|
|
471
|
+
::accordion[First]
|
|
472
|
+
Content one.
|
|
473
|
+
::accordion[Second]
|
|
474
|
+
Content two.
|
|
409
475
|
:::
|
|
410
476
|
`;
|
|
411
477
|
}
|
|
@@ -460,9 +526,9 @@ export function remarkFor(
|
|
|
460
526
|
? `[${String(args[meta.label])}]`
|
|
461
527
|
: '';
|
|
462
528
|
const head = `${':'.repeat(meta.colon ?? 2)}${name}${label}${attrs ? `{${attrs}}` : ''}`;
|
|
463
|
-
if (meta.colon !== 3
|
|
529
|
+
if (meta.solo || (meta.colon !== 3 && !meta.paired)) return head;
|
|
464
530
|
const inner =
|
|
465
531
|
typeof args.children === 'string' && args.children ? args.children : '…';
|
|
466
|
-
return `${head}\n${inner}\n
|
|
532
|
+
return `${head}\n${inner}\n${':'.repeat(meta.colon ?? 3)}`;
|
|
467
533
|
}
|
|
468
534
|
|
package/src/lib/story.ts
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { defineStoryFactory } from '@fumadocs/story/next/client';
|
|
4
|
+
import type {
|
|
5
|
+
Story,
|
|
6
|
+
StoryOptions,
|
|
7
|
+
} from '@fumadocs/story/next/client';
|
|
4
8
|
import { DocsWithControl } from '../components/story-panel';
|
|
9
|
+
import type { ComponentType } from 'react';
|
|
5
10
|
|
|
6
11
|
export { md } from './md';
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
const factory = defineStoryFactory({
|
|
9
14
|
WithControl: DocsWithControl,
|
|
10
15
|
});
|
|
11
16
|
|
|
17
|
+
const registry = ((globalThis as Record<symbol, unknown>)[
|
|
18
|
+
Symbol.for('terrafirmagreg.mdx.stories')
|
|
19
|
+
] ??= {}) as Record<string, Story>;
|
|
20
|
+
|
|
21
|
+
export function defineStory<C extends ComponentType<any>>(
|
|
22
|
+
options: StoryOptions<C>,
|
|
23
|
+
): Story<C> {
|
|
24
|
+
const story = factory.defineStory(options);
|
|
25
|
+
if (options.displayName)
|
|
26
|
+
registry[options.displayName] = story as Story;
|
|
27
|
+
return story;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function storyFor(name: string): Story | undefined {
|
|
31
|
+
return registry[name];
|
|
32
|
+
}
|