@lexibase/rdx-next 1.0.0-beta.3 → 1.0.0-beta.5

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/rdx.mjs CHANGED
@@ -2,11 +2,14 @@
2
2
 
3
3
  import { spawn } from 'node:child_process'
4
4
  import { createRequire } from 'node:module'
5
- import { cp, mkdir } from 'node:fs/promises'
5
+ import { access, cp, mkdir } from 'node:fs/promises'
6
6
  import path from 'node:path'
7
7
  import { fileURLToPath } from 'node:url'
8
8
  import process from 'node:process'
9
9
 
10
+ import { createRdxProject } from '@lexibase/rdx-core/config'
11
+ import { createJiti } from 'jiti'
12
+
10
13
  const supportedCommands = new Set(['dev', 'build', 'start'])
11
14
  const command = process.argv[2]
12
15
  const commandArgs = process.argv.slice(3)
@@ -23,28 +26,86 @@ async function prepareRuntime() {
23
26
  await cp(runtimeTemplate, runtimeDirectory, { force: true, recursive: true })
24
27
  }
25
28
 
26
- if (command === 'prepare') {
27
- await prepareRuntime()
28
- console.log('RDX runtime prepared in .rdx/')
29
- process.exit(0)
30
- }
29
+ async function main() {
30
+ if (!command || command === 'help' || command === '--help') {
31
+ console.log('Usage: rdx <dev|build|start|prepare|plugin-command>')
32
+ console.log(
33
+ 'Plugin commands are registered through plugins in rdx.config.ts.'
34
+ )
35
+ return
36
+ }
31
37
 
32
- if (!command || !supportedCommands.has(command)) {
33
- console.error('Usage: rdx <dev|build|start|prepare>')
34
- process.exit(1)
35
- }
38
+ const configPath = path.join(projectRoot, 'rdx.config.ts')
39
+ try {
40
+ await access(configPath)
41
+ } catch {
42
+ throw new Error(
43
+ `Missing ${configPath}. Run rdx from the documentation project root.`
44
+ )
45
+ }
36
46
 
37
- await prepareRuntime()
47
+ const jiti = createJiti(import.meta.url, {
48
+ moduleCache: false,
49
+ fsCache: false,
50
+ })
51
+ let input
52
+ try {
53
+ input = await jiti.import(configPath, { default: true })
54
+ } catch (error) {
55
+ const hint =
56
+ error.code === 'MODULE_NOT_FOUND' || error.code === 'ERR_MODULE_NOT_FOUND'
57
+ ? ' If a configured plugin cannot be resolved, install its package in this project.'
58
+ : ''
59
+ throw new Error(`Could not load rdx.config.ts: ${error.message}${hint}`)
60
+ }
38
61
 
39
- const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
40
- const nextCli = projectRequire.resolve('next/dist/bin/next')
41
- const child = spawn(
42
- process.execPath,
43
- [nextCli, command, runtimeDirectory, ...commandArgs],
44
- { cwd: projectRoot, stdio: 'inherit' }
45
- )
62
+ const project = await createRdxProject(input, {
63
+ rootDir: projectRoot,
64
+ command,
65
+ })
66
+ if (command === 'prepare') {
67
+ await prepareRuntime()
68
+ console.log('RDX runtime prepared in .rdx/')
69
+ return
70
+ }
71
+ if (!supportedCommands.has(command)) {
72
+ const pluginCommand = project.commands.find(
73
+ (entry) => entry.name === command
74
+ )
75
+ if (!pluginCommand)
76
+ throw new Error(
77
+ `Unknown command "${command}". Available: dev, build, start, prepare${project.commands.map((entry) => `, ${entry.name}`).join('')}. Install and configure the plugin that provides this command.`
78
+ )
79
+ await pluginCommand.run({
80
+ rootDir: projectRoot,
81
+ config: project.config,
82
+ command,
83
+ args: commandArgs,
84
+ })
85
+ return
86
+ }
46
87
 
47
- child.on('exit', (code, signal) => {
48
- if (signal) process.kill(process.pid, signal)
49
- process.exit(code ?? 1)
50
- })
88
+ await prepareRuntime()
89
+ const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
90
+ const nextCli = projectRequire.resolve('next/dist/bin/next')
91
+ const child = spawn(
92
+ process.execPath,
93
+ [nextCli, command, runtimeDirectory, ...commandArgs],
94
+ { cwd: projectRoot, stdio: 'inherit' }
95
+ )
96
+ child.on('error', (error) => {
97
+ console.error(`[RDX] Could not start Next.js: ${error.message}`)
98
+ process.exitCode = 1
99
+ })
100
+ child.on('exit', (code, signal) => {
101
+ if (signal) process.kill(process.pid, signal)
102
+ process.exit(code ?? 1)
103
+ })
104
+ }
105
+
106
+ try {
107
+ await main()
108
+ } catch (error) {
109
+ console.error(`[RDX] ${error.message}`)
110
+ process.exitCode = 1
111
+ }
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
- export { RdxRuntimeConfig } from '@lexibase/rdx-types';
1
+ export { defineConfig } from '@lexibase/rdx-core/config';
2
+ export { RdxConfig, RdxHomepage, RdxPlugin, RdxPluginContext, RdxRuntimeConfig } from '@lexibase/rdx-types';
package/dist/index.js CHANGED
@@ -0,0 +1,5 @@
1
+ // src/index.ts
2
+ import { defineConfig } from "@lexibase/rdx-core/config";
3
+ export {
4
+ defineConfig
5
+ };
@@ -1,14 +1,18 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- export { getDocsPaths } from '@lexibase/rdx-core';
4
- import { RdxRuntimeConfig } from '@lexibase/rdx-types';
3
+ import { RdxProject, RdxRuntimeConfig } from '@lexibase/rdx-types';
4
+ export { createRdxProject, getProjectDocsPaths } from '@lexibase/rdx-core';
5
5
 
