Migrate docs to Nextra 4 (App Router), Next 16, React 19

Upgrade to the latest major versions across the stack. Nextra 4 drops the Pages Router, so this is a full App Router migration: - theme.config.tsx -> config moved into app/layout.jsx (Navbar/Footer props) - add app/[[...mdxPath]]/page.jsx catch-all route and mdx-components.js - pages/*.mdx -> content/ (cli.mdx -> content/cli/index.mdx, asIndexPage) - add _meta.js sidebar ordering; remove pages/_app.jsx - favicon.ico moved into app/; pagefind search (postbuild + gitignore) Pin zod to 4.1.12 via pnpm.overrides: nextra-theme-docs@4.6.1 strips `children` before validating a schema that still requires it, which throws on zod 4.4.x's stricter z.custom() handling and 500s every page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Seto Elkahfi committed Jun 21, 2026 at 14:27 UTC 24b4eb1bcb819c13aa75f3d9d6327806fe75bdee
10 files changed +140
app/[[...mdxPath]]/page.jsx new
+27
@@ -0,0 +1,27 @@
1 +import { generateStaticParamsFor, importPage } from 'nextra/pages'
2 +import { useMDXComponents as getMDXComponents } from '../../mdx-components'
3 +
4 +export const generateStaticParams = generateStaticParamsFor('mdxPath')
5 +
6 +export async function generateMetadata(props) {
7 + const params = await props.params
8 + const { metadata } = await importPage(params.mdxPath)
9 + return metadata
10 +}
11 +
12 +const Wrapper = getMDXComponents().wrapper
13 +
14 +export default async function Page(props) {
15 + const params = await props.params
16 + const {
17 + default: MDXContent,
18 + toc,
19 + metadata,
20 + sourceCode
21 + } = await importPage(params.mdxPath)
22 + return (
23 + <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>
24 + <MDXContent {...props} params={params} />
25 + </Wrapper>
26 + )
27 +}
app/favicon.ico
Binary files /dev/null and b/app/favicon.ico differ
app/layout.jsx new
+57
@@ -0,0 +1,57 @@
1 +import { Footer, Layout, Navbar } from 'nextra-theme-docs'
2 +import { Head } from 'nextra/components'
3 +import { getPageMap } from 'nextra/page-map'
4 +import 'nextra-theme-docs/style.css'
5 +
6 +export const metadata = {
7 + metadataBase: new URL('https://docs.smbcloud.xyz'),
8 + title: {
9 + default: 'smbCloud Documentation',
10 + template: '%s – smbCloud Documentation'
11 + },
12 + description: 'smbCloud Documentation',
13 + applicationName: 'smbCloud Documentation',
14 + openGraph: {
15 + title: 'smbCloud Documentation',
16 + description: 'smbCloud Documentation',
17 + url: 'https://docs.smbcloud.xyz',
18 + siteName: 'smbCloud Documentation'
19 + }
20 +}
21 +
22 +const navbar = (
23 + <Navbar
24 + logo={<span>smbCloud Documentation</span>}
25 + projectLink="https://github.com/smbcloudXYZ"
26 + />
27 +)
28 +
29 +const footer = (
30 + <Footer>
31 + MIT {new Date().getFullYear()} ©{' '}
32 + <a href="https://docs.smbcloud.xyz" target="_blank" rel="noreferrer">
33 + smbCloud Documentation
34 + </a>
35 + </Footer>
36 +)
37 +
38 +export default async function RootLayout({ children }) {
39 + const pageMap = await getPageMap()
40 + return (
41 + <html lang="en" dir="ltr" suppressHydrationWarning>
42 + <Head />
43 + <body>
44 + <Layout
45 + navbar={navbar}
46 + footer={footer}
47 + pageMap={pageMap}
48 + docsRepositoryBase="https://github.com/smbcloudXYZ/smbcloud-docs/tree/main"
49 + editLink="Edit this page on GitHub"
50 + sidebar={{ defaultMenuCollapseLevel: 1 }}
51 + >
52 + {children}
53 + </Layout>
54 + </body>
55 + </html>
56 + )
57 +}
content/_meta.js new
+5
@@ -0,0 +1,5 @@
1 +export default {
2 + index: 'Introduction',
3 + cli: 'CLI',
4 + about: 'About'
5 +}
content/about.mdx new
+3
@@ -0,0 +1,3 @@
1 +# About
2 +
3 +This is the documentation page for smbCloud, the unified cloud platform for modern app deployment.
\ No newline at end of file
content/cli/_meta.js new
+3
@@ -0,0 +1,3 @@
1 +export default {
2 + setup: 'Setup'
3 +}
content/cli/index.mdx new
+7
@@ -0,0 +1,7 @@
1 +---
2 +asIndexPage: true
3 +---
4 +
5 +# CLI
6 +
7 +We use CLI program to interact with smbCloud resources.
\ No newline at end of file
content/cli/setup.mdx new
+23
@@ -0,0 +1,23 @@
1 +# Setup
2 +
3 +Our CLI interface is build with Rust and published on [Crates.io](https://crates.io/crates/smbcloud-cli).
4 +
5 +1. Setup your [Rust](https://www.rust-lang.org/tools/install).
6 +2. Install it globally with cargo: `cargo install smbcloud-cli`.
7 +3. Run `smb` command in your teminal to check your installation. You should get something like this:
8 +
9 +```
10 +╰─➤ smb
11 +Command line tool for creating and managing smbCloud resources.
12 +
13 +Usage: smb [OPTIONS] <COMMAND>
14 +
15 +Commands:
16 + login Login to your account. To create an account, visit https://smbcloud.xyz
17 + help Print this message or the help of the given subcommand(s)
18 +
19 +Options:
20 + -l, --log-level <LOG_LEVEL> Log level: trace, debug, info, warn, error, off
21 + -h, --help Print help
22 + -V, --version Print version
23 +```
\ No newline at end of file
content/index.mdx new
+7
@@ -0,0 +1,7 @@
1 +# smbCloud Documentation
2 +
3 +Find technical documentation for smbCloud services, SDKs and toolkits, use cases, scenarios, and tasks. Browse user guides, developer guides, tutorials, and API references.
4 +
5 +## What is smbCloud?
6 +
7 +A **simple**, **powerful** and **flexible** cloud platform for the next generation web.
mdx-components.js new
+8
@@ -0,0 +1,8 @@
1 +import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'
2 +
3 +const docsComponents = getDocsMDXComponents()
4 +
5 +export const useMDXComponents = components => ({
6 + ...docsComponents,
7 + ...components
8 +})