@lexibase/rdx-next 5.2.0 → 6.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 +22 -3
- package/bin/homepage-translations.mjs +137 -0
- package/bin/locale-routes.mjs +9 -43
- package/dist/index.d.ts +1 -1
- package/dist/runtime/index.d.ts +12 -5
- package/dist/runtime/index.js +77 -4
- package/package.json +5 -5
- package/templates/runtime/app/globals.css +0 -1
- package/templates/runtime/app/page.tsx +10 -2
- package/templates/runtime/rdx-home.ts +2 -0
package/bin/cli.mjs
CHANGED
|
@@ -26,7 +26,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
26
26
|
templateDir ?? path.join(packageRoot, 'templates', 'runtime')
|
|
27
27
|
const runtimeDirectory = path.join(projectRoot, '.rdx')
|
|
28
28
|
|
|
29
|
-
async function prepareRuntime(project) {
|
|
29
|
+
async function prepareRuntime(project, homepageTranslations) {
|
|
30
30
|
await mkdir(runtimeDirectory, { recursive: true })
|
|
31
31
|
await preparePublicAssets(projectRoot, runtimeDirectory)
|
|
32
32
|
await cp(runtimeTemplate, runtimeDirectory, {
|
|
@@ -35,6 +35,11 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
35
35
|
})
|
|
36
36
|
await prepareProjectStyles(projectRoot, runtimeDirectory)
|
|
37
37
|
await prepareLocaleRoutes(project, runtimeDirectory, runtimeTemplate)
|
|
38
|
+
if (homepageTranslations) {
|
|
39
|
+
const { prepareHomepageTranslations } =
|
|
40
|
+
await import('./homepage-translations.mjs')
|
|
41
|
+
await prepareHomepageTranslations(runtimeDirectory, homepageTranslations)
|
|
42
|
+
}
|
|
38
43
|
// Resolve in Node before Next processes this file: UI may be transitive,
|
|
39
44
|
// and native Tailwind plugins must stay outside the Turbopack module graph.
|
|
40
45
|
const resolvePlugin = createRequire(import.meta.url)
|
|
@@ -140,6 +145,20 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
140
145
|
rootDir: projectRoot,
|
|
141
146
|
command,
|
|
142
147
|
})
|
|
148
|
+
let homepageTranslations
|
|
149
|
+
if (
|
|
150
|
+
project.config.homepage?.enabled &&
|
|
151
|
+
project.config.homepage.translations &&
|
|
152
|
+
(supportedCommands.has(command) ||
|
|
153
|
+
command === 'check' ||
|
|
154
|
+
command === 'prepare')
|
|
155
|
+
) {
|
|
156
|
+
const { readHomepageTranslations } =
|
|
157
|
+
await import('./homepage-translations.mjs')
|
|
158
|
+
homepageTranslations = await readHomepageTranslations(project, {
|
|
159
|
+
report: command === 'check' || command === 'build',
|
|
160
|
+
})
|
|
161
|
+
}
|
|
143
162
|
if (command === 'check' || command === 'build') {
|
|
144
163
|
const { checkDocumentation, formatDocumentationCheck } =
|
|
145
164
|
await import('@lexibase/rdx-core/check')
|
|
@@ -153,7 +172,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
153
172
|
if (command === 'check') return
|
|
154
173
|
}
|
|
155
174
|
if (command === 'prepare') {
|
|
156
|
-
await prepareRuntime(project)
|
|
175
|
+
await prepareRuntime(project, homepageTranslations)
|
|
157
176
|
console.log('RDX runtime prepared in .rdx/')
|
|
158
177
|
return
|
|
159
178
|
}
|
|
@@ -174,7 +193,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
174
193
|
return
|
|
175
194
|
}
|
|
176
195
|
|
|
177
|
-
await prepareRuntime(project)
|
|
196
|
+
await prepareRuntime(project, homepageTranslations)
|
|
178
197
|
const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
|
|
179
198
|
const nextCli = projectRequire.resolve('next/dist/bin/next')
|
|
180
199
|
const child = spawn(
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
const sourceFile = 'components/home.tsx'
|
|
5
|
+
const metadataKey = '$metadata'
|
|
6
|
+
|
|
7
|
+
function missingFile(error) {
|
|
8
|
+
return error.code === 'ENOENT' || error.code === 'ENOTDIR'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function readOptional(file) {
|
|
12
|
+
try {
|
|
13
|
+
return await readFile(file, 'utf8')
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (!missingFile(error)) throw error
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function sourcePhrases(rootDir) {
|
|
20
|
+
const source = await readOptional(path.join(rootDir, sourceFile))
|
|
21
|
+
if (source === undefined)
|
|
22
|
+
throw new Error(`Create ${sourceFile} to use homepage.translations.`)
|
|
23
|
+
const { default: ts } = await import('typescript')
|
|
24
|
+
const file = ts.createSourceFile(sourceFile, source, ts.ScriptTarget.Latest)
|
|
25
|
+
for (const statement of file.statements) {
|
|
26
|
+
if (
|
|
27
|
+
!ts.isExpressionStatement(statement) ||
|
|
28
|
+
!ts.isStringLiteral(statement.expression)
|
|
29
|
+
)
|
|
30
|
+
break
|
|
31
|
+
if (statement.expression.text === 'use client')
|
|
32
|
+
throw new Error(
|
|
33
|
+
`${sourceFile} must be a Server Component when homepage.translations is enabled. Move 'use client' into interactive child components.`
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
const phrases = new Set()
|
|
37
|
+
function visit(node) {
|
|
38
|
+
if (
|
|
39
|
+
ts.isCallExpression(node) &&
|
|
40
|
+
ts.isIdentifier(node.expression) &&
|
|
41
|
+
node.expression.text === 't' &&
|
|
42
|
+
node.arguments.length === 1 &&
|
|
43
|
+
ts.isStringLiteralLike(node.arguments[0])
|
|
44
|
+
)
|
|
45
|
+
phrases.add(node.arguments[0].text)
|
|
46
|
+
ts.forEachChild(node, visit)
|
|
47
|
+
}
|
|
48
|
+
visit(file)
|
|
49
|
+
return phrases
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function readHomepageTranslations(
|
|
53
|
+
project,
|
|
54
|
+
{ report = false } = {}
|
|
55
|
+
) {
|
|
56
|
+
const { rootDir, localization } = project
|
|
57
|
+
const phrases = await sourcePhrases(rootDir)
|
|
58
|
+
phrases.delete(metadataKey)
|
|
59
|
+
const catalogs = []
|
|
60
|
+
for (const locale of localization?.locales ?? []) {
|
|
61
|
+
if (!locale.folder) continue
|
|
62
|
+
const file = `locale/${locale.folder}/home.json`
|
|
63
|
+
const raw = await readOptional(path.join(rootDir, file))
|
|
64
|
+
let messages = {}
|
|
65
|
+
if (raw !== undefined) {
|
|
66
|
+
try {
|
|
67
|
+
const parsed = JSON.parse(raw)
|
|
68
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
69
|
+
throw new Error('Expected a JSON object.')
|
|
70
|
+
messages = parsed
|
|
71
|
+
catalogs.push({ file, locale: locale.path })
|
|
72
|
+
} catch {
|
|
73
|
+
console.warn(
|
|
74
|
+
`[RDX] ${file}: expected a JSON object of homepage phrases. Using the primary text.`
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!report) continue
|
|
79
|
+
for (const phrase of phrases) {
|
|
80
|
+
if (
|
|
81
|
+
!Object.hasOwn(messages, phrase) ||
|
|
82
|
+
typeof messages[phrase] !== 'string' ||
|
|
83
|
+
!messages[phrase].trim()
|
|
84
|
+
)
|
|
85
|
+
console.warn(
|
|
86
|
+
`[RDX] ${file}: missing translation for ${JSON.stringify(phrase)}`
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
for (const phrase of Object.keys(messages)) {
|
|
90
|
+
if (phrase !== metadataKey && !phrases.has(phrase))
|
|
91
|
+
console.warn(
|
|
92
|
+
`[RDX] ${file}: orphaned translation for ${JSON.stringify(phrase)}`
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return { catalogs, phrases }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function prepareHomepageTranslations(
|
|
100
|
+
runtime,
|
|
101
|
+
{ catalogs, phrases }
|
|
102
|
+
) {
|
|
103
|
+
const imports = catalogs.map(
|
|
104
|
+
({ file }, index) =>
|
|
105
|
+
`import messages${index} from ${JSON.stringify(`../${file}`)}`
|
|
106
|
+
)
|
|
107
|
+
const entries = catalogs.map(
|
|
108
|
+
({ locale }, index) => ` [${JSON.stringify(locale)}, messages${index}],`
|
|
109
|
+
)
|
|
110
|
+
await writeFile(
|
|
111
|
+
path.join(runtime, 'rdx-home.ts'),
|
|
112
|
+
`import translatedComponent from '../components/home'
|
|
113
|
+
${imports.join('\n')}
|
|
114
|
+
|
|
115
|
+
const catalogs = new Map<string, Record<string, unknown>>([
|
|
116
|
+
${entries.join('\n')}
|
|
117
|
+
])
|
|
118
|
+
|
|
119
|
+
const phrases: string[] = ${JSON.stringify([...phrases])}
|
|
120
|
+
|
|
121
|
+
export function getHomepageTranslation(locale?: string) {
|
|
122
|
+
return { translatedComponent, messages: locale ? catalogs.get(locale) : undefined }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function getHomepageSeo(locale?: string) {
|
|
126
|
+
const translatedLocales = new Set<string>()
|
|
127
|
+
for (const [path, catalog] of catalogs) {
|
|
128
|
+
if (phrases.some((phrase) => {
|
|
129
|
+
const text = Object.hasOwn(catalog, phrase) ? catalog[phrase] : undefined
|
|
130
|
+
return typeof text === 'string' && text.trim() && text.trim() !== phrase.trim()
|
|
131
|
+
})) translatedLocales.add(path)
|
|
132
|
+
}
|
|
133
|
+
return { translatedLocales, metadata: locale ? catalogs.get(locale)?.${metadataKey} : undefined }
|
|
134
|
+
}
|
|
135
|
+
`
|
|
136
|
+
)
|
|
137
|
+
}
|
package/bin/locale-routes.mjs
CHANGED
|
@@ -84,7 +84,7 @@ export async function prepareLocaleRoutes(project, runtime, template) {
|
|
|
84
84
|
await emit(
|
|
85
85
|
`app/(rdx-default)/${file}`,
|
|
86
86
|
text
|
|
87
|
-
.replace(/from '(\.\.\/[^']*rdx-project)'/g, "from '../$1'")
|
|
87
|
+
.replace(/from '(\.\.\/[^']*rdx-(?:home|project))'/g, "from '../$1'")
|
|
88
88
|
.replace("'./globals.css'", "'../globals.css'")
|
|
89
89
|
)
|
|
90
90
|
}
|
|
@@ -110,49 +110,16 @@ export default async function Layout({ children, params }: { children: React.Rea
|
|
|
110
110
|
}
|
|
111
111
|
`
|
|
112
112
|
)
|
|
113
|
-
const homeRoute = 'app/(rdx-locales)/[locale]/page.tsx'
|
|
114
|
-
const localizedHomes = []
|
|
115
|
-
if (project.config.homepage?.enabled) {
|
|
116
|
-
for (const locale of project.localization.locales) {
|
|
117
|
-
if (!locale.folder || locale.code === project.localization.defaultLocale)
|
|
118
|
-
continue
|
|
119
|
-
|
|
120
|
-
const file = path.join(
|
|
121
|
-
project.rootDir,
|
|
122
|
-
'locale',
|
|
123
|
-
locale.folder,
|
|
124
|
-
'home.tsx'
|
|
125
|
-
)
|
|
126
|
-
const exists = await stat(file).then(
|
|
127
|
-
(entry) => entry.isFile(),
|
|
128
|
-
(error) => {
|
|
129
|
-
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') return false
|
|
130
|
-
throw error
|
|
131
|
-
}
|
|
132
|
-
)
|
|
133
|
-
if (!exists) continue
|
|
134
|
-
|
|
135
|
-
// Literal imports let Next compile and trace project-owned components.
|
|
136
|
-
const specifier = path
|
|
137
|
-
.relative(path.dirname(path.join(runtime, homeRoute)), file)
|
|
138
|
-
.split(path.sep)
|
|
139
|
-
.join('/')
|
|
140
|
-
.slice(0, -'.tsx'.length)
|
|
141
|
-
localizedHomes.push(
|
|
142
|
-
` case ${JSON.stringify(locale.path)}: return (await import(${JSON.stringify(specifier)})).default`
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
113
|
await emit(
|
|
147
|
-
|
|
148
|
-
`import { HomePage, getLocalizedProject } from '${provider}'
|
|
114
|
+
'app/(rdx-locales)/[locale]/page.tsx',
|
|
115
|
+
`import { HomePage, getHomepageMetadata, getLocalizedProject } from '${provider}'
|
|
149
116
|
import { notFound, permanentRedirect } from 'next/navigation'
|
|
117
|
+
import { getHomepageSeo, getHomepageTranslation } from '../../../rdx-home'
|
|
150
118
|
import { getProject } from '../../../rdx-project'
|
|
151
|
-
async function
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
119
|
+
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
|
|
120
|
+
const project = await getProject()
|
|
121
|
+
const { locale } = await params
|
|
122
|
+
return getHomepageMetadata({ project, locale, ...getHomepageSeo(locale) })
|
|
156
123
|
}
|
|
157
124
|
export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
|
|
158
125
|
const project = await getProject()
|
|
@@ -160,8 +127,7 @@ export default async function Page({ params }: { params: Promise<{ locale: strin
|
|
|
160
127
|
const selected = project.localization?.locales.find(entry => entry.path === locale)
|
|
161
128
|
if (!project.config.homepage?.enabled || !selected) notFound()
|
|
162
129
|
if (selected.code === project.localization!.defaultLocale) permanentRedirect('/')
|
|
163
|
-
|
|
164
|
-
return <HomePage project={getLocalizedProject(project, locale)} component={component} />
|
|
130
|
+
return <HomePage project={getLocalizedProject(project, locale)} {...getHomepageTranslation(locale)} />
|
|
165
131
|
}
|
|
166
132
|
`
|
|
167
133
|
)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { defineConfig } from '@lexibase/rdx-core/config';
|
|
2
|
-
export { RDXConfig, RdxHomepage, RdxHomepageProps, RdxMetadata, RdxPlugin, RdxPluginContext, RdxRuntimeConfig } from '@lexibase/rdx-types';
|
|
2
|
+
export { RDXConfig, RdxHomepage, RdxHomepageProps, RdxMetadata, RdxPlugin, RdxPluginContext, RdxRuntimeConfig, RdxTranslatedHomepageProps } from '@lexibase/rdx-types';
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
import { RdxProject, RDXConfig, RdxContentSource, RdxDocPage } from '@lexibase/rdx-types';
|
|
2
|
+
import { ComponentType, ReactNode } from 'react';
|
|
3
|
+
import { RdxProject, RDXConfig, RdxContentSource, RdxDocPage, RdxTranslatedHomepageProps } from '@lexibase/rdx-types';
|
|
4
4
|
export { createRdxProject, getLocalizedProject, getProjectDocsPaths } from '@lexibase/rdx-core';
|
|
5
5
|
import { MetadataRoute, Metadata } from 'next';
|
|
6
6
|
|
|
@@ -32,6 +32,12 @@ declare function getMarkdownResponse(project: RdxProject, path: string[]): Respo
|
|
|
32
32
|
declare function markdownNotFound(): Response;
|
|
33
33
|
declare function getDocumentMarkdownResponse(project: RdxProject, source: RdxContentSource | undefined, slug: string, documentPath?: DocumentPath): Response;
|
|
34
34
|
|
|
35
|
+
declare function getHomepageMetadata({ project, locale, translatedLocales, metadata, }: {
|
|
36
|
+
project: RdxProject;
|
|
37
|
+
locale?: string;
|
|
38
|
+
translatedLocales?: ReadonlySet<string>;
|
|
39
|
+
metadata?: unknown;
|
|
40
|
+
}): Metadata;
|
|
35
41
|
/** Read metadata from the same content source and index used by the page. */
|
|
36
42
|
declare function getDocumentMetadata({ project, slug, }: {
|
|
37
43
|
project: RdxProject;
|
|
@@ -47,9 +53,10 @@ declare function RdxLayout({ children, config, bodyClassName, }: {
|
|
|
47
53
|
config: RDXConfig;
|
|
48
54
|
bodyClassName?: string;
|
|
49
55
|
}): react.JSX.Element;
|
|
50
|
-
declare function HomePage({ project,
|
|
56
|
+
declare function HomePage({ project, translatedComponent: TranslatedHome, messages, }: {
|
|
51
57
|
project: RdxProject;
|
|
52
|
-
|
|
58
|
+
translatedComponent?: ComponentType<RdxTranslatedHomepageProps>;
|
|
59
|
+
messages?: Record<string, unknown>;
|
|
53
60
|
}): react.JSX.Element;
|
|
54
61
|
declare function NotFoundPage({ project }: {
|
|
55
62
|
project: RdxProject;
|
|
@@ -59,4 +66,4 @@ declare function DocsPage({ slug, project, }: {
|
|
|
59
66
|
project: RdxProject;
|
|
60
67
|
}): Promise<react.JSX.Element>;
|
|
61
68
|
|
|
62
|
-
export { DocsPage, HomePage, NotFoundPage, RdxLayout, getDocumentMarkdownResponse, getDocumentMetadata, getLlmIndexResponse, getMarkdownHref, getMarkdownPaths, getMarkdownResponse, getPageMetadata, getRdxMetadata, getRdxRobots, getRdxSitemap, getSearchResponse, getSearchSources, getSourceRobots, markdownNotFound, parseMarkdownPath };
|
|
69
|
+
export { DocsPage, HomePage, NotFoundPage, RdxLayout, getDocumentMarkdownResponse, getDocumentMetadata, getHomepageMetadata, getLlmIndexResponse, getMarkdownHref, getMarkdownPaths, getMarkdownResponse, getPageMetadata, getRdxMetadata, getRdxRobots, getRdxSitemap, getSearchResponse, getSearchSources, getSourceRobots, markdownNotFound, parseMarkdownPath };
|
package/dist/runtime/index.js
CHANGED
|
@@ -318,6 +318,67 @@ import {
|
|
|
318
318
|
getSourceOptions as getSourceOptions4
|
|
319
319
|
} from "@lexibase/rdx-core";
|
|
320
320
|
import { notFound } from "next/navigation";
|
|
321
|
+
function getHomepageMetadata({
|
|
322
|
+
project,
|
|
323
|
+
locale,
|
|
324
|
+
translatedLocales,
|
|
325
|
+
metadata
|
|
326
|
+
}) {
|
|
327
|
+
const { config, localization } = project;
|
|
328
|
+
if (!config.homepage?.enabled || !localization) return {};
|
|
329
|
+
const selected = localization.locales.find((entry) => entry.path === locale);
|
|
330
|
+
if (locale && (!selected || selected.code === localization.defaultLocale))
|
|
331
|
+
return {};
|
|
332
|
+
const base = config.metadata.metadataBase;
|
|
333
|
+
const primaryUrl = base ? new URL("/", base).href : void 0;
|
|
334
|
+
if (locale && !translatedLocales?.has(locale)) {
|
|
335
|
+
if (config.homepage.component) return {};
|
|
336
|
+
return {
|
|
337
|
+
robots: { index: false, follow: true },
|
|
338
|
+
...primaryUrl ? { alternates: { canonical: primaryUrl } } : {}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
const url = base && new URL(locale ? `/${locale}` : "/", base).href;
|
|
342
|
+
const site = getRdxMetadata(config);
|
|
343
|
+
const fields = metadata && typeof metadata === "object" ? metadata : {};
|
|
344
|
+
const title = "title" in fields && typeof fields.title === "string" ? fields.title.trim() : "";
|
|
345
|
+
const description = "description" in fields && typeof fields.description === "string" ? fields.description.trim() : "";
|
|
346
|
+
const defaults = {
|
|
347
|
+
title: config.metadata.applicationName,
|
|
348
|
+
description: config.description
|
|
349
|
+
};
|
|
350
|
+
const social = {
|
|
351
|
+
...title ? { title: { absolute: title } } : {},
|
|
352
|
+
...description ? { description } : {}
|
|
353
|
+
};
|
|
354
|
+
return {
|
|
355
|
+
...social,
|
|
356
|
+
...site.openGraph || title || description ? {
|
|
357
|
+
openGraph: {
|
|
358
|
+
...defaults,
|
|
359
|
+
...site.openGraph,
|
|
360
|
+
...social,
|
|
361
|
+
...url ? { url } : {}
|
|
362
|
+
}
|
|
363
|
+
} : {},
|
|
364
|
+
...site.twitter || title || description ? { twitter: { ...defaults, ...site.twitter, ...social } } : {},
|
|
365
|
+
...base && url && primaryUrl ? {
|
|
366
|
+
alternates: {
|
|
367
|
+
canonical: url,
|
|
368
|
+
languages: {
|
|
369
|
+
[localization.defaultLocale]: primaryUrl,
|
|
370
|
+
"x-default": primaryUrl,
|
|
371
|
+
...Object.fromEntries(
|
|
372
|
+
localization.locales.filter((entry) => translatedLocales?.has(entry.path)).map((entry) => [
|
|
373
|
+
entry.code,
|
|
374
|
+
new URL(`/${entry.path}`, base).href
|
|
375
|
+
])
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} : {}
|
|
380
|
+
};
|
|
381
|
+
}
|
|
321
382
|
function getDocumentMetadata({
|
|
322
383
|
project,
|
|
323
384
|
slug
|
|
@@ -488,16 +549,17 @@ function RdxHeader({
|
|
|
488
549
|
}
|
|
489
550
|
function HomePage({
|
|
490
551
|
project,
|
|
491
|
-
|
|
552
|
+
translatedComponent: TranslatedHome,
|
|
553
|
+
messages
|
|
492
554
|
}) {
|
|
493
555
|
const { config } = project;
|
|
494
556
|
const docsHref = getDocsHref4(project);
|
|
495
557
|
if (!config.homepage?.enabled) redirect(docsHref);
|
|
496
558
|
const homepage = config.homepage;
|
|
497
|
-
const CustomHome =
|
|
559
|
+
const CustomHome = homepage.component;
|
|
498
560
|
const docsLabel = getMessages(config.lang).docs;
|
|
499
561
|
const source = project.sources[0];
|
|
500
|
-
const categories = CustomHome ? [] : getDocsIndex4(getSourceOptions5(project, source));
|
|
562
|
+
const categories = CustomHome || TranslatedHome ? [] : getDocsIndex4(getSourceOptions5(project, source));
|
|
501
563
|
const firstPage = categories[0]?.pages[0];
|
|
502
564
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
503
565
|
/* @__PURE__ */ jsx(RdxHeader, { project, onHomepage: true }),
|
|
@@ -507,7 +569,17 @@ function HomePage({
|
|
|
507
569
|
id: "rdx-main",
|
|
508
570
|
tabIndex: -1,
|
|
509
571
|
className: "relative flex-1 min-h-0 overflow-y-auto",
|
|
510
|
-
children: CustomHome ? /* @__PURE__ */ jsx(CustomHome, { lang: config.lang, docsHref }) : /* @__PURE__ */ jsx(
|
|
572
|
+
children: CustomHome ? /* @__PURE__ */ jsx(CustomHome, { lang: config.lang, docsHref }) : TranslatedHome ? /* @__PURE__ */ jsx(
|
|
573
|
+
TranslatedHome,
|
|
574
|
+
{
|
|
575
|
+
lang: config.lang,
|
|
576
|
+
docsHref,
|
|
577
|
+
t: (text2) => {
|
|
578
|
+
const translation = messages && Object.hasOwn(messages, text2) ? messages[text2] : void 0;
|
|
579
|
+
return typeof translation === "string" && translation.trim() ? translation : text2;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
) : /* @__PURE__ */ jsx(
|
|
511
583
|
Home,
|
|
512
584
|
{
|
|
513
585
|
title: homepage.title ?? config.metadata.applicationName,
|
|
@@ -810,6 +882,7 @@ export {
|
|
|
810
882
|
createRdxProject,
|
|
811
883
|
getDocumentMarkdownResponse,
|
|
812
884
|
getDocumentMetadata,
|
|
885
|
+
getHomepageMetadata,
|
|
813
886
|
getLlmIndexResponse,
|
|
814
887
|
getLocalizedProject4 as getLocalizedProject,
|
|
815
888
|
getMarkdownHref,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexibase/rdx-next",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "The Next.js runtime for RDX documentation projects.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"next-mdx-remote": "^6.0.0",
|
|
53
53
|
"remark-gfm": "^4",
|
|
54
54
|
"typescript": "6.0.3",
|
|
55
|
-
"@lexibase/rdx-core": "3.
|
|
56
|
-
"@lexibase/rdx-types": "2.
|
|
55
|
+
"@lexibase/rdx-core": "3.2.0",
|
|
56
|
+
"@lexibase/rdx-types": "2.6.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@lexibase/rdx-ui": "^3.5.0",
|
|
@@ -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.5.4",
|
|
85
84
|
"@rdx/eslint-config": "1.0.0",
|
|
86
|
-
"@rdx/typescript-config": "1.0.0"
|
|
85
|
+
"@rdx/typescript-config": "1.0.0",
|
|
86
|
+
"@lexibase/rdx-ui": "3.5.5"
|
|
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",
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import { HomePage } from '@lexibase/rdx-next/runtime'
|
|
1
|
+
import { getHomepageMetadata, HomePage } from '@lexibase/rdx-next/runtime'
|
|
2
2
|
|
|
3
|
+
import { getHomepageSeo, getHomepageTranslation } from '../rdx-home'
|
|
3
4
|
import { getProject } from '../rdx-project'
|
|
4
5
|
|
|
6
|
+
export async function generateMetadata() {
|
|
7
|
+
return getHomepageMetadata({
|
|
8
|
+
project: await getProject(),
|
|
9
|
+
...getHomepageSeo(),
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
export default async function Home() {
|
|
6
|
-
return <HomePage project={await getProject()} />
|
|
14
|
+
return <HomePage project={await getProject()} {...getHomepageTranslation()} />
|
|
7
15
|
}
|