@terrafirmagreg-team/kit 0.1.0 → 1.2.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 +15 -27
- package/src/components/blocks/nav-title.tsx +22 -25
- package/src/components/outline/dropdown.tsx +3 -2
- package/src/components/outline/index.ts +2 -1
- package/src/components/outline/list.tsx +3 -2
- package/src/components/outline/outline.tsx +4 -3
- package/src/components/outline/popover.tsx +3 -2
- package/src/components/page-actions.tsx +10 -9
- package/src/components/relative-link.tsx +1 -0
- package/src/components/toc/base.tsx +2 -1
- package/src/components/toc/block.tsx +1 -0
- package/src/components/toc/clerk.tsx +2 -1
- package/src/components/toc/default.tsx +3 -2
- package/src/components/version-menu.tsx +19 -17
- package/src/components/views/dataset.tsx +11 -2
- package/src/components/views/section.tsx +88 -44
- package/src/components/workspace/content.tsx +1 -0
- package/src/components/workspace/index.ts +1 -0
- package/src/components/workspace/pagination.tsx +2 -1
- package/src/components/workspace/workspace.tsx +1 -0
- package/src/hooks/use-catalog.ts +1 -0
- package/src/hooks/use-current-dataset.ts +15 -5
- package/src/hooks/use-dataset-accent.ts +1 -0
- package/src/hooks/use-nav-options.ts +20 -17
- package/src/hooks/use-section-names.ts +40 -0
- package/src/hooks/{toc.ts → use-toc.ts} +1 -0
- package/src/hooks/use-version-pref.ts +1 -0
- package/src/hooks/use-versioned-dataset.ts +21 -0
- package/src/lib/breadcrumb.ts +3 -16
- package/src/lib/config.ts +30 -28
- package/src/lib/dataset-links.ts +1 -0
- package/src/lib/datasets.ts +98 -68
- package/src/lib/landing.ts +4 -2
- package/src/lib/layout.ts +1 -0
- package/src/lib/locale/renderer.ts +49 -0
- package/src/lib/order.ts +1 -0
- package/src/lib/page.ts +3 -2
- package/src/lib/pin-tree.ts +11 -8
- package/src/lib/preview/lookup.ts +8 -5
- package/src/lib/section/schema.ts +2 -6
- package/src/lib/section/source.ts +59 -22
- package/src/lib/sources.ts +1 -0
- package/src/lib/tree.ts +1 -0
- package/src/lib/urls.ts +1 -0
- package/src/locales/en_us.json +7 -10
- package/src/locales/ru_ru.json +7 -10
- package/src/locales.ts +1 -0
- package/src/types/embeds.ts +54 -0
- package/src/types/index.ts +13 -9
- package/src/{components/outline/types.ts → types/outline.ts} +1 -0
- package/src/components/docs-image.tsx +0 -49
- package/src/components/search/dialog.tsx +0 -145
- package/src/lib/legacy.ts +0 -18
- package/src/lib/location.ts +0 -63
- package/src/lib/markdown/dom.ts +0 -90
- package/src/lib/markdown/index.ts +0 -13
- package/src/lib/markdown/providers.ts +0 -25
- package/src/lib/mdx/accordions.ts +0 -93
- package/src/lib/mdx/banner.ts +0 -52
- package/src/lib/mdx/directive-utils.ts +0 -125
- package/src/lib/mdx/directives.ts +0 -141
- package/src/lib/mdx/game-export.ts +0 -44
- package/src/lib/mdx/html-style.ts +0 -135
- package/src/lib/mdx/preview.ts +0 -252
- package/src/lib/mdx/references.ts +0 -56
- package/src/lib/mdx/tabs.ts +0 -80
- package/src/lib/mdx-components.tsx +0 -139
- package/src/lib/pack-assets.ts +0 -45
- package/src/lib/preview/index.ts +0 -8
- package/src/lib/preview/og.tsx +0 -115
- package/src/lib/preview/resolvers.ts +0 -98
- package/src/lib/search/config.ts +0 -13
- package/src/lib/search/filters.ts +0 -22
- package/src/lib/search/index.ts +0 -19
- package/src/lib/search/indexes.ts +0 -43
- package/src/lib/search/merge.ts +0 -22
- package/src/lib/search/server.ts +0 -18
- package/src/lib/search/sources.ts +0 -19
- package/src/lib/search/structured.ts +0 -23
- package/src/types/mdx.ts +0 -55
- package/src/types/turndown-plugin-gfm.d.ts +0 -9
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
type MdastNode = {
|
|
2
|
-
type: string;
|
|
3
|
-
value?: string;
|
|
4
|
-
url?: string;
|
|
5
|
-
children?: MdastNode[];
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
const ISSUE_REF = /^#\d+$/;
|
|
9
|
-
const USER_REF = /^@[a-zA-Z\d](?:[a-zA-Z\d-]{0,37}[a-zA-Z\d])?$/;
|
|
10
|
-
const AUTO_REF = /(\B#\d+\b|\B@[a-zA-Z\d](?:[a-zA-Z\d-]{0,37}[a-zA-Z\d])?)/g;
|
|
11
|
-
const SKIP = new Set([
|
|
12
|
-
'link',
|
|
13
|
-
'linkReference',
|
|
14
|
-
'image',
|
|
15
|
-
'imageReference',
|
|
16
|
-
'code',
|
|
17
|
-
'inlineCode',
|
|
18
|
-
'html',
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
const CHANGELOG_PATH = /[/\\]changelog[/\\]([^/\\]+)[/\\]/;
|
|
22
|
-
|
|
23
|
-
export function remarkChangelogReferences(options: { datasetConfig?: Record<string, { repo?: string }> } = {}) {
|
|
24
|
-
const datasetConfig = options.datasetConfig ?? {};
|
|
25
|
-
return (tree: MdastNode, file: { path?: string }) => {
|
|
26
|
-
const pack = CHANGELOG_PATH.exec(file.path ?? '')?.[1];
|
|
27
|
-
const repo = pack ? datasetConfig[pack]?.repo : undefined;
|
|
28
|
-
if (!repo) return;
|
|
29
|
-
const repoUrl = `https://github.com/${repo}`;
|
|
30
|
-
const visit = (node: MdastNode) => {
|
|
31
|
-
if (SKIP.has(node.type) || !node.children) return;
|
|
32
|
-
node.children = node.children.flatMap((child): MdastNode[] => {
|
|
33
|
-
if (child.type !== 'text') {
|
|
34
|
-
visit(child);
|
|
35
|
-
return [child];
|
|
36
|
-
}
|
|
37
|
-
return (child.value ?? '').split(AUTO_REF).map((part) =>
|
|
38
|
-
ISSUE_REF.test(part)
|
|
39
|
-
? {
|
|
40
|
-
type: 'link',
|
|
41
|
-
url: `${repoUrl}/issues/${part.slice(1)}`,
|
|
42
|
-
children: [{ type: 'text', value: part }],
|
|
43
|
-
}
|
|
44
|
-
: USER_REF.test(part)
|
|
45
|
-
? {
|
|
46
|
-
type: 'link',
|
|
47
|
-
url: `https://github.com/${part.slice(1)}`,
|
|
48
|
-
children: [{ type: 'text', value: part }],
|
|
49
|
-
}
|
|
50
|
-
: { type: 'text', value: part },
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
visit(tree);
|
|
55
|
-
};
|
|
56
|
-
}
|
package/src/lib/mdx/tabs.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
estreeStringArray,
|
|
3
|
-
extractLeafLabel,
|
|
4
|
-
jsxExpression,
|
|
5
|
-
toJsxAttributes,
|
|
6
|
-
walkContainers,
|
|
7
|
-
type DirectiveNode,
|
|
8
|
-
type JsxElement,
|
|
9
|
-
type MdastNode,
|
|
10
|
-
} from './directive-utils.ts';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export function remarkTabs() {
|
|
14
|
-
return (tree: MdastNode) => {
|
|
15
|
-
walkContainers(tree, (directive) => {
|
|
16
|
-
if (directive.name !== 'tabs') return;
|
|
17
|
-
toTabs(directive);
|
|
18
|
-
return false;
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
function escapeValue(value: string): string {
|
|
25
|
-
return value.toLowerCase().replace(/\s/, '-');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
function toTabs(node: DirectiveNode): void {
|
|
30
|
-
const items: string[] = [];
|
|
31
|
-
const tabs: JsxElement[] = [];
|
|
32
|
-
let current: JsxElement | undefined;
|
|
33
|
-
|
|
34
|
-
for (const item of node.children ?? []) {
|
|
35
|
-
if (item.type === 'leafDirective' && (item as { name?: string }).name === 'tab') {
|
|
36
|
-
const label = extractLeafLabel(item);
|
|
37
|
-
items.push(label);
|
|
38
|
-
current = {
|
|
39
|
-
type: 'mdxJsxFlowElement',
|
|
40
|
-
name: 'Tab',
|
|
41
|
-
attributes: [
|
|
42
|
-
{
|
|
43
|
-
type: 'mdxJsxAttribute',
|
|
44
|
-
name: 'value',
|
|
45
|
-
value: escapeValue(label),
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
children: [],
|
|
49
|
-
};
|
|
50
|
-
tabs.push(current);
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
current?.children.push(item);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const attributes = toJsxAttributes(node).map((attribute) =>
|
|
58
|
-
attribute.name === 'default'
|
|
59
|
-
? {
|
|
60
|
-
type: 'mdxJsxAttribute' as const,
|
|
61
|
-
name: 'defaultValue',
|
|
62
|
-
value: escapeValue(String(attribute.value)),
|
|
63
|
-
}
|
|
64
|
-
: attribute,
|
|
65
|
-
);
|
|
66
|
-
attributes.unshift({
|
|
67
|
-
type: 'mdxJsxAttribute',
|
|
68
|
-
name: 'items',
|
|
69
|
-
value: jsxExpression(estreeStringArray(items)),
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
Object.assign(node, {
|
|
73
|
-
type: 'mdxJsxFlowElement',
|
|
74
|
-
name: 'Tabs',
|
|
75
|
-
attributes,
|
|
76
|
-
children: tabs,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Tab,
|
|
3
|
-
Tabs,
|
|
4
|
-
TabsContent,
|
|
5
|
-
TabsList,
|
|
6
|
-
TabsTrigger,
|
|
7
|
-
} from '@terrafirmagreg-team/ui/components/mdx/tabs';
|
|
8
|
-
import {
|
|
9
|
-
Accordion,
|
|
10
|
-
Accordions,
|
|
11
|
-
} from '@terrafirmagreg-team/ui/components/mdx/accordion';
|
|
12
|
-
import { Step, Steps } from '@terrafirmagreg-team/ui/components/mdx/steps';
|
|
13
|
-
import {
|
|
14
|
-
File,
|
|
15
|
-
Folder,
|
|
16
|
-
Files,
|
|
17
|
-
} from '@terrafirmagreg-team/ui/components/mdx/files';
|
|
18
|
-
import { ImageZoom } from '@terrafirmagreg-team/ui/components/mdx/image-zoom';
|
|
19
|
-
import { Banner } from '@terrafirmagreg-team/ui/components/mdx/banner';
|
|
20
|
-
import { TypeTable } from '@terrafirmagreg-team/ui/components/mdx/type-table';
|
|
21
|
-
import { Card, Cards } from '@terrafirmagreg-team/ui/components/mdx/card';
|
|
22
|
-
import { Table } from '@terrafirmagreg-team/ui/components/mdx/table';
|
|
23
|
-
import {
|
|
24
|
-
CalloutDescription,
|
|
25
|
-
CalloutTitle,
|
|
26
|
-
} from '@terrafirmagreg-team/ui/components/mdx/callout';
|
|
27
|
-
import {
|
|
28
|
-
CodeBlock,
|
|
29
|
-
CodeBlockTab,
|
|
30
|
-
CodeBlockTabs,
|
|
31
|
-
CodeBlockTabsList,
|
|
32
|
-
CodeBlockTabsTrigger,
|
|
33
|
-
Pre,
|
|
34
|
-
} from '@terrafirmagreg-team/ui/components/mdx/codeblock';
|
|
35
|
-
import { Heading } from '@terrafirmagreg-team/ui/components/blocks/page/heading';
|
|
36
|
-
import * as Twoslash from 'fumadocs-twoslash/ui';
|
|
37
|
-
import { Mermaid } from '@terrafirmagreg-team/ui/components/mdx/mermaid';
|
|
38
|
-
import { Callout, CalloutContainer } from '@terrafirmagreg-team/ui/components/mdx/callout';
|
|
39
|
-
import { Input, Output, Preview } from '@terrafirmagreg-team/ui/components/mdx/preview';
|
|
40
|
-
import { DocsImage } from '@terrafirmagreg-team/kit/components/docs-image';
|
|
41
|
-
import { Multiblock } from '@terrafirmagreg-team/ui/components/mdx/multiblock';
|
|
42
|
-
import { GradientText } from '@terrafirmagreg-team/ui/components/mdx/gradient-text';
|
|
43
|
-
import { GlowHeader } from '@terrafirmagreg-team/ui/components/mdx/glow-header';
|
|
44
|
-
import { LinkPreview } from '@terrafirmagreg-team/ui/components/blocks/link/link-preview';
|
|
45
|
-
import type { MDXComponents } from 'mdx/types';
|
|
46
|
-
import type { ComponentProps, HTMLAttributes } from 'react';
|
|
47
|
-
|
|
48
|
-
const extras: MDXComponents = {};
|
|
49
|
-
|
|
50
|
-
export function registerMdxComponents(map: MDXComponents): void {
|
|
51
|
-
Object.assign(extras, map);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function getMDXComponents(components?: MDXComponents) {
|
|
55
|
-
return {
|
|
56
|
-
...extras,
|
|
57
|
-
CodeBlockTab,
|
|
58
|
-
CodeBlockTabs,
|
|
59
|
-
CodeBlockTabsList,
|
|
60
|
-
CodeBlockTabsTrigger,
|
|
61
|
-
Tab,
|
|
62
|
-
Tabs,
|
|
63
|
-
TabsContent,
|
|
64
|
-
TabsList,
|
|
65
|
-
TabsTrigger,
|
|
66
|
-
...Twoslash,
|
|
67
|
-
Accordion,
|
|
68
|
-
Accordions,
|
|
69
|
-
Step,
|
|
70
|
-
Steps,
|
|
71
|
-
File,
|
|
72
|
-
Folder,
|
|
73
|
-
Files,
|
|
74
|
-
Mermaid,
|
|
75
|
-
Banner,
|
|
76
|
-
TypeTable,
|
|
77
|
-
Card,
|
|
78
|
-
Cards,
|
|
79
|
-
Callout,
|
|
80
|
-
CalloutContainer,
|
|
81
|
-
CalloutTitle,
|
|
82
|
-
CalloutDescription,
|
|
83
|
-
Preview,
|
|
84
|
-
Input,
|
|
85
|
-
Output,
|
|
86
|
-
DocsImage,
|
|
87
|
-
Multiblock,
|
|
88
|
-
GradientText,
|
|
89
|
-
GlowHeader,
|
|
90
|
-
a: LinkPreview,
|
|
91
|
-
pre: (props: HTMLAttributes<HTMLPreElement>) => (
|
|
92
|
-
<CodeBlock {...props}>
|
|
93
|
-
<Pre>{props.children}</Pre>
|
|
94
|
-
</CodeBlock>
|
|
95
|
-
),
|
|
96
|
-
h1: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
97
|
-
<Heading as="h1" {...props} />
|
|
98
|
-
),
|
|
99
|
-
h2: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
100
|
-
<Heading as="h2" {...props} />
|
|
101
|
-
),
|
|
102
|
-
h3: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
103
|
-
<Heading as="h3" {...props} />
|
|
104
|
-
),
|
|
105
|
-
h4: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
106
|
-
<Heading as="h4" {...props} />
|
|
107
|
-
),
|
|
108
|
-
h5: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
109
|
-
<Heading as="h5" {...props} />
|
|
110
|
-
),
|
|
111
|
-
h6: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
|
112
|
-
<Heading as="h6" {...props} />
|
|
113
|
-
),
|
|
114
|
-
table: Table,
|
|
115
|
-
img: (props: ComponentProps<'img'>) => {
|
|
116
|
-
if (typeof props.src !== 'string' || /^https?:\/\//i.test(props.src)) {
|
|
117
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
118
|
-
return <img {...props} alt={props.alt ?? ''} />;
|
|
119
|
-
}
|
|
120
|
-
const width = Number(props.width) || undefined;
|
|
121
|
-
const height = Number(props.height) || undefined;
|
|
122
|
-
return (
|
|
123
|
-
<ImageZoom
|
|
124
|
-
src={props.src}
|
|
125
|
-
alt={props.alt ?? ''}
|
|
126
|
-
width={width ?? 960}
|
|
127
|
-
height={height ?? 540}
|
|
128
|
-
sizes={props.sizes as string | undefined}
|
|
129
|
-
className={props.className}
|
|
130
|
-
/>
|
|
131
|
-
);
|
|
132
|
-
},
|
|
133
|
-
...components,
|
|
134
|
-
} as MDXComponents;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
declare global {
|
|
138
|
-
type MDXProvidedComponents = ReturnType<typeof getMDXComponents>;
|
|
139
|
-
}
|
package/src/lib/pack-assets.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { DocsImageProps } from '@terrafirmagreg-team/kit/types/mdx';
|
|
2
|
-
|
|
3
|
-
export function packPublicUrl(pack: string, ...segments: string[]): string {
|
|
4
|
-
const rel = segments
|
|
5
|
-
.map((s) => s.replace(/^\/+/, '').replaceAll('\\', '/'))
|
|
6
|
-
.filter(Boolean)
|
|
7
|
-
.join('/');
|
|
8
|
-
return rel ? `/${pack}/${rel}` : `/${pack}`;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function assetUrl(
|
|
12
|
-
pack: string,
|
|
13
|
-
modId: string,
|
|
14
|
-
...pathSegments: string[]
|
|
15
|
-
): string {
|
|
16
|
-
return packPublicUrl(pack, 'assets', modId, ...pathSegments);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function resolveSrc(
|
|
20
|
-
props: Pick<DocsImageProps, 'src' | 'pack' | 'mod' | 'path'>,
|
|
21
|
-
packFallback?: string,
|
|
22
|
-
): string | null {
|
|
23
|
-
if (props.src) {
|
|
24
|
-
const s = props.src.trim();
|
|
25
|
-
if (
|
|
26
|
-
s.startsWith('/') ||
|
|
27
|
-
s.startsWith('http://') ||
|
|
28
|
-
s.startsWith('https://')
|
|
29
|
-
) {
|
|
30
|
-
return s;
|
|
31
|
-
}
|
|
32
|
-
return `/${s.replace(/^\/+/, '')}`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const pack = props.pack ?? packFallback;
|
|
36
|
-
if (!pack) return null;
|
|
37
|
-
|
|
38
|
-
if (props.mod && props.path) {
|
|
39
|
-
return assetUrl(pack, props.mod, props.path);
|
|
40
|
-
}
|
|
41
|
-
if (props.path) {
|
|
42
|
-
return packPublicUrl(pack, props.path);
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
45
|
-
}
|
package/src/lib/preview/index.ts
DELETED
package/src/lib/preview/og.tsx
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { ImageResponse } from 'next/og';
|
|
2
|
-
import type { ReactNode } from 'react';
|
|
3
|
-
import type { ImageResponseOptions } from 'next/dist/compiled/@vercel/og/types';
|
|
4
|
-
|
|
5
|
-
interface GenerateProps {
|
|
6
|
-
title: ReactNode;
|
|
7
|
-
description?: ReactNode;
|
|
8
|
-
icon?: ReactNode;
|
|
9
|
-
primaryColor?: string;
|
|
10
|
-
primaryTextColor?: string;
|
|
11
|
-
site?: ReactNode;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function generateOGImage(options: GenerateProps & ImageResponseOptions): ImageResponse {
|
|
15
|
-
const { title, description, icon, site, primaryColor, primaryTextColor, ...rest } = options;
|
|
16
|
-
|
|
17
|
-
return new ImageResponse(
|
|
18
|
-
generate({
|
|
19
|
-
title,
|
|
20
|
-
description,
|
|
21
|
-
icon,
|
|
22
|
-
site,
|
|
23
|
-
primaryTextColor,
|
|
24
|
-
primaryColor,
|
|
25
|
-
}),
|
|
26
|
-
{
|
|
27
|
-
width: 1200,
|
|
28
|
-
height: 630,
|
|
29
|
-
...rest,
|
|
30
|
-
},
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function generate({
|
|
35
|
-
primaryColor = 'rgba(255,150,255,0.3)',
|
|
36
|
-
primaryTextColor = 'rgb(255,150,255)',
|
|
37
|
-
icon = (
|
|
38
|
-
<svg
|
|
39
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
40
|
-
width="56"
|
|
41
|
-
height="56"
|
|
42
|
-
viewBox="0 0 24 24"
|
|
43
|
-
fill="none"
|
|
44
|
-
stroke="currentColor"
|
|
45
|
-
strokeWidth="2"
|
|
46
|
-
strokeLinecap="round"
|
|
47
|
-
strokeLinejoin="round"
|
|
48
|
-
className="lucide lucide-book-icon lucide-book"
|
|
49
|
-
>
|
|
50
|
-
<circle cx="12" cy="12" r="11" stroke={primaryTextColor} strokeWidth="2" />
|
|
51
|
-
</svg>
|
|
52
|
-
),
|
|
53
|
-
...props
|
|
54
|
-
}: GenerateProps) {
|
|
55
|
-
return (
|
|
56
|
-
<div
|
|
57
|
-
style={{
|
|
58
|
-
display: 'flex',
|
|
59
|
-
flexDirection: 'column',
|
|
60
|
-
width: '100%',
|
|
61
|
-
height: '100%',
|
|
62
|
-
color: 'white',
|
|
63
|
-
padding: '4rem',
|
|
64
|
-
backgroundColor: '#0c0c0c',
|
|
65
|
-
borderBottom: `18px solid ${primaryColor}`,
|
|
66
|
-
}}
|
|
67
|
-
>
|
|
68
|
-
<p
|
|
69
|
-
style={{
|
|
70
|
-
fontWeight: 800,
|
|
71
|
-
fontSize: '82px',
|
|
72
|
-
margin: 0,
|
|
73
|
-
}}
|
|
74
|
-
>
|
|
75
|
-
{props.title}
|
|
76
|
-
</p>
|
|
77
|
-
<p
|
|
78
|
-
style={{
|
|
79
|
-
fontSize: '52px',
|
|
80
|
-
color: 'rgba(240,240,240,0.8)',
|
|
81
|
-
margin: 0,
|
|
82
|
-
marginTop: '16px',
|
|
83
|
-
paddingBottom: '28px',
|
|
84
|
-
borderBottom: `10px dashed ${primaryColor}`,
|
|
85
|
-
}}
|
|
86
|
-
>
|
|
87
|
-
{props.description}
|
|
88
|
-
</p>
|
|
89
|
-
|
|
90
|
-
<div
|
|
91
|
-
style={{
|
|
92
|
-
display: 'flex',
|
|
93
|
-
flexDirection: 'row',
|
|
94
|
-
alignItems: 'center',
|
|
95
|
-
gap: '20px',
|
|
96
|
-
marginTop: 'auto',
|
|
97
|
-
color: primaryTextColor,
|
|
98
|
-
}}
|
|
99
|
-
>
|
|
100
|
-
{icon}
|
|
101
|
-
{props.site && (
|
|
102
|
-
<p
|
|
103
|
-
style={{
|
|
104
|
-
fontSize: '56px',
|
|
105
|
-
fontWeight: 600,
|
|
106
|
-
margin: 0,
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
{props.site}
|
|
110
|
-
</p>
|
|
111
|
-
)}
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import type { Lang } from '@terrafirmagreg-team/translate/types/locale';
|
|
2
|
-
import type { PagePreviewData } from '@terrafirmagreg-team/ui/types/preview';
|
|
3
|
-
|
|
4
|
-
export interface PreviewResolverCtx {
|
|
5
|
-
|
|
6
|
-
parts: string[];
|
|
7
|
-
query: URLSearchParams;
|
|
8
|
-
lang: Lang;
|
|
9
|
-
langMap: Record<string, string>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type PreviewResolver = (
|
|
13
|
-
ctx: PreviewResolverCtx,
|
|
14
|
-
) => Promise<PagePreviewData | undefined>;
|
|
15
|
-
|
|
16
|
-
export interface PreviewResolverOptions {
|
|
17
|
-
|
|
18
|
-
langMap?: (dataset: string, lang: Lang) => Promise<Record<string, string>>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const resolvers = new Map<
|
|
22
|
-
string,
|
|
23
|
-
{ resolve: PreviewResolver; langMap?: PreviewResolverOptions['langMap'] }
|
|
24
|
-
>();
|
|
25
|
-
|
|
26
|
-
export function registerPreviewResolver(
|
|
27
|
-
section: string,
|
|
28
|
-
resolve: PreviewResolver,
|
|
29
|
-
options?: PreviewResolverOptions,
|
|
30
|
-
): void {
|
|
31
|
-
resolvers.set(section, { resolve, langMap: options?.langMap });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function parseHref(href: string | undefined) {
|
|
35
|
-
if (!href || /^(https?:|mailto:|\/\/|#)/i.test(href)) return undefined;
|
|
36
|
-
const [withoutHash] = href.split('#');
|
|
37
|
-
const [pathname, qs] = withoutHash.split('?');
|
|
38
|
-
if (!pathname.startsWith('/')) return undefined;
|
|
39
|
-
return {
|
|
40
|
-
withoutHash,
|
|
41
|
-
query: new URLSearchParams(qs),
|
|
42
|
-
parts: pathname.split('/').filter(Boolean),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function resolveLinkPreview(
|
|
47
|
-
href: string,
|
|
48
|
-
lang?: string,
|
|
49
|
-
): Promise<PagePreviewData | undefined> {
|
|
50
|
-
const parsed = parseHref(href);
|
|
51
|
-
if (!parsed) return undefined;
|
|
52
|
-
const resolvedLang = (parsed.query.get('lang') ?? lang) as Lang | undefined;
|
|
53
|
-
const entry = resolvers.get(parsed.parts[0] ?? '');
|
|
54
|
-
if (entry && resolvedLang) {
|
|
55
|
-
const dataset = parsed.parts[1];
|
|
56
|
-
if (!dataset) return undefined;
|
|
57
|
-
const langMap = entry.langMap
|
|
58
|
-
? await entry.langMap(dataset, resolvedLang)
|
|
59
|
-
: {};
|
|
60
|
-
return entry.resolve({
|
|
61
|
-
parts: parsed.parts,
|
|
62
|
-
query: parsed.query,
|
|
63
|
-
lang: resolvedLang,
|
|
64
|
-
langMap,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
const res = await fetch(
|
|
68
|
-
`/api/preview?href=${encodeURIComponent(parsed.withoutHash)}${
|
|
69
|
-
resolvedLang ? `&lang=${encodeURIComponent(resolvedLang)}` : ''
|
|
70
|
-
}`,
|
|
71
|
-
);
|
|
72
|
-
if (!res.ok) return undefined;
|
|
73
|
-
return ((await res.json()) ?? undefined) as PagePreviewData | undefined;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export async function loadClientPreviews(
|
|
77
|
-
lang: Lang,
|
|
78
|
-
langMap: Record<string, string>,
|
|
79
|
-
hrefs: Iterable<string>,
|
|
80
|
-
): Promise<Record<string, PagePreviewData>> {
|
|
81
|
-
const out: Record<string, PagePreviewData> = {};
|
|
82
|
-
await Promise.all(
|
|
83
|
-
[...hrefs].map(async (href) => {
|
|
84
|
-
const parsed = parseHref(href);
|
|
85
|
-
if (!parsed) return;
|
|
86
|
-
const entry = resolvers.get(parsed.parts[0] ?? '');
|
|
87
|
-
if (!entry) return;
|
|
88
|
-
const preview = await entry.resolve({
|
|
89
|
-
parts: parsed.parts,
|
|
90
|
-
query: parsed.query,
|
|
91
|
-
lang,
|
|
92
|
-
langMap,
|
|
93
|
-
});
|
|
94
|
-
if (preview) out[href] = preview;
|
|
95
|
-
}),
|
|
96
|
-
);
|
|
97
|
-
return out;
|
|
98
|
-
}
|
package/src/lib/search/config.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { LangConfig } from '@terrafirmagreg-team/translate/lang';
|
|
2
|
-
import { createConfig } from '@terrafirmagreg-team/kit/lib/config';
|
|
3
|
-
import type { LocalizedIndex } from './indexes';
|
|
4
|
-
|
|
5
|
-
export interface SearchConfig {
|
|
6
|
-
|
|
7
|
-
indexes(): Promise<LocalizedIndex[]>;
|
|
8
|
-
|
|
9
|
-
i18n(): LangConfig;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const { register: registerSearchConfig, get: searchConfig } =
|
|
13
|
-
createConfig<SearchConfig>('Search');
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { SortedResult } from '@terrafirmagreg-team/ui/types/search';
|
|
2
|
-
|
|
3
|
-
export type SearchHitFilter = (hit: SortedResult) => boolean;
|
|
4
|
-
export type SearchHitFilterFactory = (
|
|
5
|
-
params: URLSearchParams,
|
|
6
|
-
) => SearchHitFilter | undefined;
|
|
7
|
-
|
|
8
|
-
const hitFilters = new Map<string, SearchHitFilterFactory>();
|
|
9
|
-
|
|
10
|
-
export function registerSearchHitFilter(
|
|
11
|
-
section: string,
|
|
12
|
-
factory: SearchHitFilterFactory,
|
|
13
|
-
): void {
|
|
14
|
-
hitFilters.set(section, factory);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function searchHitFilter(
|
|
18
|
-
section: string,
|
|
19
|
-
params: URLSearchParams,
|
|
20
|
-
): SearchHitFilter | undefined {
|
|
21
|
-
return hitFilters.get(section)?.(params);
|
|
22
|
-
}
|
package/src/lib/search/index.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export { mergeClients } from './merge';
|
|
2
|
-
export { pageStructuredData } from './structured';
|
|
3
|
-
export {
|
|
4
|
-
buildSearchIndexes,
|
|
5
|
-
type LocalizedIndex,
|
|
6
|
-
type SearchIndexPage,
|
|
7
|
-
type SearchPageSource,
|
|
8
|
-
} from './indexes';
|
|
9
|
-
export {
|
|
10
|
-
registerSearchConfig,
|
|
11
|
-
searchConfig,
|
|
12
|
-
type SearchConfig,
|
|
13
|
-
} from './config';
|
|
14
|
-
export {
|
|
15
|
-
registerSearchHitFilter,
|
|
16
|
-
searchHitFilter,
|
|
17
|
-
type SearchHitFilter,
|
|
18
|
-
type SearchHitFilterFactory,
|
|
19
|
-
} from './filters';
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { AdvancedIndex } from 'fumadocs-core/search/server';
|
|
2
|
-
import { stripLangFromUrl } from '@terrafirmagreg-team/translate/lib/slug';
|
|
3
|
-
import { pageStructuredData } from './structured';
|
|
4
|
-
|
|
5
|
-
export type LocalizedIndex = AdvancedIndex & { locale: string };
|
|
6
|
-
|
|
7
|
-
export interface SearchIndexPage {
|
|
8
|
-
slugs: string[];
|
|
9
|
-
url: string;
|
|
10
|
-
data: { title?: string; description?: string };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface SearchPageSource {
|
|
14
|
-
source: { getPages(): SearchIndexPage[] };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function buildSearchIndexes(
|
|
18
|
-
sources: Record<string, SearchPageSource | undefined>,
|
|
19
|
-
languages: readonly string[],
|
|
20
|
-
): Promise<LocalizedIndex[]> {
|
|
21
|
-
const rows = (
|
|
22
|
-
await Promise.all(
|
|
23
|
-
Object.entries(sources).flatMap(([section, entry]) =>
|
|
24
|
-
entry?.source.getPages().map(async (page) => {
|
|
25
|
-
const [dataset, lang] = page.slugs;
|
|
26
|
-
if (!dataset || !lang) return null;
|
|
27
|
-
return {
|
|
28
|
-
title: page.data.title ?? page.url,
|
|
29
|
-
description: page.data.description,
|
|
30
|
-
url: stripLangFromUrl(page.url, [...languages]),
|
|
31
|
-
id: page.url,
|
|
32
|
-
tag: `${section}:${dataset}`,
|
|
33
|
-
locale: lang,
|
|
34
|
-
structuredData: await pageStructuredData(
|
|
35
|
-
page.data as Record<string, unknown>,
|
|
36
|
-
),
|
|
37
|
-
} satisfies LocalizedIndex;
|
|
38
|
-
}) ?? [],
|
|
39
|
-
),
|
|
40
|
-
)
|
|
41
|
-
).filter((index) => index !== null);
|
|
42
|
-
return rows;
|
|
43
|
-
}
|
package/src/lib/search/merge.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { SearchClient } from 'fumadocs-core/search/client';
|
|
2
|
-
|
|
3
|
-
export function mergeClients(...clients: SearchClient[]): SearchClient {
|
|
4
|
-
return {
|
|
5
|
-
deps: clients.flatMap((client) => client.deps ?? []),
|
|
6
|
-
async search(query) {
|
|
7
|
-
const lists = await Promise.all(
|
|
8
|
-
clients.map((client) => client.search(query)),
|
|
9
|
-
);
|
|
10
|
-
const seen = new Set<string>();
|
|
11
|
-
const out = [];
|
|
12
|
-
for (const list of lists) {
|
|
13
|
-
for (const hit of list) {
|
|
14
|
-
if (seen.has(hit.id)) continue;
|
|
15
|
-
seen.add(hit.id);
|
|
16
|
-
out.push(hit);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return out;
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
}
|
package/src/lib/search/server.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import 'server-only';
|
|
2
|
-
import { createI18nSearchAPI } from 'fumadocs-core/search/server';
|
|
3
|
-
import { searchConfig } from './config';
|
|
4
|
-
|
|
5
|
-
async function createSearchApi() {
|
|
6
|
-
const config = searchConfig();
|
|
7
|
-
return createI18nSearchAPI('advanced', {
|
|
8
|
-
i18n: config.i18n(),
|
|
9
|
-
indexes: await config.indexes(),
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
let cached: ReturnType<typeof createSearchApi> | undefined;
|
|
14
|
-
|
|
15
|
-
export function loadSearchApi() {
|
|
16
|
-
cached ??= createSearchApi();
|
|
17
|
-
return cached;
|
|
18
|
-
}
|