@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.
Files changed (78) hide show
  1. package/package.json +68 -3
  2. package/src/components/blocks/nav-title.tsx +65 -0
  3. package/src/components/docs-image.tsx +49 -0
  4. package/src/components/outline/dropdown.tsx +67 -0
  5. package/src/components/outline/index.ts +10 -0
  6. package/src/components/outline/list.tsx +120 -0
  7. package/src/components/outline/outline.tsx +49 -0
  8. package/src/components/outline/popover.tsx +76 -0
  9. package/src/components/outline/types.ts +29 -0
  10. package/src/components/page-actions.tsx +201 -0
  11. package/src/components/relative-link.tsx +18 -0
  12. package/src/components/search/dialog.tsx +145 -0
  13. package/src/components/toc/base.tsx +65 -0
  14. package/src/components/toc/block.tsx +111 -0
  15. package/src/components/toc/clerk.tsx +265 -0
  16. package/src/components/toc/default.tsx +333 -0
  17. package/src/components/version-menu.tsx +128 -0
  18. package/src/components/views/dataset.tsx +63 -0
  19. package/src/components/views/section.tsx +108 -0
  20. package/src/components/workspace/content.tsx +53 -0
  21. package/src/components/workspace/index.ts +12 -0
  22. package/src/components/workspace/pagination.tsx +73 -0
  23. package/src/components/workspace/workspace.tsx +148 -0
  24. package/src/hooks/toc.ts +9 -0
  25. package/src/hooks/use-catalog.ts +11 -0
  26. package/src/hooks/use-current-dataset.ts +14 -0
  27. package/src/hooks/use-dataset-accent.ts +13 -0
  28. package/src/hooks/use-nav-options.ts +84 -0
  29. package/src/hooks/use-version-pref.ts +30 -0
  30. package/src/lib/breadcrumb.ts +78 -0
  31. package/src/lib/config.ts +109 -0
  32. package/src/lib/dataset-links.ts +30 -0
  33. package/src/lib/datasets.ts +211 -0
  34. package/src/lib/landing.ts +46 -0
  35. package/src/lib/layout.ts +15 -0
  36. package/src/lib/legacy.ts +18 -0
  37. package/src/lib/location.ts +63 -0
  38. package/src/lib/markdown/dom.ts +90 -0
  39. package/src/lib/markdown/index.ts +13 -0
  40. package/src/lib/markdown/providers.ts +25 -0
  41. package/src/lib/mdx/accordions.ts +93 -0
  42. package/src/lib/mdx/banner.ts +52 -0
  43. package/src/lib/mdx/directive-utils.ts +125 -0
  44. package/src/lib/mdx/directives.ts +141 -0
  45. package/src/lib/mdx/game-export.ts +44 -0
  46. package/src/lib/mdx/html-style.ts +135 -0
  47. package/src/lib/mdx/preview.ts +252 -0
  48. package/src/lib/mdx/references.ts +56 -0
  49. package/src/lib/mdx/tabs.ts +80 -0
  50. package/src/lib/mdx-components.tsx +139 -0
  51. package/src/lib/order.ts +88 -0
  52. package/src/lib/pack-assets.ts +45 -0
  53. package/src/lib/page.ts +108 -0
  54. package/src/lib/pin-tree.ts +35 -0
  55. package/src/lib/preview/index.ts +8 -0
  56. package/src/lib/preview/lookup.ts +48 -0
  57. package/src/lib/preview/og.tsx +115 -0
  58. package/src/lib/preview/resolvers.ts +98 -0
  59. package/src/lib/search/config.ts +13 -0
  60. package/src/lib/search/filters.ts +22 -0
  61. package/src/lib/search/index.ts +19 -0
  62. package/src/lib/search/indexes.ts +43 -0
  63. package/src/lib/search/merge.ts +22 -0
  64. package/src/lib/search/server.ts +18 -0
  65. package/src/lib/search/sources.ts +19 -0
  66. package/src/lib/search/structured.ts +23 -0
  67. package/src/lib/section/schema.ts +36 -0
  68. package/src/lib/section/source.ts +40 -0
  69. package/src/lib/sources.ts +21 -0
  70. package/src/lib/tree.ts +60 -0
  71. package/src/lib/urls.ts +16 -0
  72. package/src/locales/en_us.json +10 -0
  73. package/src/locales/ru_ru.json +10 -0
  74. package/src/locales.ts +5 -0
  75. package/src/types/index.ts +83 -0
  76. package/src/types/mdx.ts +55 -0
  77. package/src/types/turndown-plugin-gfm.d.ts +9 -0
  78. 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
+ );
@@ -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
+ }
@@ -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
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "ui": {
3
+ "select_section": "Select section",
4
+ "select_dataset": "Select dataset",
5
+ "view_markdown": "View as Markdown",
6
+ "copy_error": "Failed to copy",
7
+ "search_everywhere": "Everywhere",
8
+ "version_latest": "latest"
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "ui": {
3
+ "select_section": "Выберите раздел",
4
+ "select_dataset": "Выберите набор данных",
5
+ "view_markdown": "Просмотр Markdown",
6
+ "copy_error": "Не удалось скопировать",
7
+ "search_everywhere": "Везде",
8
+ "version_latest": "последняя"
9
+ }
10
+ }
package/src/locales.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { createLocaleCatalog } from '@terrafirmagreg-team/translate/lib/locales';
2
+
3
+ export const locales = createLocaleCatalog(
4
+ import.meta.glob('./locales/*.json', { eager: true, import: 'default' }),
5
+ );
@@ -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
+ };
@@ -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
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.