6
6
  declare function RdxLayout({ children, config, }: {
7
7
  children: ReactNode;
8
8
  config: RdxRuntimeConfig;
9
9
  }): react_jsx_runtime.JSX.Element;
10
- declare function DocsPage({ slug }: {
10
+ declare function HomePage({ project }: {
11
+ project: RdxProject;
12
+ }): react_jsx_runtime.JSX.Element;
13
+ declare function DocsPage({ slug, project, }: {
11
14
  slug?: string[];
15
+ project: RdxProject;
12
16
  }): Promise<react_jsx_runtime.JSX.Element>;
13
17
 
14
- export { DocsPage, RdxLayout };
18
+ export { DocsPage, HomePage, RdxLayout };
@@ -1,10 +1,15 @@
1
1
  // src/runtime/index.tsx
2
- import { getDocument, getDocsIndex, getDocsPaths } from "@lexibase/rdx-core";
3
- import { getDocsPaths as getDocsPaths2 } from "@lexibase/rdx-core";
2
+ import {
3
+ getDocument,
4
+ getDocsPaths,
5
+ getSourceOptions,
6
+ resolveDocsRoute
7
+ } from "@lexibase/rdx-core";
4
8
  import { compileMDX } from "next-mdx-remote/rsc";
5
9
  import Link from "next/link";
6
- import { notFound } from "next/navigation";
7
- import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { notFound, redirect } from "next/navigation";
11
+ import { createRdxProject, getProjectDocsPaths } from "@lexibase/rdx-core";
12
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
13
  var mdxComponents = {
9
14
  h1: (props) => /* @__PURE__ */ jsx("h1", { ...props }),
10
15
  h2: (props) => /* @__PURE__ */ jsx("h2", { ...props }),
@@ -33,10 +38,60 @@ function RdxLayout({
33
38
  children,
34
39
  config
35
40
  }) {
36
- const brand = config.navbar?.title || config.title;
37
- return /* @__PURE__ */ jsx("html", { lang: "en", children: /* @__PURE__ */ jsxs("body", { children: [
38
- /* @__PURE__ */ jsxs("header", { className: "rdx-header", children: [
39
- /* @__PURE__ */ jsx(Link, { className: "rdx-brand", href: "/docs", children: brand }),
41
+ return /* @__PURE__ */ jsx(
42
+ "html",
43
+ {
44
+ lang: config.lang ?? "en",
45
+ "data-theme": config.theme?.defaultTheme ?? "system",
46
+ children: /* @__PURE__ */ jsxs("body", { children: [
47
+ /* @__PURE__ */ jsx("a", { className: "rdx-skip-link", href: "#rdx-main", children: "Skip to content" }),
48
+ children
49
+ ] })
50
+ }
51
+ );
52
+ }
53
+ function RdxHeader({
54
+ project,
55
+ slug
56
+ }) {
57
+ const { config } = project;
58
+ const { source, slug: currentSlug } = resolveDocsRoute(project, slug);
59
+ const brand = config.navbar?.title ?? config.title;
60
+ return /* @__PURE__ */ jsxs("header", { className: "rdx-header", children: [
61
+ /* @__PURE__ */ jsx(
62
+ Link,
63
+ {
64
+ className: "rdx-brand",
65
+ href: config.homepage?.enabled ? "/" : "/docs",
66
+ "aria-label": config.title,
67
+ children: brand
68
+ }
69
+ ),
70
+ /* @__PURE__ */ jsxs("nav", { className: "rdx-header-actions", "aria-label": "Main navigation", children: [
71
+ config.homepage?.enabled && /* @__PURE__ */ jsx(Link, { href: "/", children: "Home" }),
72
+ /* @__PURE__ */ jsx(Link, { href: "/docs", children: "Documentation" }),
73
+ project.sources.length > 1 && /* @__PURE__ */ jsxs("details", { className: "rdx-version-menu", children: [
74
+ /* @__PURE__ */ jsxs("summary", { "aria-label": `Documentation version: ${source.label}`, children: [
75
+ source.label,
76
+ source.badge ? ` (${source.badge})` : ""
77
+ ] }),
78
+ /* @__PURE__ */ jsx("ul", { "aria-label": "Documentation versions", children: project.sources.map((edition) => {
79
+ const options = getSourceOptions(project, edition);
80
+ const destination = currentSlug && getDocument(currentSlug, options) ? currentSlug : getDocsPaths(options)[0];
81
+ const href = ["/docs", edition.routePrefix, destination].filter(Boolean).join("/");
82
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
83
+ Link,
84
+ {
85
+ href,
86
+ "aria-current": edition.id === source.id ? "true" : void 0,
87
+ children: [
88
+ edition.label,
89
+ edition.badge ? ` (${edition.badge})` : ""
90
+ ]
91
+ }
92
+ ) }, edition.id);
93
+ }) })
94
+ ] }),
40
95
  config.navbar?.actions?.github?.visible && config.navbar.actions.github.url && /* @__PURE__ */ jsx(
41
96
  "a",
42
97
  {
@@ -47,20 +102,53 @@ function RdxLayout({
47
102
  children: "GitHub"
48
103
  }
49
104
  )
50
- ] }),
51
- children
52
- ] }) });
105
+ ] })
106
+ ] });
53
107
  }
54
- async function DocsPage({ slug }) {
55
- const categories = getDocsIndex();
56
- const currentSlug = slug?.join("/") || getDocsPaths()[0];
108
+ function HomePage({ project }) {
109
+ const { config } = project;
110
+ if (!config.homepage?.enabled) redirect("/docs");
111
+ const homepage = config.homepage;
112
+ const buttons = homepage.buttons ?? [
113
+ { label: "Read the documentation", href: "/docs" }
114
+ ];
115
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
116
+ /* @__PURE__ */ jsx(RdxHeader, { project }),
117
+ /* @__PURE__ */ jsxs("main", { id: "rdx-main", tabIndex: -1, className: "rdx-homepage", children: [
118
+ /* @__PURE__ */ jsx("p", { className: "rdx-homepage-eyebrow", children: config.title }),
119
+ /* @__PURE__ */ jsx("h1", { children: homepage.title ?? config.title }),
120
+ /* @__PURE__ */ jsx("p", { className: "rdx-homepage-description", children: homepage.description ?? config.description }),
121
+ /* @__PURE__ */ jsx("div", { className: "rdx-homepage-buttons", children: buttons.map((button, index) => /* @__PURE__ */ jsx(
122
+ Link,
123
+ {
124
+ className: index === 0 ? "rdx-button rdx-button-primary" : "rdx-button",
125
+ href: button.href,
126
+ children: button.label
127
+ },
128
+ `${index}:${button.href}`
129
+ )) })
130
+ ] })
131
+ ] });
132
+ }
133
+ async function DocsPage({
134
+ slug,
135
+ project
136
+ }) {
137
+ const {
138
+ source,
139
+ slug: currentSlug,
140
+ document,
141
+ categories
142
+ } = resolveDocsRoute(project, slug);
57
143
  if (!currentSlug) {
58
- return /* @__PURE__ */ jsxs("main", { className: "rdx-empty-state", children: [
59
- /* @__PURE__ */ jsx("h1", { children: "Your documentation is ready." }),
60
- /* @__PURE__ */ jsx("p", { children: "Add an `.mdx` file inside `docs/` to create your first page." })
144
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
145
+ /* @__PURE__ */ jsx(RdxHeader, { project, slug }),
146
+ /* @__PURE__ */ jsxs("main", { id: "rdx-main", tabIndex: -1, className: "rdx-empty-state", children: [
147
+ /* @__PURE__ */ jsx("h1", { children: "Your documentation is ready." }),
148
+ /* @__PURE__ */ jsx("p", { children: "Add an `.mdx` file inside `docs/` to create your first page." })
149
+ ] })
61
150
  ] });
62
151
  }
63
- const document = getDocument(currentSlug);
64
152
  if (!document) notFound();
65
153
  const { content } = await compileMDX({
66
154
  source: document.content,
@@ -68,35 +156,44 @@ async function DocsPage({ slug }) {
68
156
  });
69
157
  const title = typeof document.frontmatter.title === "string" ? document.frontmatter.title : currentSlug;
70
158
  const description = typeof document.frontmatter.description === "string" ? document.frontmatter.description : null;
71
- return /* @__PURE__ */ jsxs("div", { className: "rdx-docs-layout", children: [
72
- /* @__PURE__ */ jsx("aside", { className: "rdx-sidebar", "aria-label": "Documentation navigation", children: categories.map((category) => /* @__PURE__ */ jsxs("section", { className: "rdx-sidebar-category", children: [
73
- /* @__PURE__ */ jsx("h2", { children: category.title }),
74
- /* @__PURE__ */ jsx("ul", { children: category.pages.map((page) => {
75
- const href = `/docs/${page.slug}`;
76
- const isCurrentPage = page.slug === currentSlug;
77
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
78
- Link,
79
- {
80
- "aria-current": isCurrentPage ? "page" : void 0,
81
- className: isCurrentPage ? "is-active" : void 0,
82
- href,
83
- children: page.title
84
- }
85
- ) }, page.slug);
86
- }) })
87
- ] }, category.id)) }),
88
- /* @__PURE__ */ jsxs("main", { className: "rdx-document", children: [
89
- /* @__PURE__ */ jsxs("header", { className: "rdx-document-header", children: [
90
- /* @__PURE__ */ jsx("p", { className: "rdx-breadcrumb", children: currentSlug }),
91
- /* @__PURE__ */ jsx("h1", { children: title }),
92
- description && /* @__PURE__ */ jsx("p", { className: "rdx-description", children: description })
93
- ] }),
94
- /* @__PURE__ */ jsx("article", { className: "rdx-mdx-content", children: content })
159
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
160
+ /* @__PURE__ */ jsx(RdxHeader, { project, slug }),
161
+ /* @__PURE__ */ jsxs("div", { className: "rdx-docs-layout", children: [
162
+ /* @__PURE__ */ jsx("aside", { className: "rdx-sidebar", "aria-label": "Documentation navigation", children: /* @__PURE__ */ jsxs("details", { className: "rdx-sidebar-menu", open: true, children: [
163
+ /* @__PURE__ */ jsx("summary", { children: "On this site" }),
164
+ /* @__PURE__ */ jsx("nav", { "aria-label": "Documentation pages", children: categories.map((category) => /* @__PURE__ */ jsxs("section", { className: "rdx-sidebar-category", children: [
165
+ /* @__PURE__ */ jsx("h2", { children: category.title }),
166
+ /* @__PURE__ */ jsx("ul", { children: category.pages.map((page) => {
167
+ const href = ["/docs", source.routePrefix, page.slug].filter(Boolean).join("/");
168
+ const isCurrentPage = page.slug === currentSlug;
169
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
170
+ Link,
171
+ {
172
+ "aria-current": isCurrentPage ? "page" : void 0,
173
+ className: isCurrentPage ? "is-active" : void 0,
174
+ href,
175
+ children: page.title
176
+ }
177
+ ) }, page.slug);
178
+ }) })
179
+ ] }, category.id)) })
180
+ ] }) }),
181
+ /* @__PURE__ */ jsxs("main", { id: "rdx-main", tabIndex: -1, className: "rdx-document", children: [
182
+ /* @__PURE__ */ jsxs("header", { className: "rdx-document-header", children: [
183
+ source.badge && /* @__PURE__ */ jsx("p", { className: "rdx-source-badge", children: source.badge }),
184
+ /* @__PURE__ */ jsx("p", { className: "rdx-breadcrumb", children: currentSlug }),
185
+ /* @__PURE__ */ jsx("h1", { children: title }),
186
+ description && /* @__PURE__ */ jsx("p", { className: "rdx-description", children: description })
187
+ ] }),
188
+ /* @__PURE__ */ jsx("article", { className: "rdx-mdx-content", children: content })
189
+ ] })
95
190
  ] })
96
191
  ] });
