@lexibase/rdx-next 4.1.0 → 5.0.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/bin/cli.mjs +1 -1
- package/bin/locale-routes.mjs +31 -1
- package/config.mjs +1 -1
- package/dist/runtime/index.d.ts +12 -1
- package/dist/runtime/index.js +225 -58
- package/package.json +7 -7
- package/templates/runtime/app/docs/llms.txt/route.ts +8 -0
- package/templates/runtime/app/rdx-markdown/[...path]/route.ts +19 -0
package/bin/cli.mjs
CHANGED
|
@@ -74,7 +74,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
74
74
|
['--help', '-h'].includes(commandArgs[0])
|
|
75
75
|
) {
|
|
76
76
|
console.log(
|
|
77
|
-
'Usage: rdx check\nValidate static MDX links, section anchors and local public/ files without building the site.'
|
|
77
|
+
'Usage: rdx check\nValidate static Markdown and MDX links, section anchors and local public/ files without building the site.'
|
|
78
78
|
)
|
|
79
79
|
return
|
|
80
80
|
}
|
package/bin/locale-routes.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { lstat, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
1
|
+
import { lstat, mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
4
|
const defaultFiles = [
|
|
@@ -14,6 +14,7 @@ const generated = [
|
|
|
14
14
|
'app/(rdx-locales)/[locale]/not-found.tsx',
|
|
15
15
|
'app/(rdx-locales)/[locale]/docs/[[...slug]]/page.tsx',
|
|
16
16
|
'app/(rdx-locales)/[locale]/rdx-search/[source]/route.ts',
|
|
17
|
+
'app/(rdx-locales)/[locale]/docs/llms.txt/route.ts',
|
|
17
18
|
]
|
|
18
19
|
|
|
19
20
|
/** Root layouts keep HTML language correct on the server, without middleware. */
|
|
@@ -34,6 +35,18 @@ export async function prepareLocaleRoutes(project, runtime, template) {
|
|
|
34
35
|
}
|
|
35
36
|
return current
|
|
36
37
|
}
|
|
38
|
+
// An existing public index owns this URL. Keep it when upgrading a project.
|
|
39
|
+
const publicIndex = path.join(project.rootDir, 'public', 'docs', 'llms.txt')
|
|
40
|
+
const hasPublicIndex = await stat(publicIndex).then(
|
|
41
|
+
(entry) => entry.isFile(),
|
|
42
|
+
(error) => {
|
|
43
|
+
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') return false
|
|
44
|
+
throw error
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
if (hasPublicIndex)
|
|
48
|
+
await rm(await safe('app/docs/llms.txt/route.ts'), { force: true })
|
|
49
|
+
|
|
37
50
|
const marker = await safe('.rdx-localization.json')
|
|
38
51
|
let owned = false
|
|
39
52
|
try {
|
|
@@ -130,6 +143,23 @@ export async function generateStaticParams() {
|
|
|
130
143
|
return project.localization!.locales.flatMap(locale => getSearchSources(getLocalizedProject(project, locale.path)).map(source => ({ locale: locale.path, ...source })))
|
|
131
144
|
}
|
|
132
145
|
export async function GET(_request: Request, { params }: { params: Promise<{ locale: string, source: string }> }) { const { locale, source } = await params; return getSearchResponse(getLocalizedProject(await getProject(), locale), source) }
|
|
146
|
+
`
|
|
147
|
+
)
|
|
148
|
+
await emit(
|
|
149
|
+
'app/(rdx-locales)/[locale]/docs/llms.txt/route.ts',
|
|
150
|
+
`import { getLlmIndexResponse, getLocalizedProject } from '${provider}'
|
|
151
|
+
import { getProject } from '../../../../../rdx-project'
|
|
152
|
+
export const dynamic = 'force-static'
|
|
153
|
+
export const dynamicParams = false
|
|
154
|
+
export async function generateStaticParams() {
|
|
155
|
+
return (await getProject()).localization!.locales.map(locale => ({ locale: locale.path }))
|
|
156
|
+
}
|
|
157
|
+
export async function GET(_request: Request, { params }: { params: Promise<{ locale: string }> }) {
|
|
158
|
+
const project = await getProject()
|
|
159
|
+
const { locale } = await params
|
|
160
|
+
if (!project.localization?.locales.some(entry => entry.path === locale)) return new Response(null, { status: 404 })
|
|
161
|
+
return getLlmIndexResponse(getLocalizedProject(project, locale))
|
|
162
|
+
}
|
|
133
163
|
`
|
|
134
164
|
)
|
|
135
165
|
await writeFile(marker, JSON.stringify({ version: 1 }) + '\n')
|
package/config.mjs
CHANGED
|
@@ -49,7 +49,7 @@ async function contentFiles(directory) {
|
|
|
49
49
|
const filename = path.join(directory, entry.name)
|
|
50
50
|
if (entry.isDirectory()) return contentFiles(filename)
|
|
51
51
|
return entry.isFile() &&
|
|
52
|
-
(entry.name
|
|
52
|
+
(/\.mdx?$/.test(entry.name) || entry.name === '_category.json')
|
|
53
53
|
? [filename]
|
|
54
54
|
: []
|
|
55
55
|
})
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -21,6 +21,17 @@ declare function getRdxSitemap(project: RdxProject, { documentPath, }?: {
|
|
|
21
21
|
documentPath?: (source: RdxContentSource, page: RdxDocPage) => string;
|
|
22
22
|
}): MetadataRoute.Sitemap;
|
|
23
23
|
|
|
24
|
+
type DocumentPath = (source: RdxContentSource, page: Pick<RdxDocPage, 'slug' | 'sourcePath'>) => string;
|
|
25
|
+
declare function getMarkdownHref(htmlPath: string): string;
|
|
26
|
+
declare function getLlmIndexResponse(project: RdxProject, documentPath?: DocumentPath): Response;
|
|
27
|
+
declare function getMarkdownPaths(project: RdxProject, documentPath?: DocumentPath): {
|
|
28
|
+
path: string[];
|
|
29
|
+
}[];
|
|
30
|
+
declare function parseMarkdownPath(path: string[]): string[] | undefined;
|
|
31
|
+
declare function getMarkdownResponse(project: RdxProject, path: string[]): Response;
|
|
32
|
+
declare function markdownNotFound(): Response;
|
|
33
|
+
declare function getDocumentMarkdownResponse(project: RdxProject, source: RdxContentSource | undefined, slug: string, documentPath?: DocumentPath): Response;
|
|
34
|
+
|
|
24
35
|
/** Read metadata from the same content source and index used by the page. */
|
|
25
36
|
declare function getDocumentMetadata({ project, slug, }: {
|
|
26
37
|
project: RdxProject;
|
|
@@ -47,4 +58,4 @@ declare function DocsPage({ slug, project, }: {
|
|
|
47
58
|
project: RdxProject;
|
|
48
59
|
}): Promise<react.JSX.Element>;
|
|
49
60
|
|
|
50
|
-
export { DocsPage, HomePage, NotFoundPage, RdxLayout, getDocumentMetadata, getPageMetadata, getRdxMetadata, getRdxRobots, getRdxSitemap, getSearchResponse, getSearchSources, getSourceRobots };
|
|
61
|
+
export { DocsPage, HomePage, NotFoundPage, RdxLayout, getDocumentMarkdownResponse, getDocumentMetadata, getLlmIndexResponse, getMarkdownHref, getMarkdownPaths, getMarkdownResponse, getPageMetadata, getRdxMetadata, getRdxRobots, getRdxSitemap, getSearchResponse, getSearchSources, getSourceRobots, markdownNotFound, parseMarkdownPath };
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
// src/runtime/index.tsx
|
|
2
2
|
import {
|
|
3
|
-
getDocument as
|
|
3
|
+
getDocument as getDocument4,
|
|
4
4
|
getDocsPaths,
|
|
5
|
-
getSourceOptions as
|
|
5
|
+
getSourceOptions as getSourceOptions5,
|
|
6
6
|
resolveDocsRoute as resolveDocsRoute2,
|
|
7
|
-
getLocalizedProject as
|
|
8
|
-
getDocsHref as
|
|
7
|
+
getLocalizedProject as getLocalizedProject3,
|
|
8
|
+
getDocsHref as getDocsHref4,
|
|
9
9
|
getLanguageLinks,
|
|
10
|
-
isFallbackPage as
|
|
10
|
+
isFallbackPage as isFallbackPage4
|
|
11
11
|
} from "@lexibase/rdx-core";
|
|
12
|
+
import { getEditPageHref } from "@lexibase/rdx-core/config";
|
|
12
13
|
import { Button } from "@lexibase/rdx-ui/components/button";
|
|
13
14
|
import { Callout } from "@lexibase/rdx-ui/components/callout";
|
|
14
15
|
import { LanguageDropdown } from "@lexibase/rdx-ui/components/language-dropdown";
|
|
@@ -19,7 +20,9 @@ import { DocsSearch } from "@lexibase/rdx-ui/components/docs-search";
|
|
|
19
20
|
import { Home } from "@lexibase/rdx-ui/components/home";
|
|
20
21
|
import { SkipLink } from "@lexibase/rdx-ui/components/skip-link";
|
|
21
22
|
import { FooterCredit } from "@lexibase/rdx-ui/components/footer-credit";
|
|
22
|
-
import {
|
|
23
|
+
import { EditPageLink } from "@lexibase/rdx-ui/components/edit-page-link";
|
|
24
|
+
import { CopyPage } from "@lexibase/rdx-ui/components/copy-page";
|
|
25
|
+
import { BrandLogo } from "@lexibase/rdx-ui/components/brand-logo";
|
|
23
26
|
import { getMdxComponents } from "@lexibase/rdx-ui/components/mdx-components";
|
|
24
27
|
import { getMessages, formatMessage } from "@lexibase/rdx-ui/lib/i18n";
|
|
25
28
|
import { LocaleProvider } from "@lexibase/rdx-ui/providers/locale-provider";
|
|
@@ -49,6 +52,7 @@ function compileDocumentation(source, components, links) {
|
|
|
49
52
|
blockJS: true,
|
|
50
53
|
blockDangerousJS: true,
|
|
51
54
|
mdxOptions: {
|
|
55
|
+
format: links?.sourcePath.endsWith(".md") ? "md" : "mdx",
|
|
52
56
|
remarkPlugins: [
|
|
53
57
|
remarkGfm,
|
|
54
58
|
remarkDocumentationComponents,
|
|
@@ -60,19 +64,164 @@ function compileDocumentation(source, components, links) {
|
|
|
60
64
|
});
|
|
61
65
|
}
|
|
62
66
|
|
|
67
|
+
// src/runtime/markdown.ts
|
|
68
|
+
import {
|
|
69
|
+
getContentSources,
|
|
70
|
+
getDocsHref,
|
|
71
|
+
getDocsIndex,
|
|
72
|
+
getDocument,
|
|
73
|
+
getLocalizedProject,
|
|
74
|
+
getSourceOptions,
|
|
75
|
+
isFallbackPage
|
|
76
|
+
} from "@lexibase/rdx-core";
|
|
77
|
+
import { exportMarkdownBody } from "@lexibase/rdx-core/mdx";
|
|
78
|
+
function publicUrl(project, path) {
|
|
79
|
+
const base = project.config.metadata.metadataBase;
|
|
80
|
+
return base ? new URL(path, base).href : path;
|
|
81
|
+
}
|
|
82
|
+
function indexPath(project) {
|
|
83
|
+
return `${project.locale ? `/${project.locale.path}` : ""}/docs/llms.txt`;
|
|
84
|
+
}
|
|
85
|
+
function defaultLocale(project) {
|
|
86
|
+
const locale = project.localization?.locales.find(
|
|
87
|
+
(entry) => entry.code === project.localization.defaultLocale
|
|
88
|
+
);
|
|
89
|
+
return !project.locale && locale ? getLocalizedProject(project, locale.path) : project;
|
|
90
|
+
}
|
|
91
|
+
function text(value) {
|
|
92
|
+
return value.replace(/\s+/g, " ").trim().replace(/[\\`*_[\]<>]/g, "\\$&");
|
|
93
|
+
}
|
|
94
|
+
function getMarkdownHref(htmlPath) {
|
|
95
|
+
return `/rdx-markdown${htmlPath}.md`;
|
|
96
|
+
}
|
|
97
|
+
function response(body, type, status = 200) {
|
|
98
|
+
return new Response(body, {
|
|
99
|
+
status,
|
|
100
|
+
headers: {
|
|
101
|
+
"Content-Type": `${type}; charset=utf-8`,
|
|
102
|
+
"X-Robots-Tag": "noindex, follow"
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function getLlmIndexResponse(project, documentPath) {
|
|
107
|
+
project = defaultLocale(project);
|
|
108
|
+
const source = project.sources.find(
|
|
109
|
+
(entry) => entry.id !== "current" && entry.redirectTo === void 0 && entry.badge !== "Archived"
|
|
110
|
+
) ?? project.sources[0];
|
|
111
|
+
const { metadata, description } = project.config;
|
|
112
|
+
const lines = [`# ${text(metadata.applicationName)} Documentation`, ""];
|
|
113
|
+
if (description) lines.push(`> ${text(description)}`, "");
|
|
114
|
+
if (source) {
|
|
115
|
+
for (const category of getDocsIndex(getSourceOptions(project, source))) {
|
|
116
|
+
const pages = category.pages.filter(
|
|
117
|
+
(page) => !isFallbackPage(project, source, page.sourcePath)
|
|
118
|
+
);
|
|
119
|
+
if (!pages.length) continue;
|
|
120
|
+
lines.push(`## ${text(category.title)}`, "");
|
|
121
|
+
for (const page of pages) {
|
|
122
|
+
const href = documentPath?.(source, page) ?? getDocsHref(project, source, page.slug);
|
|
123
|
+
lines.push(
|
|
124
|
+
`- [${text(page.title)}](<${publicUrl(project, getMarkdownHref(href))}>)${page.description ? `: ${text(page.description)}` : ""}`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
lines.push("");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return response(lines.join("\n"), "text/plain");
|
|
131
|
+
}
|
|
132
|
+
function getMarkdownPaths(project, documentPath) {
|
|
133
|
+
const paths = /* @__PURE__ */ new Set();
|
|
134
|
+
for (const source of getContentSources(project)) {
|
|
135
|
+
if (source.redirectTo !== void 0) continue;
|
|
136
|
+
for (const category of getDocsIndex(getSourceOptions(project, source))) {
|
|
137
|
+
for (const page of category.pages) {
|
|
138
|
+
if (isFallbackPage(project, source, page.sourcePath)) continue;
|
|
139
|
+
const href = documentPath?.(source, page) ?? getDocsHref(project, source, page.slug);
|
|
140
|
+
paths.add(`${href.slice(1)}.md`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return [...paths].map((path) => ({
|
|
145
|
+
path: path.split("/").map(decodeURIComponent)
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
function parseMarkdownPath(path) {
|
|
149
|
+
const last = path.at(-1);
|
|
150
|
+
return last?.endsWith(".md") && last.length > 3 ? [...path.slice(0, -1), last.slice(0, -3)] : void 0;
|
|
151
|
+
}
|
|
152
|
+
function getMarkdownResponse(project, path) {
|
|
153
|
+
const segments = parseMarkdownPath(path);
|
|
154
|
+
if (!segments) return markdownNotFound();
|
|
155
|
+
if (project.localization) {
|
|
156
|
+
const locale = segments.shift();
|
|
157
|
+
if (!project.localization.locales.some((entry) => entry.path === locale))
|
|
158
|
+
return markdownNotFound();
|
|
159
|
+
project = getLocalizedProject(project, locale);
|
|
160
|
+
}
|
|
161
|
+
if (segments.shift() !== "docs" || !segments.length) return markdownNotFound();
|
|
162
|
+
const edition = project.sources.find(
|
|
163
|
+
(source) => source.routePrefix && source.routePrefix === segments[0]
|
|
164
|
+
);
|
|
165
|
+
if (edition) segments.shift();
|
|
166
|
+
return getDocumentMarkdownResponse(
|
|
167
|
+
project,
|
|
168
|
+
edition ?? project.sources[0],
|
|
169
|
+
segments.join("/")
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
function markdownNotFound() {
|
|
173
|
+
return response(null, "text/markdown", 404);
|
|
174
|
+
}
|
|
175
|
+
function getDocumentMarkdownResponse(project, source, slug, documentPath) {
|
|
176
|
+
if (!source || !slug || source.redirectTo !== void 0)
|
|
177
|
+
return markdownNotFound();
|
|
178
|
+
const options = getSourceOptions(project, source);
|
|
179
|
+
const document = getDocument(slug, options);
|
|
180
|
+
if (!document || isFallbackPage(project, source, document.sourcePath))
|
|
181
|
+
return markdownNotFound();
|
|
182
|
+
const pages = getDocsIndex(options).flatMap((category) => category.pages);
|
|
183
|
+
const bySlug = new Map(pages.map((page2) => [page2.slug, page2]));
|
|
184
|
+
const href = (page2) => publicUrl(
|
|
185
|
+
project,
|
|
186
|
+
documentPath?.(source, page2) ?? getDocsHref(project, source, page2.slug)
|
|
187
|
+
);
|
|
188
|
+
const page = bySlug.get(document.slug);
|
|
189
|
+
const frontmatter = {
|
|
190
|
+
title: page.title,
|
|
191
|
+
...page.description ? { description: page.description } : {},
|
|
192
|
+
url: href(document),
|
|
193
|
+
docs_index: publicUrl(project, indexPath(project))
|
|
194
|
+
};
|
|
195
|
+
const fields = Object.entries(frontmatter).map(
|
|
196
|
+
([key, value]) => `${key}: ${JSON.stringify(value)}`
|
|
197
|
+
);
|
|
198
|
+
const body = exportMarkdownBody(document.content, {
|
|
199
|
+
sourceRoot: options.docsDir,
|
|
200
|
+
sourcePath: document.sourcePath,
|
|
201
|
+
virtualPaths: !!options.fallbackDocsDir,
|
|
202
|
+
documents: pages,
|
|
203
|
+
documentHref: (slug2) => href(bySlug.get(slug2))
|
|
204
|
+
});
|
|
205
|
+
return response(`---
|
|
206
|
+
${fields.join("\n")}
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
${body}`, "text/markdown");
|
|
210
|
+
}
|
|
211
|
+
|
|
63
212
|
// src/runtime/index.tsx
|
|
64
213
|
import {
|
|
65
214
|
createRdxProject,
|
|
66
215
|
getProjectDocsPaths,
|
|
67
|
-
getLocalizedProject as
|
|
216
|
+
getLocalizedProject as getLocalizedProject4
|
|
68
217
|
} from "@lexibase/rdx-core";
|
|
69
218
|
|
|
70
219
|
// src/runtime/search.ts
|
|
71
220
|
import {
|
|
72
|
-
getDocsIndex,
|
|
73
|
-
getDocument,
|
|
74
|
-
getSourceOptions,
|
|
75
|
-
getDocsHref
|
|
221
|
+
getDocsIndex as getDocsIndex2,
|
|
222
|
+
getDocument as getDocument2,
|
|
223
|
+
getSourceOptions as getSourceOptions2,
|
|
224
|
+
getDocsHref as getDocsHref2
|
|
76
225
|
} from "@lexibase/rdx-core";
|
|
77
226
|
import { buildSearchIndex } from "@lexibase/rdx-core/search";
|
|
78
227
|
function getSearchSources(project) {
|
|
@@ -88,15 +237,16 @@ function getSearchResponse(project, key) {
|
|
|
88
237
|
if (!source) return new Response(null, { status: 404, headers });
|
|
89
238
|
if (source.fallbackOnly)
|
|
90
239
|
return Response.json(buildSearchIndex([]), { headers });
|
|
91
|
-
const { docsDir } =
|
|
240
|
+
const { docsDir } = getSourceOptions2(project, source);
|
|
92
241
|
const options = { docsDir };
|
|
93
|
-
const documents =
|
|
242
|
+
const documents = getDocsIndex2(options).flatMap(
|
|
94
243
|
(category) => category.pages.map((page) => ({
|
|
95
244
|
title: page.title,
|
|
96
245
|
description: page.description,
|
|
97
246
|
category: category.title,
|
|
98
|
-
href:
|
|
99
|
-
|
|
247
|
+
href: getDocsHref2(project, source, page.slug),
|
|
248
|
+
sourcePath: page.sourcePath,
|
|
249
|
+
content: getDocument2(page.slug, options)?.content ?? ""
|
|
100
250
|
}))
|
|
101
251
|
);
|
|
102
252
|
return Response.json(buildSearchIndex(documents), { headers });
|
|
@@ -104,10 +254,10 @@ function getSearchResponse(project, key) {
|
|
|
104
254
|
|
|
105
255
|
// src/runtime/indexing.ts
|
|
106
256
|
import {
|
|
107
|
-
getDocsIndex as
|
|
108
|
-
getSourceOptions as
|
|
109
|
-
getContentSources,
|
|
110
|
-
isFallbackPage
|
|
257
|
+
getDocsIndex as getDocsIndex3,
|
|
258
|
+
getSourceOptions as getSourceOptions3,
|
|
259
|
+
getContentSources as getContentSources2,
|
|
260
|
+
isFallbackPage as isFallbackPage2
|
|
111
261
|
} from "@lexibase/rdx-core";
|
|
112
262
|
function getSourceRobots(project, source) {
|
|
113
263
|
const published = project.sources.some(
|
|
@@ -136,11 +286,11 @@ function getRdxSitemap(project, {
|
|
|
136
286
|
if (!base) return [];
|
|
137
287
|
const urls = /* @__PURE__ */ new Set();
|
|
138
288
|
if (project.config.homepage?.enabled) urls.add(new URL("/", base).href);
|
|
139
|
-
for (const source of
|
|
289
|
+
for (const source of getContentSources2(project)) {
|
|
140
290
|
if (!getSourceRobots(project, source).index) continue;
|
|
141
|
-
for (const category of
|
|
291
|
+
for (const category of getDocsIndex3(getSourceOptions3(project, source))) {
|
|
142
292
|
for (const page of category.pages) {
|
|
143
|
-
if (
|
|
293
|
+
if (isFallbackPage2(project, source, page.sourcePath)) continue;
|
|
144
294
|
urls.add(new URL(documentPath(source, page), base).href);
|
|
145
295
|
}
|
|
146
296
|
}
|
|
@@ -151,11 +301,11 @@ function getRdxSitemap(project, {
|
|
|
151
301
|
// src/runtime/metadata.ts
|
|
152
302
|
import {
|
|
153
303
|
resolveDocsRoute,
|
|
154
|
-
getLocalizedProject,
|
|
155
|
-
getDocsHref as
|
|
156
|
-
isFallbackPage as
|
|
157
|
-
getDocument as
|
|
158
|
-
getSourceOptions as
|
|
304
|
+
getLocalizedProject as getLocalizedProject2,
|
|
305
|
+
getDocsHref as getDocsHref3,
|
|
306
|
+
isFallbackPage as isFallbackPage3,
|
|
307
|
+
getDocument as getDocument3,
|
|
308
|
+
getSourceOptions as getSourceOptions4
|
|
159
309
|
} from "@lexibase/rdx-core";
|
|
160
310
|
import { notFound } from "next/navigation";
|
|
161
311
|
function getDocumentMetadata({
|
|
@@ -170,24 +320,24 @@ function getDocumentMetadata({
|
|
|
170
320
|
if (!route.slug) return { robots: { index: false, follow: true } };
|
|
171
321
|
if (!route.document) notFound();
|
|
172
322
|
const page = route.categories.flatMap((category) => category.pages).find((page2) => page2.slug === route.slug);
|
|
173
|
-
const fallback =
|
|
323
|
+
const fallback = isFallbackPage3(project, route.source, page.sourcePath);
|
|
174
324
|
const primary = project.localization?.locales.find(
|
|
175
325
|
(locale) => locale.code === project.localization.defaultLocale
|
|
176
326
|
);
|
|
177
|
-
const canonicalProject = fallback ?
|
|
327
|
+
const canonicalProject = fallback ? getLocalizedProject2(project, primary.path) : project;
|
|
178
328
|
const base = project.config.metadata.metadataBase;
|
|
179
329
|
const languages = project.localization && base ? Object.fromEntries(
|
|
180
330
|
project.localization.locales.flatMap((locale) => {
|
|
181
|
-
const view =
|
|
331
|
+
const view = getLocalizedProject2(project, locale.path);
|
|
182
332
|
const source = view.sources.find(
|
|
183
333
|
(entry) => entry.id === route.source.id
|
|
184
334
|
);
|
|
185
|
-
return !source.fallbackOnly &&
|
|
186
|
-
docsDir:
|
|
335
|
+
return !source.fallbackOnly && getDocument3(page.slug, {
|
|
336
|
+
docsDir: getSourceOptions4(view, source).docsDir
|
|
187
337
|
}) ? [
|
|
188
338
|
[
|
|
189
339
|
locale.code,
|
|
190
|
-
new URL(
|
|
340
|
+
new URL(getDocsHref3(view, source, page.slug), base).href
|
|
191
341
|
]
|
|
192
342
|
] : [];
|
|
193
343
|
})
|
|
@@ -198,7 +348,7 @@ function getDocumentMetadata({
|
|
|
198
348
|
...project.localization && base ? {
|
|
199
349
|
alternates: {
|
|
200
350
|
canonical: new URL(
|
|
201
|
-
|
|
351
|
+
getDocsHref3(
|
|
202
352
|
canonicalProject,
|
|
203
353
|
canonicalProject.sources.find(
|
|
204
354
|
(entry) => entry.id === route.source.id
|
|
@@ -278,16 +428,15 @@ function RdxHeader({
|
|
|
278
428
|
const messages = getMessages(config.lang);
|
|
279
429
|
const { source, slug: currentSlug } = resolveDocsRoute2(project, slug);
|
|
280
430
|
const options = project.sources.filter((edition) => edition.redirectTo === void 0).map((edition) => {
|
|
281
|
-
const docs =
|
|
282
|
-
const destination = currentSlug &&
|
|
431
|
+
const docs = getSourceOptions5(project, edition);
|
|
432
|
+
const destination = currentSlug && getDocument4(currentSlug, docs) ? currentSlug : getDocsPaths(docs)[0];
|
|
283
433
|
return {
|
|
284
434
|
id: edition.id,
|
|
285
435
|
label: edition.id === "current" ? messages.current : formatMessage(messages.version, { version: edition.label }),
|
|
286
436
|
kind: edition.id === "current" ? "live" : edition.badge === "Archived" ? "archived" : "version",
|
|
287
|
-
href:
|
|
437
|
+
href: getDocsHref4(project, edition, destination)
|
|
288
438
|
};
|
|
289
439
|
});
|
|
290
|
-
const BrandLogo = config.navbar?.logo ?? Logo;
|
|
291
440
|
return /* @__PURE__ */ jsx(
|
|
292
441
|
Navbar,
|
|
293
442
|
{
|
|
@@ -301,9 +450,9 @@ function RdxHeader({
|
|
|
301
450
|
}
|
|
302
451
|
) : void 0,
|
|
303
452
|
siteTitle: config.metadata.applicationName,
|
|
304
|
-
logo: /* @__PURE__ */ jsx(BrandLogo, { className: "size-5" }),
|
|
305
|
-
homeHref: config.homepage?.enabled ? "/" :
|
|
306
|
-
docsHref:
|
|
453
|
+
logo: /* @__PURE__ */ jsx(BrandLogo, { source: config.navbar?.logo, className: "size-5" }),
|
|
454
|
+
homeHref: config.homepage?.enabled ? "/" : getDocsHref4(project),
|
|
455
|
+
docsHref: getDocsHref4(project, source),
|
|
307
456
|
languageMenu: project.localization ? /* @__PURE__ */ jsx(
|
|
308
457
|
LanguageDropdown,
|
|
309
458
|
{
|
|
@@ -321,10 +470,9 @@ function RdxHeader({
|
|
|
321
470
|
}
|
|
322
471
|
function HomePage({ project }) {
|
|
323
472
|
const { config } = project;
|
|
324
|
-
if (!config.homepage?.enabled) redirect(
|
|
473
|
+
if (!config.homepage?.enabled) redirect(getDocsHref4(project));
|
|
325
474
|
const homepage = config.homepage;
|
|
326
475
|
const CustomHome = homepage.component;
|
|
327
|
-
const BrandLogo = config.navbar?.logo ?? Logo;
|
|
328
476
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
329
477
|
/* @__PURE__ */ jsx(RdxHeader, { project }),
|
|
330
478
|
/* @__PURE__ */ jsx(
|
|
@@ -337,7 +485,13 @@ function HomePage({ project }) {
|
|
|
337
485
|
Home,
|
|
338
486
|
{
|
|
339
487
|
title: homepage.title ?? config.metadata.applicationName,
|
|
340
|
-
logo: /* @__PURE__ */ jsx(
|
|
488
|
+
logo: /* @__PURE__ */ jsx(
|
|
489
|
+
BrandLogo,
|
|
490
|
+
{
|
|
491
|
+
source: config.navbar?.logo,
|
|
492
|
+
className: "size-52 hover:scale-105 hover:rotate-1 transition-[scale,rotation] duration-1000"
|
|
493
|
+
}
|
|
494
|
+
),
|
|
341
495
|
description: homepage.description,
|
|
342
496
|
buttons: homepage.buttons
|
|
343
497
|
}
|
|
@@ -349,7 +503,6 @@ function HomePage({ project }) {
|
|
|
349
503
|
function NotFoundPage({ project }) {
|
|
350
504
|
if (project.localization) {
|
|
351
505
|
const { config, localization } = project;
|
|
352
|
-
const BrandLogo = config.navbar?.logo ?? Logo;
|
|
353
506
|
return /* @__PURE__ */ jsx(
|
|
354
507
|
LocalizedNotFound,
|
|
355
508
|
{
|
|
@@ -361,7 +514,7 @@ function NotFoundPage({ project }) {
|
|
|
361
514
|
siteTitle: config.metadata.applicationName,
|
|
362
515
|
github: config.navbar?.actions?.github,
|
|
363
516
|
showToggleMode: config.navbar?.actions?.showToggleMode,
|
|
364
|
-
logo: /* @__PURE__ */ jsx(BrandLogo, { className: "size-5" })
|
|
517
|
+
logo: /* @__PURE__ */ jsx(BrandLogo, { source: config.navbar?.logo, className: "size-5" })
|
|
365
518
|
}
|
|
366
519
|
}
|
|
367
520
|
);
|
|
@@ -376,7 +529,7 @@ async function DocsPage({
|
|
|
376
529
|
project
|
|
377
530
|
}) {
|
|
378
531
|
if (project.localization && !project.locale)
|
|
379
|
-
permanentRedirect(
|
|
532
|
+
permanentRedirect(getDocsHref4(project, project.sources[0], slug?.join("/")));
|
|
380
533
|
const messages = getMessages(project.config.lang);
|
|
381
534
|
const {
|
|
382
535
|
source,
|
|
@@ -386,7 +539,7 @@ async function DocsPage({
|
|
|
386
539
|
} = resolveDocsRoute2(project, slug);
|
|
387
540
|
if (source.redirectTo !== void 0)
|
|
388
541
|
permanentRedirect(
|
|
389
|
-
|
|
542
|
+
getDocsHref4(
|
|
390
543
|
project,
|
|
391
544
|
project.sources.find(
|
|
392
545
|
(entry) => entry.routePrefix === source.redirectTo
|
|
@@ -403,15 +556,16 @@ async function DocsPage({
|
|
|
403
556
|
] })
|
|
404
557
|
] });
|
|
405
558
|
if (!document) notFound2();
|
|
406
|
-
const fallback =
|
|
559
|
+
const fallback = isFallbackPage4(project, source, document.sourcePath);
|
|
560
|
+
const editHref = fallback ? void 0 : getEditPageHref(project, source, document.sourcePath);
|
|
407
561
|
const primaryLocale = (source.localization ?? project.localization)?.locales.find(
|
|
408
562
|
(locale) => locale.code === project.localization.defaultLocale
|
|
409
563
|
);
|
|
410
|
-
const originalProject = fallback && primaryLocale ?
|
|
564
|
+
const originalProject = fallback && primaryLocale ? getLocalizedProject3(project, primaryLocale.path) : project;
|
|
411
565
|
const contentSource = originalProject.sources.find(
|
|
412
566
|
(entry) => entry.id === source.id
|
|
413
567
|
);
|
|
414
|
-
const contentOptions =
|
|
568
|
+
const contentOptions = getSourceOptions5(originalProject, contentSource);
|
|
415
569
|
const contentCategories = fallback ? resolveDocsRoute2(originalProject, slug).categories : categories;
|
|
416
570
|
const contentLanguage = fallback ? primaryLocale.code : project.config.lang;
|
|
417
571
|
const { content } = await compileDocumentation(
|
|
@@ -426,18 +580,20 @@ async function DocsPage({
|
|
|
426
580
|
documents: contentCategories.flatMap((category2) => category2.pages)
|
|
427
581
|
}
|
|
428
582
|
);
|
|
429
|
-
const title = typeof document.frontmatter.title === "string" ? document.frontmatter.title : currentSlug;
|
|
430
583
|
const description = typeof document.frontmatter.description === "string" ? document.frontmatter.description : null;
|
|
431
|
-
const hrefFor = (pageSlug) =>
|
|
584
|
+
const hrefFor = (pageSlug) => getDocsHref4(project, source, pageSlug);
|
|
585
|
+
const markdownHref = fallback ? void 0 : getMarkdownHref(hrefFor(currentSlug));
|
|
432
586
|
const sidebarCategories = categories.map((category2) => ({
|
|
433
587
|
title: category2.title,
|
|
434
588
|
links: category2.pages.map((page) => ({
|
|
435
|
-
label: page.title,
|
|
589
|
+
label: page.navTitle ?? page.title,
|
|
590
|
+
highlighting: page.highlighting,
|
|
436
591
|
href: hrefFor(page.slug)
|
|
437
592
|
}))
|
|
438
593
|
}));
|
|
439
594
|
const pages = categories.flatMap((category2) => category2.pages);
|
|
440
595
|
const index = pages.findIndex((page) => page.slug === currentSlug);
|
|
596
|
+
const title = pages[index]?.title ?? currentSlug;
|
|
441
597
|
const previous = pages[index - 1];
|
|
442
598
|
const next = pages[index + 1];
|
|
443
599
|
const category = categories.find(
|
|
@@ -495,7 +651,7 @@ async function DocsPage({
|
|
|
495
651
|
Button,
|
|
496
652
|
{
|
|
497
653
|
variant: "link",
|
|
498
|
-
href:
|
|
654
|
+
href: getDocsHref4(
|
|
499
655
|
originalProject,
|
|
500
656
|
contentSource,
|
|
501
657
|
currentSlug
|
|
@@ -529,7 +685,10 @@ async function DocsPage({
|
|
|
529
685
|
/* @__PURE__ */ jsxs("header", { className: "mb-6", children: [
|
|
530
686
|
source.badge && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: source.badge === "Archived" ? messages.archivedVersion : source.badge }),
|
|
531
687
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-600 font-semibold uppercase block -mb-0.5", children: category?.title }),
|
|
532
|
-
/* @__PURE__ */
|
|
688
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex flex-wrap items-start gap-x-4 gap-y-2", children: [
|
|
689
|
+
/* @__PURE__ */ jsx("h1", { className: "min-w-0 max-w-full break-words text-4xl font-bold uppercase", children: title }),
|
|
690
|
+
markdownHref && /* @__PURE__ */ jsx(CopyPage, { href: markdownHref }, markdownHref)
|
|
691
|
+
] }),
|
|
533
692
|
description && /* @__PURE__ */ jsx("p", { className: "text-sm text-ring max-w-[726px]", children: description })
|
|
534
693
|
] }),
|
|
535
694
|
/* @__PURE__ */ jsx("div", { className: "h-full w-full flex-1 max-w-[960px]", children: content })
|
|
@@ -537,6 +696,7 @@ async function DocsPage({
|
|
|
537
696
|
}
|
|
538
697
|
),
|
|
539
698
|
/* @__PURE__ */ jsxs("footer", { className: "flex flex-col", children: [
|
|
699
|
+
editHref && /* @__PURE__ */ jsx(EditPageLink, { href: editHref, lang: project.config.lang }),
|
|
540
700
|
/* @__PURE__ */ jsxs("section", { className: "flex items-center justify-between", children: [
|
|
541
701
|
previous ? /* @__PURE__ */ jsx(
|
|
542
702
|
Button,
|
|
@@ -585,8 +745,13 @@ export {
|
|
|
585
745
|
NotFoundPage,
|
|
586
746
|
RdxLayout,
|
|
587
747
|
createRdxProject,
|
|
748
|
+
getDocumentMarkdownResponse,
|
|
588
749
|
getDocumentMetadata,
|
|
589
|
-
|
|
750
|
+
getLlmIndexResponse,
|
|
751
|
+
getLocalizedProject4 as getLocalizedProject,
|
|
752
|
+
getMarkdownHref,
|
|
753
|
+
getMarkdownPaths,
|
|
754
|
+
getMarkdownResponse,
|
|
590
755
|
getPageMetadata,
|
|
591
756
|
getProjectDocsPaths,
|
|
592
757
|
getRdxMetadata,
|
|
@@ -594,5 +759,7 @@ export {
|
|
|
594
759
|
getRdxSitemap,
|
|
595
760
|
getSearchResponse,
|
|
596
761
|
getSearchSources,
|
|
597
|
-
getSourceRobots
|
|
762
|
+
getSourceRobots,
|
|
763
|
+
markdownNotFound,
|
|
764
|
+
parseMarkdownPath
|
|
598
765
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexibase/rdx-next",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "The Next.js runtime for RDX documentation projects.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
"next-mdx-remote": "^6.0.0",
|
|
53
53
|
"remark-gfm": "^4",
|
|
54
54
|
"typescript": "6.0.3",
|
|
55
|
-
"@lexibase/rdx-
|
|
56
|
-
"@lexibase/rdx-
|
|
55
|
+
"@lexibase/rdx-types": "2.3.0",
|
|
56
|
+
"@lexibase/rdx-core": "3.0.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@lexibase/rdx-ui": "^3.
|
|
59
|
+
"@lexibase/rdx-ui": "^3.5.0",
|
|
60
60
|
"next": "^16.4.2",
|
|
61
61
|
"react": "^19.3.1",
|
|
62
62
|
"react-dom": "^19.3.1"
|
|
@@ -81,9 +81,9 @@
|
|
|
81
81
|
"next": "^16.4.2",
|
|
82
82
|
"react": "19.3.1",
|
|
83
83
|
"react-dom": "19.3.1",
|
|
84
|
-
"@lexibase/rdx-ui": "3.
|
|
85
|
-
"@rdx/
|
|
86
|
-
"@rdx/
|
|
84
|
+
"@lexibase/rdx-ui": "3.5.0",
|
|
85
|
+
"@rdx/eslint-config": "1.0.0",
|
|
86
|
+
"@rdx/typescript-config": "1.0.0"
|
|
87
87
|
},
|
|
88
88
|
"scripts": {
|
|
89
89
|
"dev": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --watch --external @lexibase/rdx-core --external @lexibase/rdx-types --external @lexibase/rdx-ui --external next --external react --external react-dom --external next-mdx-remote",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMarkdownPaths,
|
|
3
|
+
getMarkdownResponse,
|
|
4
|
+
} from '@lexibase/rdx-next/runtime'
|
|
5
|
+
import { getProject } from '../../../rdx-project'
|
|
6
|
+
|
|
7
|
+
export const dynamic = 'force-static'
|
|
8
|
+
export const dynamicParams = false
|
|
9
|
+
|
|
10
|
+
export async function generateStaticParams() {
|
|
11
|
+
return getMarkdownPaths(await getProject())
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function GET(
|
|
15
|
+
_request: Request,
|
|
16
|
+
{ params }: { params: Promise<{ path: string[] }> }
|
|
17
|
+
) {
|
|
18
|
+
return getMarkdownResponse(await getProject(), (await params).path)
|
|
19
|
+
}
|