@terrafirmagreg-team/kit 0.0.0-stage → 0.1.0
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 +68 -3
- package/src/components/blocks/nav-title.tsx +65 -0
- package/src/components/docs-image.tsx +49 -0
- package/src/components/outline/dropdown.tsx +67 -0
- package/src/components/outline/index.ts +10 -0
- package/src/components/outline/list.tsx +120 -0
- package/src/components/outline/outline.tsx +49 -0
- package/src/components/outline/popover.tsx +76 -0
- package/src/components/outline/types.ts +29 -0
- package/src/components/page-actions.tsx +201 -0
- package/src/components/relative-link.tsx +18 -0
- package/src/components/search/dialog.tsx +145 -0
- package/src/components/toc/base.tsx +65 -0
- package/src/components/toc/block.tsx +111 -0
- package/src/components/toc/clerk.tsx +265 -0
- package/src/components/toc/default.tsx +333 -0
- package/src/components/version-menu.tsx +128 -0
- package/src/components/views/dataset.tsx +63 -0
- package/src/components/views/section.tsx +108 -0
- package/src/components/workspace/content.tsx +53 -0
- package/src/components/workspace/index.ts +12 -0
- package/src/components/workspace/pagination.tsx +73 -0
- package/src/components/workspace/workspace.tsx +148 -0
- package/src/hooks/toc.ts +9 -0
- package/src/hooks/use-catalog.ts +11 -0
- package/src/hooks/use-current-dataset.ts +14 -0
- package/src/hooks/use-dataset-accent.ts +13 -0
- package/src/hooks/use-nav-options.ts +84 -0
- package/src/hooks/use-version-pref.ts +30 -0
- package/src/lib/breadcrumb.ts +78 -0
- package/src/lib/config.ts +109 -0
- package/src/lib/dataset-links.ts +30 -0
- package/src/lib/datasets.ts +211 -0
- package/src/lib/landing.ts +46 -0
- package/src/lib/layout.ts +15 -0
- package/src/lib/legacy.ts +18 -0
- package/src/lib/location.ts +63 -0
- package/src/lib/markdown/dom.ts +90 -0
- package/src/lib/markdown/index.ts +13 -0
- package/src/lib/markdown/providers.ts +25 -0
- package/src/lib/mdx/accordions.ts +93 -0
- package/src/lib/mdx/banner.ts +52 -0
- package/src/lib/mdx/directive-utils.ts +125 -0
- package/src/lib/mdx/directives.ts +141 -0
- package/src/lib/mdx/game-export.ts +44 -0
- package/src/lib/mdx/html-style.ts +135 -0
- package/src/lib/mdx/preview.ts +252 -0
- package/src/lib/mdx/references.ts +56 -0
- package/src/lib/mdx/tabs.ts +80 -0
- package/src/lib/mdx-components.tsx +139 -0
- package/src/lib/order.ts +88 -0
- package/src/lib/pack-assets.ts +45 -0
- package/src/lib/page.ts +108 -0
- package/src/lib/pin-tree.ts +35 -0
- package/src/lib/preview/index.ts +8 -0
- package/src/lib/preview/lookup.ts +48 -0
- package/src/lib/preview/og.tsx +115 -0
- package/src/lib/preview/resolvers.ts +98 -0
- package/src/lib/search/config.ts +13 -0
- package/src/lib/search/filters.ts +22 -0
- package/src/lib/search/index.ts +19 -0
- package/src/lib/search/indexes.ts +43 -0
- package/src/lib/search/merge.ts +22 -0
- package/src/lib/search/server.ts +18 -0
- package/src/lib/search/sources.ts +19 -0
- package/src/lib/search/structured.ts +23 -0
- package/src/lib/section/schema.ts +36 -0
- package/src/lib/section/source.ts +40 -0
- package/src/lib/sources.ts +21 -0
- package/src/lib/tree.ts +60 -0
- package/src/lib/urls.ts +16 -0
- package/src/locales/en_us.json +10 -0
- package/src/locales/ru_ru.json +10 -0
- package/src/locales.ts +5 -0
- package/src/types/index.ts +83 -0
- package/src/types/mdx.ts +55 -0
- package/src/types/turndown-plugin-gfm.d.ts +9 -0
- package/README.md +0 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SearchClient } from 'fumadocs-core/search/client';
|
|
2
|
+
|
|
3
|
+
export type SearchClientSourceCtx = {
|
|
4
|
+
refs: string[];
|
|
5
|
+
locale: string;
|
|
6
|
+
tag?: string | string[];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type SearchClientSource = (ctx: SearchClientSourceCtx) => SearchClient;
|
|
10
|
+
|
|
11
|
+
const sources: SearchClientSource[] = [];
|
|
12
|
+
|
|
13
|
+
export function registerSearchClientSource(source: SearchClientSource): void {
|
|
14
|
+
sources.push(source);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getSearchClientSources(): readonly SearchClientSource[] {
|
|
18
|
+
return sources;
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StructuredData } from 'fumadocs-core/mdx-plugins';
|
|
2
|
+
|
|
3
|
+
type StructuredPageData = Record<string, unknown>;
|
|
4
|
+
|
|
5
|
+
export async function pageStructuredData(
|
|
6
|
+
data: StructuredPageData,
|
|
7
|
+
): Promise<StructuredData> {
|
|
8
|
+
const raw = data.structuredData;
|
|
9
|
+
if (typeof raw === 'function') {
|
|
10
|
+
return (raw as () => Promise<StructuredData> | StructuredData)();
|
|
11
|
+
}
|
|
12
|
+
if (typeof data.load === 'function') {
|
|
13
|
+
const loaded = await (
|
|
14
|
+
data.load as () => Promise<{ structuredData?: StructuredData }>
|
|
15
|
+
)();
|
|
16
|
+
if (!loaded.structuredData) {
|
|
17
|
+
throw new Error('Cannot find structured data from page');
|
|
18
|
+
}
|
|
19
|
+
return loaded.structuredData;
|
|
20
|
+
}
|
|
21
|
+
if (!raw) throw new Error('Cannot find structured data from page');
|
|
22
|
+
return raw as StructuredData;
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { metaSchema, pageSchema } from 'fumadocs-core/source/schema';
|
|
2
|
+
import { z, type ZodRawShape } from 'zod';
|
|
3
|
+
|
|
4
|
+
export function sectionDocsConfig(
|
|
5
|
+
dir: string,
|
|
6
|
+
schemaFields: ZodRawShape = {},
|
|
7
|
+
): {
|
|
8
|
+
dir: string;
|
|
9
|
+
docs: {
|
|
10
|
+
schema: ReturnType<typeof pageSchema.extend>;
|
|
11
|
+
postprocess: { includeProcessedMarkdown: true };
|
|
12
|
+
};
|
|
13
|
+
meta: { schema: typeof metaSchema };
|
|
14
|
+
} {
|
|
15
|
+
return {
|
|
16
|
+
dir,
|
|
17
|
+
docs: {
|
|
18
|
+
schema: pageSchema.extend({
|
|
19
|
+
order: z.number().optional(),
|
|
20
|
+
unlisted: z.boolean().optional(),
|
|
21
|
+
comments: z.boolean().optional(),
|
|
22
|
+
redirect: z.string().optional(),
|
|
23
|
+
defaultOpen: z.boolean().optional(),
|
|
24
|
+
collapsible: z.boolean().optional(),
|
|
25
|
+
link: z.boolean().optional(),
|
|
26
|
+
...schemaFields,
|
|
27
|
+
}),
|
|
28
|
+
postprocess: {
|
|
29
|
+
includeProcessedMarkdown: true,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
meta: {
|
|
33
|
+
schema: metaSchema,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { llms, loader, type StaticSource } from 'fumadocs-core/source';
|
|
2
|
+
import { sectionDatasets } from '@terrafirmagreg-team/kit/lib/datasets';
|
|
3
|
+
import { orderPlugin } from '@terrafirmagreg-team/kit/lib/order';
|
|
4
|
+
import { renderSectionMarkdown } from '@terrafirmagreg-team/kit/lib/markdown';
|
|
5
|
+
import { localizedDatasetTrees } from '@terrafirmagreg-team/kit/lib/tree';
|
|
6
|
+
import type { SectionTrees } from '@terrafirmagreg-team/kit/types';
|
|
7
|
+
|
|
8
|
+
type SectionSource = StaticSource;
|
|
9
|
+
|
|
10
|
+
export function createSectionSource<S extends SectionSource>(options: {
|
|
11
|
+
route: string;
|
|
12
|
+
|
|
13
|
+
section: string;
|
|
14
|
+
source: S;
|
|
15
|
+
|
|
16
|
+
postTrees?: (trees: SectionTrees) => SectionTrees;
|
|
17
|
+
}) {
|
|
18
|
+
const { route, section, source: fumadocsSource, postTrees } = options;
|
|
19
|
+
const source = loader({
|
|
20
|
+
baseUrl: route,
|
|
21
|
+
source: fumadocsSource,
|
|
22
|
+
plugins: [orderPlugin()],
|
|
23
|
+
});
|
|
24
|
+
const markdown = llms(source as never, {
|
|
25
|
+
renderPage: renderSectionMarkdown as (
|
|
26
|
+
page: unknown,
|
|
27
|
+
) => Promise<string>,
|
|
28
|
+
}) as { page(page: unknown): Promise<string> };
|
|
29
|
+
|
|
30
|
+
let cached: Promise<SectionTrees> | undefined;
|
|
31
|
+
const trees = (): Promise<SectionTrees> => {
|
|
32
|
+
cached ??= sectionDatasets(section).then((datasets) => {
|
|
33
|
+
const built = localizedDatasetTrees(source, datasets);
|
|
34
|
+
return postTrees ? postTrees(built) : built;
|
|
35
|
+
});
|
|
36
|
+
return cached;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return { route, source, markdown, trees };
|
|
40
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { sectionConfig } from './config';
|
|
2
|
+
import type { SectionKey, SectionSourceEntry } from '@terrafirmagreg-team/kit/types';
|
|
3
|
+
|
|
4
|
+
export const sections: Partial<Record<SectionKey, SectionSourceEntry>> =
|
|
5
|
+
new Proxy(
|
|
6
|
+
{},
|
|
7
|
+
{
|
|
8
|
+
get: (_, key: string) => sectionConfig().sources[key as SectionKey],
|
|
9
|
+
has: (_, key: string) =>
|
|
10
|
+
Object.hasOwn(sectionConfig().sources ?? {}, key as string),
|
|
11
|
+
ownKeys: () => Reflect.ownKeys(sectionConfig().sources ?? {}),
|
|
12
|
+
getOwnPropertyDescriptor: (_, key: string) =>
|
|
13
|
+
Object.hasOwn(sectionConfig().sources, key)
|
|
14
|
+
? {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
value: sectionConfig().sources[key as SectionKey],
|
|
18
|
+
}
|
|
19
|
+
: undefined,
|
|
20
|
+
},
|
|
21
|
+
);
|
package/src/lib/tree.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type * as PageTree from 'fumadocs-core/page-tree';
|
|
2
|
+
import { localizePageTree } from '@terrafirmagreg-team/translate/server';
|
|
3
|
+
import { loadLocaleRegistry } from '@terrafirmagreg-team/translate/server';
|
|
4
|
+
import { sectionConfig } from './config';
|
|
5
|
+
import type { Lang } from '@terrafirmagreg-team/translate/types/locale';
|
|
6
|
+
import type { SectionDataset, SectionTrees } from '@terrafirmagreg-team/kit/types';
|
|
7
|
+
import type { SectionSource } from './page';
|
|
8
|
+
|
|
9
|
+
export function datasetId(node: PageTree.Folder): string | undefined {
|
|
10
|
+
const segment = node.index?.url.split('/').filter(Boolean)[1];
|
|
11
|
+
if (segment) return segment;
|
|
12
|
+
const segments = node.$id?.split('/').filter(Boolean);
|
|
13
|
+
return segments?.[segments.length - 1];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function datasetTree(
|
|
17
|
+
tree: PageTree.Root,
|
|
18
|
+
id: string,
|
|
19
|
+
lang: Lang,
|
|
20
|
+
): PageTree.Root {
|
|
21
|
+
const folder = tree.children.find(
|
|
22
|
+
(node): node is PageTree.Folder =>
|
|
23
|
+
node.type === 'folder' && datasetId(node) === id,
|
|
24
|
+
);
|
|
25
|
+
if (!folder) return { name: id, children: [], $id: `${id}:${lang}` };
|
|
26
|
+
return { name: folder.name, children: folder.children, $id: `${id}:${lang}` };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function localizedDatasetTrees(
|
|
30
|
+
source: SectionSource,
|
|
31
|
+
datasets: readonly SectionDataset[],
|
|
32
|
+
): SectionTrees {
|
|
33
|
+
const { defaultLanguage } = loadLocaleRegistry();
|
|
34
|
+
const tree = source.getPageTree();
|
|
35
|
+
const options = {
|
|
36
|
+
languages: [...sectionConfig().knownLanguages],
|
|
37
|
+
fallbackLanguage: defaultLanguage,
|
|
38
|
+
};
|
|
39
|
+
const localized = new Map<string, PageTree.Root>();
|
|
40
|
+
const localize = (lang: Lang) => {
|
|
41
|
+
let out = localized.get(lang);
|
|
42
|
+
if (!out) {
|
|
43
|
+
out = localizePageTree(tree, lang, options);
|
|
44
|
+
localized.set(lang, out);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
};
|
|
48
|
+
const trees: SectionTrees = {};
|
|
49
|
+
for (const dataset of datasets) {
|
|
50
|
+
for (const lang of dataset.languages ?? [defaultLanguage]) {
|
|
51
|
+
const code = lang as Lang;
|
|
52
|
+
(trees[code] ??= {})[dataset.id] = datasetTree(
|
|
53
|
+
localize(code),
|
|
54
|
+
dataset.id,
|
|
55
|
+
code,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return trees;
|
|
60
|
+
}
|
package/src/lib/urls.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createGetUrl } from 'fumadocs-core/source';
|
|
2
|
+
import { sectionConfig } from './config';
|
|
3
|
+
|
|
4
|
+
export function canonicalUrl(pathname: string): string {
|
|
5
|
+
const path = pathname.startsWith('/') ? pathname : `/${pathname}`;
|
|
6
|
+
return new URL(path, sectionConfig().siteUrl).toString();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getDatasetImageUrl(section: string, dataset: string) {
|
|
10
|
+
const segments = [section, dataset, 'image.png'];
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
segments,
|
|
14
|
+
url: createGetUrl(sectionConfig().previewRoute)(segments),
|
|
15
|
+
};
|
|
16
|
+
}
|
package/src/locales.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { MDXProps } from 'mdx/types';
|
|
2
|
+
import type { TOCItemType } from 'fumadocs-core/toc';
|
|
3
|
+
import type * as PageTree from 'fumadocs-core/page-tree';
|
|
4
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
5
|
+
import type { IconName } from 'lucide-react/dynamic';
|
|
6
|
+
import type { Page } from 'fumadocs-core/source';
|
|
7
|
+
import type { Lang } from '@terrafirmagreg-team/translate/types/locale';
|
|
8
|
+
|
|
9
|
+
export type SectionKey = string;
|
|
10
|
+
|
|
11
|
+
export type SectionUrl = string;
|
|
12
|
+
|
|
13
|
+
export type SectionDataset = {
|
|
14
|
+
id: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
icon?: IconName;
|
|
18
|
+
accent?: string;
|
|
19
|
+
|
|
20
|
+
versions?: string[];
|
|
21
|
+
|
|
22
|
+
languages?: Lang[];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type DatasetCatalog = Record<SectionKey, SectionDataset[]>;
|
|
26
|
+
|
|
27
|
+
export type LeftSidebarScope = {
|
|
28
|
+
section: SectionKey;
|
|
29
|
+
catalog: DatasetCatalog;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type LeftSidebarSlotProps = LeftSidebarScope & {
|
|
33
|
+
|
|
34
|
+
feature?: ComponentType;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type SectionTrees = Record<Lang, Record<string, PageTree.Root>>;
|
|
38
|
+
|
|
39
|
+
export type SectionPage = {
|
|
40
|
+
data: {
|
|
41
|
+
body: (props: MDXProps) => ReactNode | Promise<ReactNode>;
|
|
42
|
+
toc: TOCItemType[];
|
|
43
|
+
full?: boolean;
|
|
44
|
+
title: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
comments?: boolean;
|
|
47
|
+
redirect?: string;
|
|
48
|
+
authors?: string[];
|
|
49
|
+
gitChangelog?:
|
|
50
|
+
| boolean
|
|
51
|
+
| {
|
|
52
|
+
disableChangelog?: boolean;
|
|
53
|
+
disableContributors?: boolean;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
path: string;
|
|
57
|
+
slugs: string[];
|
|
58
|
+
url: string;
|
|
59
|
+
locale?: string;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type SectionSource = {
|
|
63
|
+
getPage(slugs: string[] | undefined, language?: string): unknown;
|
|
64
|
+
getPages(language?: string): Page[];
|
|
65
|
+
getPageTree(locale?: string): PageTree.Root;
|
|
66
|
+
getNodeMeta?(
|
|
67
|
+
node: PageTree.Folder | PageTree.Root,
|
|
68
|
+
language?: string,
|
|
69
|
+
): unknown;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type DatasetLanding = {
|
|
73
|
+
title: string;
|
|
74
|
+
description?: string;
|
|
75
|
+
dataset: string;
|
|
76
|
+
datasetTitle?: string;
|
|
77
|
+
lang: Lang;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type SectionSourceEntry = {
|
|
81
|
+
source: SectionSource;
|
|
82
|
+
markdown: { page(page: unknown): Promise<string> };
|
|
83
|
+
};
|
package/src/types/mdx.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export interface MdastNode {
|
|
5
|
+
type: string;
|
|
6
|
+
data?: Record<string, unknown>;
|
|
7
|
+
children?: MdastNode[];
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DirectiveNode extends MdastNode {
|
|
12
|
+
type: 'containerDirective' | 'leafDirective' | 'textDirective';
|
|
13
|
+
name: string;
|
|
14
|
+
attributes?: Record<string, string | boolean | undefined>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type JsxAttributeValue =
|
|
18
|
+
| string
|
|
19
|
+
| boolean
|
|
20
|
+
| {
|
|
21
|
+
type: 'mdxJsxAttributeValueExpression';
|
|
22
|
+
value: string;
|
|
23
|
+
data?: { estree?: Record<string, unknown> };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export interface JsxAttribute {
|
|
27
|
+
type: 'mdxJsxAttribute';
|
|
28
|
+
name: string;
|
|
29
|
+
value: JsxAttributeValue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface JsxElement {
|
|
33
|
+
type: 'mdxJsxFlowElement';
|
|
34
|
+
name: string;
|
|
35
|
+
attributes: JsxAttribute[];
|
|
36
|
+
children: MdastNode[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type DocsImageProps = {
|
|
40
|
+
|
|
41
|
+
src?: string;
|
|
42
|
+
|
|
43
|
+
pack?: string;
|
|
44
|
+
|
|
45
|
+
mod?: string;
|
|
46
|
+
|
|
47
|
+
path?: string;
|
|
48
|
+
alt?: string;
|
|
49
|
+
width?: number;
|
|
50
|
+
height?: number;
|
|
51
|
+
className?: string;
|
|
52
|
+
caption?: string;
|
|
53
|
+
|
|
54
|
+
defaultPack?: string;
|
|
55
|
+
} & Omit<ComponentProps<'img'>, 'src' | 'alt' | 'width' | 'height' | 'className'>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare module 'turndown-plugin-gfm' {
|
|
2
|
+
import type { Plugin } from 'turndown';
|
|
3
|
+
|
|
4
|
+
export const gfm: Plugin;
|
|
5
|
+
export const highlightedCodeBlock: Plugin;
|
|
6
|
+
export const strikethrough: Plugin;
|
|
7
|
+
export const tables: Plugin;
|
|
8
|
+
export const taskListItems: Plugin;
|
|
9
|
+
}
|
package/README.md
DELETED