97
192
  }
98
193
  export {
99
194
  DocsPage,
195
+ HomePage,
100
196
  RdxLayout,
101
- getDocsPaths2 as getDocsPaths
197
+ createRdxProject,
198
+ getProjectDocsPaths
102
199
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexibase/rdx-next",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.5",
4
4
  "description": "The Next.js runtime for RDX documentation projects.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,9 +24,10 @@
24
24
  "README.md"
25
25
  ],
26
26
  "dependencies": {
27
+ "jiti": "^2.6.1",
27
28
  "next-mdx-remote": "^5.0.0",
28
- "@lexibase/rdx-core": "1.0.0-beta.1",
29
- "@lexibase/rdx-types": "1.0.0-beta.1"
29
+ "@lexibase/rdx-types": "1.0.0-beta.3",
30
+ "@lexibase/rdx-core": "1.0.0-beta.3"
30
31
  },
31
32
  "peerDependencies": {
32
33
  "next": "^15.5.0",
@@ -60,6 +61,8 @@
60
61
  "scripts": {
61
62
  "build": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --clean --external @lexibase/rdx-core --external @lexibase/rdx-types --external next --external react --external react-dom --external next-mdx-remote",
62
63
  "lint": "eslint . --max-warnings 0",
63
- "check-types": "tsc --noEmit"
64
+ "check-types": "tsc --noEmit",
65
+ "test": "node --test tests/*.test.mjs",
66
+ "test:runtime": "node --test tests/runtime.integration.mjs"
64
67
  }
65
68
  }
@@ -1,7 +1,11 @@
1
- import { DocsPage, getDocsPaths } from '@lexibase/rdx-next/runtime'
1
+ import { DocsPage, getProjectDocsPaths } from '@lexibase/rdx-next/runtime'
2
2
 
3
- export function generateStaticParams() {
4
- return getDocsPaths().map((slug) => ({ slug: slug.split('/') }))
3
+ import { getProject } from '../../../rdx-project'
4
+
5
+ export async function generateStaticParams() {
6
+ return getProjectDocsPaths(await getProject()).map((slug) => ({
7
+ slug: slug.split('/'),
8
+ }))
5
9
  }
6
10
 
7
11
  export default async function DocumentationPage({
@@ -11,5 +15,5 @@ export default async function DocumentationPage({
11
15
  }) {
12
16
  const { slug } = await params
13
17
 
14
- return <DocsPage slug={slug} />
18
+ return <DocsPage slug={slug} project={await getProject()} />
15
19
  }
@@ -8,7 +8,7 @@
8
8
  }
9
9
 
10
10
  @media (prefers-color-scheme: dark) {
11
- :root {
11
+ :root:not([data-theme='light']) {
12
12
  --rdx-background: #121212;
13
13
  --rdx-foreground: #f4f4f5;
14
14
  --rdx-muted: #a1a1aa;
@@ -18,6 +18,20 @@
18
18
  }
19
19
  }
20
20
 
21
+ :root[data-theme='dark'] {
22
+ --rdx-background: #121212;
23
+ --rdx-foreground: #f4f4f5;
24
+ --rdx-muted: #a1a1aa;
25
+ --rdx-border: #303033;
26
+ --rdx-accent: #202022;
27
+ --rdx-link: #7bb0ff;
28
+ }
29
+
30
+ .rdx-source-badge {
31
+ color: var(--rdx-muted);
32
+ font-size: 0.85rem;
33
+ }
34
+
21
35
  * {
22
36
  box-sizing: border-box;
23
37
  }
@@ -42,9 +56,137 @@ a {
42
56
  align-items: center;
43
57
  border-bottom: 1px solid var(--rdx-border);
44
58
  display: flex;
45
- height: 60px;
59
+ min-height: 64px;
60
+ gap: 16px;
61
+ flex-wrap: wrap;
46
62
  justify-content: space-between;
47
- padding: 0 24px;
63
+ padding: 12px 24px;
64
+ }
65
+
66
+ .rdx-header-actions {
67
+ align-items: center;
68
+ display: flex;
69
+ flex-wrap: wrap;
70
+ gap: 20px;
71
+ font-size: 0.9rem;
72
+ }
73
+
74
+ .rdx-header-actions a {
75
+ text-decoration: none;
76
+ }
77
+ .rdx-header-actions a:hover {
78
+ color: var(--rdx-link);
79
+ }
80
+ .rdx-brand {
81
+ overflow-wrap: anywhere;
82
+ }
83
+
84
+ :where(a, summary):focus-visible {
85
+ outline: 2px solid var(--rdx-link);
86
+ outline-offset: 4px;
87
+ border-radius: 4px;
88
+ }
89
+
90
+ .rdx-skip-link {
91
+ position: fixed;
92
+ top: -100px;
93
+ left: 16px;
94
+ z-index: 20;
95
+ padding: 12px;
96
+ background: var(--rdx-background);
97
+ }
98
+ .rdx-skip-link:focus {
99
+ top: 12px;
100
+ }
101
+
102
+ .rdx-version-menu {
103
+ position: relative;
104
+ }
105
+ .rdx-version-menu summary {
106
+ cursor: pointer;
107
+ padding: 8px 12px;
108
+ border: 1px solid var(--rdx-border);
109
+ border-radius: 8px;
110
+ background: var(--rdx-accent);
111
+ }
112
+ .rdx-version-menu ul {
113
+ position: absolute;
114
+ right: 0;
115
+ z-index: 10;
116
+ min-width: 180px;
117
+ max-width: calc(100vw - 48px);
118
+ max-height: 320px;
119
+ overflow: auto;
120
+ list-style: none;
121
+ margin: 8px 0 0;
122
+ padding: 6px;
123
+ border: 1px solid var(--rdx-border);
124
+ border-radius: 10px;
125
+ background: var(--rdx-background);
126
+ box-shadow: 0 8px 24px #0002;
127
+ }
128
+ .rdx-version-menu a {
129
+ display: block;
130
+ padding: 10px;
131
+ border-radius: 6px;
132
+ overflow-wrap: anywhere;
133
+ }
134
+ .rdx-version-menu a:hover,
135
+ .rdx-version-menu a[aria-current] {
136
+ background: var(--rdx-accent);
137
+ }
138
+ .rdx-sidebar-menu > summary {
139
+ display: list-item;
140
+ cursor: pointer;
141
+ font-weight: 600;
142
+ margin-bottom: 20px;
143
+ }
144
+
145
+ .rdx-homepage {
146
+ max-width: 1040px;
147
+ margin: 0 auto;
148
+ padding: clamp(72px, 16vh, 160px) 24px;
149
+ text-align: center;
150
+ }
151
+ .rdx-homepage-eyebrow {
152
+ color: var(--rdx-link);
153
+ font-weight: 600;
154
+ }
155
+ .rdx-homepage h1 {
156
+ font-size: clamp(2.5rem, 7vw, 5rem);
157
+ line-height: 1.05;
158
+ letter-spacing: -0.05em;
159
+ margin: 24px 0;
160
+ overflow-wrap: anywhere;
161
+ }
162
+ .rdx-homepage-description {
163
+ color: var(--rdx-muted);
164
+ font-size: 1.2rem;
165
+ line-height: 1.7;
166
+ max-width: 640px;
167
+ margin: 0 auto;
168
+ }
169
+ .rdx-homepage-buttons {
170
+ display: flex;
171
+ flex-wrap: wrap;
172
+ gap: 12px;
173
+ justify-content: center;
174
+ margin-top: 32px;
175
+ }
176
+ .rdx-button {
177
+ border: 1px solid var(--rdx-border);
178
+ border-radius: 8px;
179
+ padding: 14px 20px;
180
+ text-decoration: none;
181
+ font-weight: 600;
182
+ }
183
+ .rdx-button-primary {
184
+ background: var(--rdx-foreground);
185
+ color: var(--rdx-background);
186
+ }
187
+ .rdx-button:hover {
188
+ outline: 2px solid var(--rdx-link);
189
+ outline-offset: 2px;
48
190
  }
49
191
 
50
192
  .rdx-brand {
@@ -62,7 +204,7 @@ a {
62
204
  .rdx-docs-layout {
63
205
  display: grid;
64
206
  grid-template-columns: minmax(190px, 250px) minmax(0, 1fr);
65
- min-height: calc(100vh - 60px);
207
+ min-height: calc(100vh - 64px);
66
208
  }
67
209
 
68
210
  .rdx-sidebar {
@@ -198,6 +340,19 @@ a {
198
340
  }
199
341
 
200
342
  @media (max-width: 720px) {
343
+ .rdx-header {
344
+ padding: 12px 20px;
345
+ }
346
+ .rdx-header-actions {
347
+ gap: 12px;
348
+ }
349
+ .rdx-sidebar-menu > summary {
350
+ display: list-item;
351
+ padding: 4px 0;
352
+ }
353
+ .rdx-sidebar-menu[open] > summary {
354
+ margin-bottom: 20px;
355
+ }
201
356
  .rdx-docs-layout {
202
357
  display: block;
203
358
  }
@@ -2,20 +2,21 @@ import type { Metadata } from 'next'
2
2
 
3
3
  import { RdxLayout } from '@lexibase/rdx-next/runtime'
4
4
 
5
- import config from '../../rdx.config'
5
+ import { getProject } from '../rdx-project'
6
6
 
7
7
  import './globals.css'
8
8
 
9
- export const metadata: Metadata = {
10
- title: {
11
- default: config.title,
12
- template: `%s | ${config.title}`,
13
- },
14
- description: config.description,
9
+ export async function generateMetadata(): Promise<Metadata> {
10
+ const { config } = await getProject()
11
+ return {
12
+ title: { default: config.title, template: `%s | ${config.title}` },
13
+ description: config.description,
14
+ }
15
15
  }
16
16
 
17
- export default function RootLayout({
17
+ export default async function RootLayout({
18
18
  children,
19
19
  }: Readonly<{ children: React.ReactNode }>) {
20
+ const { config } = await getProject()
20
21
  return <RdxLayout config={config}>{children}</RdxLayout>
21
22
  }
@@ -1,5 +1,7 @@
1
- import { redirect } from 'next/navigation'
1
+ import { HomePage } from '@lexibase/rdx-next/runtime'
2
2
 
3
- export default function Home() {
4
- redirect('/docs')
3
+ import { getProject } from '../rdx-project'
4
+
5
+ export default async function Home() {
6
+ return <HomePage project={await getProject()} />
5
7
  }
@@ -0,0 +1,7 @@
1
+ import { createRdxProject } from '@lexibase/rdx-next/runtime'
2
+
3
+ import config from '../rdx.config'
4
+
5
+ export function getProject() {
6
+ return createRdxProject(config)
7
+ }