Showing preview only (1,765K chars total). Download the full file or copy to clipboard to get everything.
Repository: shuding/nextra
Branch: main
Commit: 81c29fd31b5a
Files: 652
Total size: 1.6 MB
Directory structure:
gitextract_ikx05y15/
├── .changeset/
│ └── config.json
├── .editorconfig
├── .github/
│ ├── CODE_OF_CONDUCT.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── workflows/
│ ├── lint.yml
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .node-version
├── .npmrc
├── .prettierignore
├── LICENSE
├── README.md
├── docs/
│ ├── app/
│ │ ├── _components/
│ │ │ ├── features/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── style.module.css
│ │ │ │ └── themes-animation.tsx
│ │ │ ├── framer-motion.ts
│ │ │ ├── i18n-demo.tsx
│ │ │ └── overview-page.tsx
│ │ ├── _meta.global.tsx
│ │ ├── about/
│ │ │ └── page.mdx
│ │ ├── api/
│ │ │ ├── [name]/
│ │ │ │ └── page.tsx
│ │ │ └── page.mdx
│ │ ├── blog/
│ │ │ └── page.mdx
│ │ ├── docs/
│ │ │ ├── advanced/
│ │ │ │ ├── customize-the-cascade-layers/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── latex/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── mermaid/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── npm2yarn/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── page.mdx
│ │ │ │ ├── remote/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── table/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── tailwind-css/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── twoslash/
│ │ │ │ │ └── page.mdx
│ │ │ │ └── typescript/
│ │ │ │ └── page.mdx
│ │ │ ├── blog-theme/
│ │ │ │ ├── get-posts-and-tags/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── page.mdx
│ │ │ │ ├── posts/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── rss/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── start/
│ │ │ │ │ └── page.mdx
│ │ │ │ └── tags/
│ │ │ │ └── page.mdx
│ │ │ ├── built-ins/
│ │ │ │ ├── [name]/
│ │ │ │ │ └── page.tsx
│ │ │ │ └── page.mdx
│ │ │ ├── custom-theme/
│ │ │ │ ├── old.mdx
│ │ │ │ └── page.mdx
│ │ │ ├── docs-theme/
│ │ │ │ ├── api/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── built-ins/
│ │ │ │ │ ├── footer/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ ├── layout/
│ │ │ │ │ │ ├── old.mdx
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ ├── navbar/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ ├── not-found/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── page.mdx
│ │ │ │ └── start/
│ │ │ │ └── page.mdx
│ │ │ ├── file-conventions/
│ │ │ │ ├── content-directory/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── mdx-components-file/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── meta-file/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── page-file/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── page.mdx
│ │ │ │ └── src-directory/
│ │ │ │ └── page.mdx
│ │ │ ├── guide/
│ │ │ │ ├── custom-css/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── github-alert-syntax/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── i18n/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── image/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── link/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── markdown/
│ │ │ │ │ ├── _counter.tsx
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── page.mdx
│ │ │ │ ├── search/
│ │ │ │ │ ├── ai/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── ssg/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── static-exports/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── syntax-highlighting/
│ │ │ │ │ ├── _dynamic-code.tsx
│ │ │ │ │ └── page.mdx
│ │ │ │ └── turbopack/
│ │ │ │ └── page.mdx
│ │ │ └── page.mdx
│ │ ├── env.d.ts
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── not-found.ts
│ │ ├── og/
│ │ │ ├── Inter-SemiBold.otf
│ │ │ └── route.tsx
│ │ ├── page.css
│ │ ├── page.module.css
│ │ ├── page.tsx
│ │ ├── showcase/
│ │ │ └── page.mdx
│ │ └── sponsors/
│ │ └── page.mdx
│ ├── components/
│ │ ├── _slider.tsx
│ │ ├── _table/
│ │ │ ├── index.tsx
│ │ │ └── style.module.css
│ │ ├── content-and-app-file-tree.tsx
│ │ ├── example-code.tsx
│ │ ├── example-tsdoc.mdx
│ │ ├── generate-api-reference.ts
│ │ ├── get-page-map.ts
│ │ ├── icons/
│ │ │ └── index.ts
│ │ ├── inkeep-chat-button.tsx
│ │ ├── install-nextra-theme.mdx
│ │ ├── playground-demo.tsx
│ │ ├── ready-to-go.mdx
│ │ ├── shadow.jsx
│ │ ├── toggle-visibility-section.tsx
│ │ └── video.tsx
│ ├── mdx-components.tsx
│ ├── next-sitemap.config.js
│ ├── next.config.ts
│ ├── package.json
│ ├── postcss.config.mjs
│ ├── tsconfig.json
│ └── vercel.json
├── examples/
│ ├── blog/
│ │ ├── app/
│ │ │ ├── _meta.global.js
│ │ │ ├── layout.jsx
│ │ │ ├── page.mdx
│ │ │ ├── posts/
│ │ │ │ ├── (with-comments)/
│ │ │ │ │ ├── aaron-swartz-a-programmable-web/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ ├── code-blocks/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ ├── draft/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ ├── layout.jsx
│ │ │ │ │ ├── lists/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ ├── nextra-components/
│ │ │ │ │ │ └── page.mdx
│ │ │ │ │ └── table/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── get-posts.js
│ │ │ │ └── page.jsx
│ │ │ ├── rss.xml/
│ │ │ │ └── route.js
│ │ │ └── tags/
│ │ │ └── [tag]/
│ │ │ └── page.jsx
│ │ ├── mdx-components.jsx
│ │ ├── next.config.js
│ │ └── package.json
│ ├── custom-theme/
│ │ ├── app/
│ │ │ ├── _components/
│ │ │ │ ├── footer.tsx
│ │ │ │ ├── navbar.tsx
│ │ │ │ ├── nextra-theme.tsx
│ │ │ │ ├── sidebar.tsx
│ │ │ │ └── toc.tsx
│ │ │ ├── _meta.global.ts
│ │ │ ├── docs/
│ │ │ │ ├── nested-level/
│ │ │ │ │ └── bar/
│ │ │ │ │ └── page.mdx
│ │ │ │ ├── one-level/
│ │ │ │ │ └── page.mdx
│ │ │ │ └── page.mdx
│ │ │ ├── layout.tsx
│ │ │ └── page.mdx
│ │ ├── mdx-components.jsx
│ │ ├── next.config.ts
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── .gitkeep
│ │ └── tsconfig.json
│ ├── docs/
│ │ ├── mdx-components.js
│ │ ├── next.config.mjs
│ │ ├── package.json
│ │ └── src/
│ │ ├── app/
│ │ │ ├── _ignored/
│ │ │ │ ├── _meta.js
│ │ │ │ └── page.mdx
│ │ │ ├── _meta.js
│ │ │ ├── blog/
│ │ │ │ └── page.jsx
│ │ │ ├── docs/
│ │ │ │ └── [[...mdxPath]]/
│ │ │ │ └── page.jsx
│ │ │ ├── layout.jsx
│ │ │ ├── page.jsx
│ │ │ └── showcase/
│ │ │ └── (overview)/
│ │ │ └── page.jsx
│ │ └── content/
│ │ ├── _meta.js
│ │ ├── advanced/
│ │ │ └── code-highlighting.mdx
│ │ ├── features/
│ │ │ ├── _meta.js
│ │ │ ├── i18n.mdx
│ │ │ ├── image.mdx
│ │ │ ├── latex.mdx
│ │ │ ├── mdx.mdx
│ │ │ ├── ssg.mdx
│ │ │ └── themes.mdx
│ │ ├── get-started.mdx
│ │ ├── index.mdx
│ │ ├── mermaid.mdx
│ │ ├── page.mdx
│ │ └── themes/
│ │ ├── _meta.js
│ │ ├── blog/
│ │ │ ├── _meta.js
│ │ │ └── index.mdx
│ │ └── docs/
│ │ ├── _meta.js
│ │ ├── bleed.mdx
│ │ ├── callout.mdx
│ │ ├── configuration.mdx
│ │ ├── index.mdx
│ │ └── tabs.mdx
│ └── swr-site/
│ ├── README.md
│ ├── app/
│ │ ├── [lang]/
│ │ │ ├── [[...mdxPath]]/
│ │ │ │ └── page.tsx
│ │ │ ├── graphql-eslint/
│ │ │ │ └── [[...slug]]/
│ │ │ │ └── page.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── not-found.ts
│ │ │ ├── remote/
│ │ │ │ └── graphql-yoga/
│ │ │ │ └── [[...slug]]/
│ │ │ │ └── page.tsx
│ │ │ └── styles.css
│ │ ├── _components/
│ │ │ ├── authors.tsx
│ │ │ ├── blog.tsx
│ │ │ ├── example-dynamic-markdown-import.tsx
│ │ │ ├── external.mdx
│ │ │ ├── features.css
│ │ │ ├── features.tsx
│ │ │ └── video.tsx
│ │ ├── _dictionaries/
│ │ │ ├── en.ts
│ │ │ ├── es.ts
│ │ │ ├── get-dictionary.ts
│ │ │ ├── i18n-config.ts
│ │ │ └── ru.ts
│ │ ├── _icons/
│ │ │ └── index.ts
│ │ ├── env.d.ts
│ │ └── manifest.ts
│ ├── content/
│ │ ├── en/
│ │ │ ├── _meta.ts
│ │ │ ├── about/
│ │ │ │ ├── _meta.ts
│ │ │ │ ├── a-page.mdx
│ │ │ │ ├── acknowledgement.mdx
│ │ │ │ └── team.mdx
│ │ │ ├── blog/
│ │ │ │ └── swr-v1.mdx
│ │ │ ├── blog.mdx
│ │ │ ├── docs/
│ │ │ │ ├── _meta.tsx
│ │ │ │ ├── advanced/
│ │ │ │ │ ├── _meta.tsx
│ │ │ │ │ ├── cache.mdx
│ │ │ │ │ ├── code-highlighting.mdx
│ │ │ │ │ ├── dynamic-markdown-import.mdx
│ │ │ │ │ ├── file-name.with.DOTS.mdx
│ │ │ │ │ ├── images.mdx
│ │ │ │ │ ├── markdown-import.mdx
│ │ │ │ │ ├── more/
│ │ │ │ │ │ ├── loooooooooooooooooooong-title.mdx
│ │ │ │ │ │ └── tree/
│ │ │ │ │ │ ├── one.mdx
│ │ │ │ │ │ ├── three.mdx
│ │ │ │ │ │ └── two.mdx
│ │ │ │ │ ├── performance.mdx
│ │ │ │ │ ├── react-native.mdx
│ │ │ │ │ └── scrollbar-x.mdx
│ │ │ │ ├── advanced.mdx
│ │ │ │ ├── arguments.mdx
│ │ │ │ ├── callout.mdx
│ │ │ │ ├── change-log.mdx
│ │ │ │ ├── code-block-without-language.mdx
│ │ │ │ ├── conditional-fetching.md
│ │ │ │ ├── custom-header-ids.mdx
│ │ │ │ ├── data-fetching.mdx
│ │ │ │ ├── error-handling.mdx
│ │ │ │ ├── getting-started.mdx
│ │ │ │ ├── global-configuration.md
│ │ │ │ ├── middleware.mdx
│ │ │ │ ├── mutation.md
│ │ │ │ ├── options.mdx
│ │ │ │ ├── pagination.mdx
│ │ │ │ ├── prefetching.md
│ │ │ │ ├── revalidation.mdx
│ │ │ │ ├── suspense.mdx
│ │ │ │ ├── typescript.mdx
│ │ │ │ ├── understanding.mdx
│ │ │ │ ├── with-nextjs.mdx
│ │ │ │ └── wrap-toc-items.mdx
│ │ │ ├── examples/
│ │ │ │ ├── _meta.ts
│ │ │ │ ├── auth.mdx
│ │ │ │ ├── basic.mdx
│ │ │ │ ├── error-handling.mdx
│ │ │ │ ├── full.mdx
│ │ │ │ ├── infinite-loading.mdx
│ │ │ │ └── ssr.mdx
│ │ │ ├── foo.md
│ │ │ ├── index.mdx
│ │ │ └── test.md
│ │ ├── es/
│ │ │ ├── _meta.ts
│ │ │ ├── docs/
│ │ │ │ ├── _meta.ts
│ │ │ │ ├── advanced/
│ │ │ │ │ ├── _meta.ts
│ │ │ │ │ ├── file-name.with.DOTS.mdx
│ │ │ │ │ └── performance.mdx
│ │ │ │ ├── arguments.mdx
│ │ │ │ ├── change-log.mdx
│ │ │ │ ├── conditional-fetching.md
│ │ │ │ ├── data-fetching.mdx
│ │ │ │ ├── error-handling.mdx
│ │ │ │ ├── getting-started.mdx
│ │ │ │ ├── global-configuration.md
│ │ │ │ ├── mutation.md
│ │ │ │ ├── options.mdx
│ │ │ │ ├── pagination.mdx
│ │ │ │ ├── prefetching.md
│ │ │ │ ├── revalidation.mdx
│ │ │ │ ├── suspense.mdx
│ │ │ │ ├── understanding.mdx
│ │ │ │ ├── with-nextjs.mdx
│ │ │ │ └── wrap-toc-items.mdx
│ │ │ ├── examples/
│ │ │ │ ├── _meta.ts
│ │ │ │ ├── auth.mdx
│ │ │ │ ├── basic.mdx
│ │ │ │ ├── error-handling.mdx
│ │ │ │ └── infinite-loading.mdx
│ │ │ └── index.mdx
│ │ └── ru/
│ │ ├── _meta.ts
│ │ ├── blog/
│ │ │ └── swr-v1.mdx
│ │ ├── blog.mdx
│ │ ├── docs/
│ │ │ ├── _meta.ts
│ │ │ ├── advanced/
│ │ │ │ ├── _meta.ts
│ │ │ │ ├── cache.mdx
│ │ │ │ ├── file-name.with.DOTS.mdx
│ │ │ │ ├── performance.mdx
│ │ │ │ └── react-native.mdx
│ │ │ ├── arguments.mdx
│ │ │ ├── change-log.mdx
│ │ │ ├── conditional-fetching.md
│ │ │ ├── data-fetching.mdx
│ │ │ ├── error-handling.mdx
│ │ │ ├── getting-started.mdx
│ │ │ ├── global-configuration.md
│ │ │ ├── middleware.mdx
│ │ │ ├── mutation.md
│ │ │ ├── options.mdx
│ │ │ ├── pagination.mdx
│ │ │ ├── prefetching.md
│ │ │ ├── revalidation.mdx
│ │ │ ├── suspense.mdx
│ │ │ ├── understanding.mdx
│ │ │ ├── with-nextjs.mdx
│ │ │ └── wrap-toc-items.mdx
│ │ ├── examples/
│ │ │ ├── _meta.ts
│ │ │ ├── auth.mdx
│ │ │ ├── basic.mdx
│ │ │ ├── error-handling.mdx
│ │ │ ├── infinite-loading.mdx
│ │ │ └── ssr.mdx
│ │ └── index.mdx
│ ├── mdx-components.ts
│ ├── next.config.ts
│ ├── nextra-remote-filepaths/
│ │ ├── fetch.js
│ │ ├── graphql-eslint.json
│ │ └── graphql-yoga.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── proxy.ts
│ ├── public/
│ │ ├── favicon/
│ │ │ └── browserconfig.xml
│ │ └── stork.wasm
│ ├── tsconfig.json
│ └── vercel.json
├── package.json
├── packages/
│ ├── esbuild-react-compiler-plugin/
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── env.d.ts
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ └── tsup.config.ts
│ ├── eslint-config/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── nextra/
│ │ ├── CHANGELOG.md
│ │ ├── default-entry.ts
│ │ ├── loader.cjs
│ │ ├── package.json
│ │ ├── setup-files.ts
│ │ ├── src/
│ │ │ ├── client/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── mdx-components.test-d.ts
│ │ │ │ │ ├── remove-links.test.tsx
│ │ │ │ │ └── use-fs-route.test.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── banner/
│ │ │ │ │ │ ├── close-banner-button.tsx
│ │ │ │ │ │ ├── index.client.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── bleed.tsx
│ │ │ │ │ ├── button.tsx
│ │ │ │ │ ├── callout.tsx
│ │ │ │ │ ├── cards.tsx
│ │ │ │ │ ├── collapse.tsx
│ │ │ │ │ ├── file-tree/
│ │ │ │ │ │ ├── file.tsx
│ │ │ │ │ │ ├── folder.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── tree.tsx
│ │ │ │ │ ├── head.tsx
│ │ │ │ │ ├── image-zoom.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── playground.tsx
│ │ │ │ │ ├── popup/
│ │ │ │ │ │ ├── index.client.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── search.tsx
│ │ │ │ │ ├── select.tsx
│ │ │ │ │ ├── skip-nav/
│ │ │ │ │ │ ├── index.client.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── steps.tsx
│ │ │ │ │ └── tabs/
│ │ │ │ │ ├── index.client.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── evaluate.ts
│ │ │ │ ├── hocs/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── with-github-alert.tsx
│ │ │ │ │ └── with-icons.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── use-copy.ts
│ │ │ │ │ ├── use-fs-route.ts
│ │ │ │ │ ├── use-hash.ts
│ │ │ │ │ └── use-mounted.ts
│ │ │ │ ├── icons/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── mdx-components/
│ │ │ │ │ ├── anchor.tsx
│ │ │ │ │ ├── code.tsx
│ │ │ │ │ ├── details.tsx
│ │ │ │ │ ├── image.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── pre/
│ │ │ │ │ │ ├── copy-to-clipboard.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── toggle-word-wrap-button.tsx
│ │ │ │ │ ├── summary.tsx
│ │ │ │ │ └── table.tsx
│ │ │ │ ├── mdx-components.ts
│ │ │ │ ├── mdx-remote.tsx
│ │ │ │ ├── normalize-pages.ts
│ │ │ │ ├── pages.ts
│ │ │ │ ├── remove-links.ts
│ │ │ │ └── setup-page.tsx
│ │ │ ├── env.d.ts
│ │ │ ├── icon.ts
│ │ │ ├── server/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── compile.test.ts.snap
│ │ │ │ │ │ └── normalize.test.ts.snap
│ │ │ │ │ ├── compile-metadata.test.ts
│ │ │ │ │ ├── compile.test.ts
│ │ │ │ │ ├── fixture/
│ │ │ │ │ │ └── page-maps/
│ │ │ │ │ │ ├── active-type-should-be-initialized-from-star/
│ │ │ │ │ │ │ ├── 1-level/
│ │ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ │ └── foo.md
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ └── generated-page-map.ts
│ │ │ │ │ │ ├── first-child-route-should-return-index-as-first/
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ ├── blog/
│ │ │ │ │ │ │ │ ├── _.md
│ │ │ │ │ │ │ │ ├── a.md
│ │ │ │ │ │ │ │ └── index.md
│ │ │ │ │ │ │ └── generated-page-map.ts
│ │ │ │ │ │ ├── folder-index-page-and-folder-should-be-merged/
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ ├── themes/
│ │ │ │ │ │ │ │ └── bar.md
│ │ │ │ │ │ │ ├── themes-test/
│ │ │ │ │ │ │ │ └── foo.md
│ │ │ │ │ │ │ ├── themes-test.md
│ │ │ │ │ │ │ └── themes.md
│ │ │ │ │ │ ├── folder-with-symlinks/
│ │ │ │ │ │ │ ├── docs/
│ │ │ │ │ │ │ │ └── test2.md
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ └── generated-page-map.ts
│ │ │ │ │ │ │ └── test1.md
│ │ │ │ │ │ ├── folder-without-markdown-files/
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ └── test.ts
│ │ │ │ │ │ ├── folder-without-meta-json/
│ │ │ │ │ │ │ ├── callout.md
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ └── tabs.md
│ │ │ │ │ │ ├── hidden-route-should-have-theme-context/
│ │ │ │ │ │ │ ├── 1-level/
│ │ │ │ │ │ │ │ ├── 2-level/
│ │ │ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ │ │ └── foo.md
│ │ │ │ │ │ │ │ └── qux.md
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ ├── bar.md
│ │ │ │ │ │ │ └── generated-page-map.ts
│ │ │ │ │ │ ├── non-english-characters-in-filename/
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ ├── тест.mdx
│ │ │ │ │ │ │ └── 测试.mdx
│ │ │ │ │ │ ├── page-map.ts
│ │ │ │ │ │ ├── pages-order-without-type-page/
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ ├── docs/
│ │ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ │ └── bar.md
│ │ │ │ │ │ │ ├── foo.md
│ │ │ │ │ │ │ └── generated-page-map.ts
│ │ │ │ │ │ ├── respect-order-for-type-separator-menu-and-item-with-href/
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ └── one/
│ │ │ │ │ │ │ └── two/
│ │ │ │ │ │ │ ├── 1-one.md
│ │ │ │ │ │ │ ├── 2024.md
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ ├── foo.md
│ │ │ │ │ │ │ ├── one.md
│ │ │ │ │ │ │ └── qux.md
│ │ │ │ │ │ ├── should-move-file-with-index-name/
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ ├── foo.mdx
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ └── index.mdx
│ │ │ │ │ │ ├── should-rename-folder/
│ │ │ │ │ │ │ ├── _meta.js
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ └── test/
│ │ │ │ │ │ │ └── foo.md
│ │ │ │ │ │ ├── title/
│ │ │ │ │ │ │ ├── 1-meta.mdx
│ │ │ │ │ │ │ ├── 2-sidebar-title.mdx
│ │ │ │ │ │ │ ├── 3-title.mdx
│ │ │ │ │ │ │ ├── 4-from-filename.mdx
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ ├── folder/
│ │ │ │ │ │ │ │ ├── bar.mdx
│ │ │ │ │ │ │ │ └── index.mdx
│ │ │ │ │ │ │ ├── folder-with-index/
│ │ │ │ │ │ │ │ ├── foo.mdx
│ │ │ │ │ │ │ │ └── index.mdx
│ │ │ │ │ │ │ └── generated-page-map.ts
│ │ │ │ │ │ ├── type-menu-should-contain-items/
│ │ │ │ │ │ │ ├── _meta.ts
│ │ │ │ │ │ │ ├── generated-page-map.ts
│ │ │ │ │ │ │ ├── mix/
│ │ │ │ │ │ │ │ ├── not-specified.md
│ │ │ │ │ │ │ │ └── qux.md
│ │ │ │ │ │ │ └── pagesOnly/
│ │ │ │ │ │ │ ├── one.md
│ │ │ │ │ │ │ └── two.md
│ │ │ │ │ │ └── type-menu-should-contain-local-pages/
│ │ │ │ │ │ ├── mix/
│ │ │ │ │ │ │ ├── not-specified.md
│ │ │ │ │ │ │ └── qux.md
│ │ │ │ │ │ └── one/
│ │ │ │ │ │ └── bar.md
│ │ │ │ │ ├── latex.test.ts
│ │ │ │ │ ├── merge-meta-with-page-map.test.ts
│ │ │ │ │ ├── nextra-config.test-d.ts
│ │ │ │ │ ├── normalize.test.ts
│ │ │ │ │ ├── page-map.test.ts
│ │ │ │ │ ├── recma-rewrite.test.ts
│ │ │ │ │ ├── rehype-extract-toc-content.test.ts
│ │ │ │ │ ├── remark-mdx-frontmatter.test.ts
│ │ │ │ │ ├── remark-mdx-title.test.ts
│ │ │ │ │ ├── remark-remove-imports.test.ts
│ │ │ │ │ ├── remark-static-images.test.ts
│ │ │ │ │ ├── test-utils.ts
│ │ │ │ │ ├── to-js.test.ts
│ │ │ │ │ └── to-page-map.test.ts
│ │ │ │ ├── compile-metadata.ts
│ │ │ │ ├── compile.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── fetch-filepaths-from-github.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── loader.ts
│ │ │ │ ├── locales.ts
│ │ │ │ ├── page-map/
│ │ │ │ │ ├── find-meta-and-page-file-paths.ts
│ │ │ │ │ ├── get.ts
│ │ │ │ │ ├── index-page.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── merge-meta-with-page-map.ts
│ │ │ │ │ ├── normalize.ts
│ │ │ │ │ ├── placeholder.ts
│ │ │ │ │ ├── to-ast.ts
│ │ │ │ │ ├── to-js.ts
│ │ │ │ │ └── to-page-map.ts
│ │ │ │ ├── recma-plugins/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── recma-rewrite.ts
│ │ │ │ ├── rehype-plugins/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── rehype-better-react-mathjax.ts
│ │ │ │ │ ├── rehype-extract-toc-content.ts
│ │ │ │ │ ├── rehype-twoslash-popup.ts
│ │ │ │ │ └── rehype.ts
│ │ │ │ ├── remark-plugins/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── remark-assign-frontmatter.ts
│ │ │ │ │ ├── remark-custom-heading-id.ts
│ │ │ │ │ ├── remark-export-only-metadata.ts
│ │ │ │ │ ├── remark-export-source-code.ts
│ │ │ │ │ ├── remark-headings.ts
│ │ │ │ │ ├── remark-link-rewrite.ts
│ │ │ │ │ ├── remark-mdx-disable-explicit-jsx.ts
│ │ │ │ │ ├── remark-mdx-frontmatter.ts
│ │ │ │ │ ├── remark-mdx-title.ts
│ │ │ │ │ ├── remark-remove-imports.ts
│ │ │ │ │ └── remark-static-image.ts
│ │ │ │ ├── schemas.ts
│ │ │ │ ├── tsdoc/
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── tsdoc.tsx
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── zod-to-ts.ts
│ │ │ │ ├── twoslash.ts
│ │ │ │ └── utils.ts
│ │ │ ├── types.generated.ts
│ │ │ └── types.ts
│ │ ├── styles/
│ │ │ ├── cards.css
│ │ │ ├── code-block.css
│ │ │ ├── default.css
│ │ │ ├── react-medium-image-zoom.css
│ │ │ ├── scrollbar.css
│ │ │ ├── steps.css
│ │ │ └── subheading-anchor.css
│ │ ├── tsconfig.json
│ │ ├── tsup.config.ts
│ │ └── vitest.config.ts
│ ├── nextra-theme-blog/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── __test__/
│ │ │ └── is-valid-date.test.ts
│ │ ├── package.json
│ │ ├── postcss.config.mjs
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── cusdis.tsx
│ │ │ │ ├── go-back.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── meta.tsx
│ │ │ │ ├── navbar-link.tsx
│ │ │ │ ├── navbar.tsx
│ │ │ │ ├── post-card.tsx
│ │ │ │ └── theme-switch.tsx
│ │ │ ├── env.d.ts
│ │ │ ├── index.ts
│ │ │ ├── is-valid-date.ts
│ │ │ ├── mdx-components.tsx
│ │ │ ├── style.css
│ │ │ └── types.ts
│ │ ├── tsconfig.json
│ │ ├── tsup.config.ts
│ │ └── vitest.config.mts
│ ├── nextra-theme-docs/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── css/
│ │ │ ├── hamburger.css
│ │ │ └── typesetting-article.css
│ │ ├── package.json
│ │ ├── postcss.config.mjs
│ │ ├── setup-files.ts
│ │ ├── src/
│ │ │ ├── __tests__/
│ │ │ │ ├── git-url-parse.test.ts
│ │ │ │ ├── layout-props.test-d.ts
│ │ │ │ └── mdx-components.test-d.ts
│ │ │ ├── components/
│ │ │ │ ├── 404/
│ │ │ │ │ ├── index.client.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── back-to-top.tsx
│ │ │ │ ├── breadcrumb.tsx
│ │ │ │ ├── copy-page.tsx
│ │ │ │ ├── footer/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── switchers.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── last-updated.tsx
│ │ │ │ ├── locale-switch.tsx
│ │ │ │ ├── navbar/
│ │ │ │ │ ├── index.client.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── pagination.tsx
│ │ │ │ ├── sidebar.tsx
│ │ │ │ ├── theme-switch.tsx
│ │ │ │ └── toc.tsx
│ │ │ ├── index.ts
│ │ │ ├── layout.tsx
│ │ │ ├── mdx-components/
│ │ │ │ ├── heading-anchor.client.tsx
│ │ │ │ ├── heading.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── link.tsx
│ │ │ │ └── wrapper.client.tsx
│ │ │ ├── schemas.tsx
│ │ │ ├── stores/
│ │ │ │ ├── active-anchor.ts
│ │ │ │ ├── config.tsx
│ │ │ │ ├── focused-route.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── menu.ts
│ │ │ │ ├── theme-config.ts
│ │ │ │ └── toc.ts
│ │ │ ├── style.css
│ │ │ ├── types.generated.ts
│ │ │ └── utils/
│ │ │ ├── extract-only-strings-from-react-node.ts
│ │ │ ├── get-git-issue-url.ts
│ │ │ ├── git-url-parse.ts
│ │ │ └── index.ts
│ │ ├── tailwind.config.ts
│ │ ├── tsconfig.json
│ │ ├── tsup.config.ts
│ │ └── vitest.config.mts
│ ├── prettier-config/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── src/
│ │ └── index.js
│ └── tsdoc/
│ ├── README.md
│ ├── package.json
│ ├── src/
│ │ ├── __tests__/
│ │ │ ├── base.test.ts
│ │ │ ├── fixtures/
│ │ │ │ └── flattened.ts
│ │ │ ├── snapshots/
│ │ │ │ ├── flattened.json
│ │ │ │ ├── get-smooth-step-path.json
│ │ │ │ ├── get-viewport-for-bounds.json
│ │ │ │ ├── head-props.ts
│ │ │ │ ├── head.json
│ │ │ │ ├── layout-props.json
│ │ │ │ ├── layout-props.ts
│ │ │ │ ├── navbar.json
│ │ │ │ ├── nextra-config.json
│ │ │ │ ├── react-flow-instance.json
│ │ │ │ ├── search.json
│ │ │ │ ├── use-config.json
│ │ │ │ ├── use-edges-state.json
│ │ │ │ └── use-theme-config.json
│ │ │ └── zod-to-ts.test.ts
│ │ ├── env.d.ts
│ │ └── index.ts
│ ├── tsconfig.json
│ ├── tsup.config.ts
│ └── vitest.config.ts
├── patches/
│ ├── @changesets__assemble-release-plan.patch
│ ├── esbuild-plugin-svgr.patch
│ ├── eslint-plugin-tailwindcss.patch
│ ├── next.patch
│ └── tsup.patch
├── pnpm-workspace.yaml
├── prettier.config.mjs
├── renovate.json5
└── turbo.jsonc
================================================
FILE CONTENTS
================================================
================================================
FILE: .changeset/config.json
================================================
{
"$schema": "https://unpkg.com/@changesets/config@2.0.1/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [["nextra", "nextra-theme-docs", "nextra-theme-blog"]],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
},
"ignore": [
"@nextra/tsdoc",
"example-blog",
"example-docs",
"swr-site",
"docs",
"@nextra/prettier-config",
"@nextra/eslint-config"
]
}
================================================
FILE: .editorconfig
================================================
[*]
indent_style = space
indent_size = 2
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of
any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at g@shud.in. All
complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug** A clear and concise description of what the bug is.
**To Reproduce** Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior** A clear and concise description of what you expected to
happen.
**Screenshots** If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context** Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.** A clear and
concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like** A clear and concise description of what you
want to happen.
**Describe alternatives you've considered** A clear and concise description of
any alternative solutions or features you've considered.
**Additional context** Add any other context or screenshots about the feature
request here.
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--
Thank you for contributing to this project! You must fill out the information below before we can
review this pull request. By explaining why you're making a change (or linking to an issue) and
what changes you've made, we can triage your pull request to the best possible team for review.
-->
## Why:
Closes:
<!-- If there's an existing issue for your change, please link to it above. -->
## What's being changed (if available, include any code snippets, screenshots, or gifs):
<!-- Let us know what you are changing. Share anything that could provide the most context. -->
## Check off the following:
- [ ] I have reviewed my changes in staging, available via the **View
deployment** link in this PR's timeline (this link will be available after
opening the PR).
================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint
on:
pull_request:
branches: [main, v4-v2]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Check out code
uses: actions/checkout@v4
- name: Cache turbo build setup
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: pnpm
- name: Install Dependencies
run: pnpm i
- name: Lint Prettier
run: pnpm lint:prettier
- name: Lint ESLint
run: pnpm lint
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches: [main, v4-v2]
jobs:
release:
if: github.repository == 'shuding/nextra'
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Check out code
uses: actions/checkout@v4
- name: Cache turbo build setup
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: pnpm
- name: Install Dependencies
run: pnpm i
- name: Clean
run: pnpm clean
- name: Build
run: pnpm build
- name: Type Check
run: pnpm types:check
- name: Create Release Pull Request or Publish to npm
uses: changesets/action@v1
with:
publish: pnpm release
version: pnpm run version # should be `pnpm run`
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
pull_request:
branches: [main, v4-v2]
jobs:
test:
name: Test (${{matrix.os}})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Check out code
uses: actions/checkout@v4
- name: Cache turbo build setup
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: pnpm
- run: pnpm i
- run: pnpm build:all
- run: pnpm test
- run: pnpm clean
- run: pnpm types:check
================================================
FILE: .gitignore
================================================
.DS_Store
.next/
.tsup/
node_modules/
*.log
dist/
.turbo/
out/
.vercel/
.idea/
.eslintcache
.env
tsup.config.bundled*
tsconfig.tsbuildinfo
tsconfig.vitest-temp.json
_pagefind/
docs/public/sitemap.xml
next-env.d.ts
================================================
FILE: .node-version
================================================
22
================================================
FILE: .npmrc
================================================
strict-peer-dependencies=false
shell-emulator=true
enable-pre-post-scripts=true
================================================
FILE: .prettierignore
================================================
pnpm-lock.yaml
.changeset/*.md
CHANGELOG.md
generated-page-map.ts
packages/tsdoc/src/__tests__/snapshots
examples/swr-site/nextra-remote-filepaths/*.json
examples/docs/src/content/features/mdx.mdx
docs/app/docs/guide/ssg/page.mdx
docs/app/docs/guide/syntax-highlighting/page.mdx
# contains mdx comments
docs/app/docs/blog-theme/start/page.mdx
types.generated.ts
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Shu Ding
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Nextra
Simple, powerful and flexible site generation framework with everything you love
from Next.js.
## Documentation
https://nextra.site
## Development
### Installation
The Nextra repository uses [PNPM Workspaces](https://pnpm.io/workspaces) and
[Turborepo](https://github.com/vercel/turborepo).
1. Run `corepack enable` to enable Corepack.
> If the command above fails, run `npm install -g corepack@latest` to install
> the latest version of
> [Corepack](https://github.com/nodejs/corepack?tab=readme-ov-file#manual-installs).
2. Run `pnpm install` to install the project's dependencies.
### Build `nextra`
```bash
pnpm --filter nextra build
```
Watch mode: `pnpm --filter nextra dev`
### Build `nextra-theme-docs`
```bash
pnpm --filter nextra-theme-docs build
```
### Development
You can also debug them together with a website locally. For instance, to start
`examples/docs` locally, run
```bash
pnpm --filter example-docs dev
```
Any change to `example/docs` will be re-rendered instantly.
If you update the core or theme packages, a rebuild is required. Or you can use
the watch mode for both Nextra and the theme in separated terminals.
## Sponsors
<div>
<a href="https://inkeep.com?utm_source=github&utm_campaign=nextra&utm_content=logolink">
<img src="/docs/app/showcase/_logos/inkeep.png" alt="Inkeep - AI Agents that get real work done" width="256">
</a>
<a href="https://xyflow.com?utm_source=github&utm_campaign=nextra&utm_content=logolink">
<img src="/docs/app/showcase/_logos/xyflow.png" alt="xyflow preview" width="256">
</a>
</div>
================================================
FILE: docs/app/_components/features/index.tsx
================================================
import { ArrowRightIcon } from '@components/icons'
import cn from 'clsx'
import Link from 'next/link'
import type { ComponentProps, FC, ReactNode } from 'react'
import { MotionDiv } from '../framer-motion'
import styles from './style.module.css'
export const Feature: FC<
{
large?: boolean
centered?: boolean
children: ReactNode
lightOnly?: boolean
href?: string
index: number
} & ComponentProps<typeof MotionDiv>
> = ({
large,
centered,
children,
lightOnly,
className,
href,
index,
...props
}) => {
return (
<MotionDiv
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true, margin: '-20px' }}
transition={{ duration: Math.min(0.25 + index * 0.2, 0.8) }}
className={cn(
styles.feature,
large && styles.large,
centered && styles.centered,
lightOnly && styles['light-only'],
className
)}
{...props}
>
{children}
{href && (
<Link
className={cn('x:focus-visible:nextra-focus', styles.link)}
href={href}
target="_blank"
rel="noreferrer"
>
<ArrowRightIcon height="24" />
</Link>
)}
</MotionDiv>
)
}
export const Features: FC<{ children: ReactNode }> = ({ children }) => {
return <div className={styles.features}>{children}</div>
}
================================================
FILE: docs/app/_components/features/style.module.css
================================================
.feature {
position: relative;
padding: 1.5rem 1.75rem;
color: #000;
background-color: white;
overflow: hidden;
border-radius: 1.78em;
}
.feature.large {
grid-column: span 2;
}
.feature.centered {
text-align: center;
}
.feature h3 {
position: relative;
font-size: 34px;
font-size: min(34px, max(4vw, 24px));
font-weight: 600;
line-height: 1.25;
letter-spacing: -0.02rem;
z-index: 2;
}
:global(.dark) .feature:not(.light-only) {
color: #fff;
background-color: #202020;
}
.feature {
box-shadow:
0 8px 16px rgb(0 0 0 / 8%),
0 1px 2px rgb(0 0 0 / 4%),
0 0 0 1px rgb(0 0 0 / 3%);
transition: box-shadow 0.3s ease;
}
:global(.dark) .feature {
box-shadow: 0 0 0 1px rgb(82 82 82 / 60%);
}
.feature .link {
position: absolute;
right: 1em;
bottom: 1em;
z-index: 2;
width: 2.5em;
height: 2.5em;
background-color: rgb(0 0 0 / 39%);
backdrop-filter: blur(10px);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: rgba(255, 255, 255, 0.9);
box-shadow:
0 0 0 2px rgb(154 154 154 / 56%),
0 0 30px rgb(0 0 0 / 10%);
transition: all 0.2s ease;
-webkit-user-drag: none;
}
@media (hover: hover) {
.feature .link {
opacity: 0;
}
.feature:hover .link {
opacity: 1;
}
.feature .link:hover,
.link:focus {
transform: scale(1.05);
color: rgba(255, 255, 255, 1);
background-color: rgba(64, 64, 64, 0.39);
box-shadow:
0 0 0 2px rgba(220, 220, 220, 0.56),
0 0 30px rgb(0 0 0 / 10%);
}
.feature .link:active {
transform: scale(1);
color: rgba(255, 255, 255, 0.8);
background-color: rgba(22, 22, 22, 0.39);
box-shadow:
0 0 0 2px rgba(178, 178, 178, 0.56),
0 0 30px rgb(0 0 0 / 10%);
}
}
.features {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 2em;
font-feature-settings: initial;
}
.feature :global(.show-on-mobile) {
display: none;
}
@media screen and (max-width: 1024px) {
.feature {
max-width: 80vw;
width: 100%;
}
.feature.large {
grid-column: span 1;
}
.features {
grid-template-columns: 1fr;
grid-gap: 3em;
justify-items: center;
}
.feature h3 {
font-size: 28px;
font-size: min(28px, max(4vw, 22px));
text-align: center;
}
}
@media screen and (max-width: 640px) {
.feature {
max-width: 460px;
width: 100%;
}
.feature.large {
grid-column: span 1;
}
.features {
grid-template-columns: 1fr;
grid-gap: 3em;
justify-items: center;
}
.feature h3 {
font-size: 34px;
font-size: min(34px, max(4vw, 22px));
text-align: center;
}
.feature :global(.show-on-mobile) {
display: block;
}
}
================================================
FILE: docs/app/_components/features/themes-animation.tsx
================================================
import type { FC } from 'react'
export const ThemesAnimation: FC = props => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="-50 0 268 250"
{...props}
>
<circle
cx="83.4"
cy="142.4"
r="48.84"
fill="#DDD"
fillOpacity="0.2"
stroke="#E6E6E6"
strokeWidth="3"
/>
<path
fill="#000"
d="M61.88 146.8v-7.13h.07l4.74 7.13h1.75v-10.67h-1.97v7.1h-.07l-4.73-7.1h-1.76v10.67h1.97zm12.14.15c2.22 0 3.3-1.32 3.5-2.65H75.6c-.17.67-.75 1.08-1.57 1.08-1.05 0-1.76-.8-1.76-2.06v-.22h5.31v-.82c0-2.38-1.4-3.92-3.65-3.92-2.18 0-3.67 1.44-3.67 3.87v.76c0 2.54 1.48 3.96 3.75 3.96zm-1.74-5.16v-.01c0-1.07.67-1.89 1.67-1.89 1 0 1.65.82 1.65 1.89v.01h-3.32zm11.7 5h2.32l-2.69-4.14 2.71-4.14h-2.27l-1.64 2.82h-.06l-1.64-2.82h-2.38l2.65 4.14-2.63 4.15h2.2l1.69-2.82h.05l1.7 2.82zm4.46-8.28h-1.21v1.6h1.17v4.35c0 1.7.68 2.39 2.74 2.39.42 0 .78-.04.94-.07v-1.53l-.44.02c-.85 0-1.2-.25-1.2-1.08v-4.09h1.6v-1.59h-1.6v-1.98h-2v1.98zm5.4 7.24c0 .67.55 1.22 1.22 1.22a1.22 1.22 0 000-2.43c-.67 0-1.22.55-1.22 1.21zm4.26-9.3c0 .65.53 1.08 1.17 1.08.64 0 1.16-.43 1.16-1.07 0-.65-.52-1.09-1.16-1.09-.64 0-1.17.44-1.17 1.09zm2.19 2.06h-2.05v8.44c0 .89-.34 1.25-1.07 1.25-.16 0-.35-.01-.47-.03v1.48c.15.02.57.06.86.06 1.64 0 2.73-.83 2.73-2.74v-8.46zm1.84 2.46c0 1.53 1.2 2.09 2.7 2.4 1.06.21 2.05.33 2.05 1.13 0 .54-.45 1-1.42 1-.88 0-1.41-.42-1.5-1.03h-1.99c0 1.48 1.24 2.48 3.38 2.48 2.19 0 3.53-1.01 3.53-2.71 0-1.53-1.12-2.06-2.64-2.33-.95-.17-2.14-.31-2.14-1.13 0-.61.51-.99 1.32-.99 1 0 1.33.58 1.39 1.1h1.82c0-1.54-1.2-2.53-3.18-2.53-1.74 0-3.32.77-3.32 2.61z"
/>
<path
fill="#888"
d="M84.48 35.77h2.8v-.97h-2.8v-2.88h-.97v2.88h-2.78v.97h2.78v3.05h.97v-3.05z"
/>
<path
className="dash-ring"
stroke="#E6E6E6"
strokeDasharray="7 7"
strokeLinecap="round"
strokeWidth="3"
d="M166 143a82 82 0 11-164 0 82 82 0 01164 0z"
/>
<path
fill="#fff"
fillOpacity="0.82"
d="M64.77 67v3h3v-3h-3zm0-6.24v-3h-3v3h3zm.05 0l2.5-1.66-.89-1.34h-1.6v3zM68.97 67l-2.5 1.66.9 1.34h1.6v-3zm1.53 0v3h3v-3h-3zm0-9.33h3v-3h-3v3zm-1.72 0v-3h-3v3h3zm0 6.2v3h3v-3h-3zm-.06 0l-2.5 1.67.9 1.34h1.6v-3zm-4.14-6.2l2.5-1.66-.9-1.34h-1.6v3zm-1.53 0v-3h-3v3h3zm0 9.33h-3v3h3v-3zm4.72 0v-6.24h-6V67h6zm-3-3.24h.05v-6h-.05v6zm-2.45-1.34l4.15 6.24 5-3.32-4.15-6.24-5 3.32zM68.97 70h1.53v-6h-1.53v6zm4.53-3v-9.33h-6V67h6zm-3-12.33h-1.72v6h1.72v-6zm-4.72 3v6.2h6v-6.2h-6zm3 3.2h-.06v6h.06v-6zm2.44 1.34l-4.14-6.2-5 3.32 4.14 6.2 5-3.32zm-6.64-7.54h-1.53v6h1.53v-6zm-4.53 3V67h6v-9.33h-6zm3 12.33h1.72v-6h-1.72v6zm15.68-5.19l2.96.44.51-3.44h-3.47v3zm-1.67 0v-3h-2.33l-.58 2.26 2.9.74zm-2.91-1.05v-3h-3v3h3zm4.64 0v3h3v-3h-3zm-4.64-1.14h-3v3h3v-3zm2.9 0v3h3v-3h-3zm-1.38 7.51c1.6 0 3.04-.49 4.16-1.46a5.6 5.6 0 001.86-3.42l-5.93-.87a.4.4 0 01.14-.24c.04-.04.07-.05.06-.04-.02 0-.1.03-.29.03v6zm3.06-8.32h-1.67v6h1.67v-6zm-4.58 2.26c.1-.38.35-.77.73-1.03.36-.25.67-.28.8-.28v6c1.8 0 3.73-1.03 4.28-3.2l-5.8-1.5zm1.53-1.31c.36 0 .82.16 1.16.55.3.35.3.65.3.65h-6c0 1.1.32 2.3 1.16 3.27a4.43 4.43 0 003.38 1.53v-6zm1.47 1.2v-.2h-6v.2h6zm-3 2.8h4.64v-6h-4.64v6zm7.64-3v-.71h-6v.71h6zm0-.71a6.6 6.6 0 00-1.65-4.54 6.08 6.08 0 00-4.54-1.9v6a.91.91 0 01.2.03l-.02-.01a.26.26 0 01-.05-.04c-.06-.08.06 0 .06.46h6zm-6.2-6.43c-1.62 0-3.25.55-4.47 1.8A6.45 6.45 0 0069.38 63h6c0-.22.04-.35.05-.4.02-.04.02-.03 0 0-.04.04-.06.05-.06.04.01 0 .08-.02.23-.02v-6zM69.4 63v.66h6V63h-6zm0 .66c0 1.7.5 3.39 1.74 4.66a6.22 6.22 0 004.54 1.81v-6a.89.89 0 01-.3-.04s.02 0 .06.05c.04.03.03.05.01 0a1.54 1.54 0 01-.06-.48h-6zm7.76-1.04v-.02h-6v.02h6zm0-.02c0 .15-.05.47-.33.8a1.7 1.7 0 01-1.21.56v-6c-2.94 0-4.46 2.48-4.46 4.64h6zm-1.54 1.36c-.44 0-.91-.2-1.23-.58a1.23 1.23 0 01-.33-.78h6c0-1.05-.32-2.2-1.1-3.12a4.34 4.34 0 00-3.34-1.52v6zm-1.56-1.36v.02h6v-.02h-6zm3-2.98h-2.9v6h2.9v-6zM84.67 67l-2.57 1.55.87 1.45h1.7v-3zm2.02 0v3h5.52l-3-4.63L86.69 67zm-2.35-3.63l-2.51-1.64-1.07 1.63L81.82 65l2.52-1.63zm2.37-3.62l2.51 1.64 3.04-4.64h-5.55v3zm-1.99 0v-3H83l-.87 1.49 2.6 1.5zM83.3 62.2v3H85l.87-1.49-2.6-1.5zm-.05 0l-2.6 1.51.87 1.5h1.73v-3zm-1.44-2.46l2.6-1.51-.87-1.5H81.8v3zm-2.08 0v-3h-5.48l2.95 4.61 2.53-1.61zm2.31 3.62l2.54 1.6 1.02-1.6-1.03-1.62-2.53 1.62zM79.73 67l-2.53-1.6-2.9 4.6h5.45v-3zm1.94 0v3h1.7l.87-1.46L81.67 67zm1.47-2.47v-3h-1.71L80.56 63l2.58 1.53zm.04 0L85.75 63l-.87-1.46h-1.7v3zM84.67 70h2.02v-6h-2.02v6zm4.54-4.63l-2.35-3.63L81.82 65l2.35 3.63 5.04-3.26zM86.85 65l2.37-3.62-5.02-3.29-2.37 3.63L86.85 65zm-.14-8.26h-1.99v6h2v-6zm-4.58 1.49l-1.44 2.47 5.19 3.01 1.43-2.46-5.18-3.02zm1.16.97h-.05v6h.05v-6zm2.54 1.5l-1.43-2.47-5.2 3.02 1.44 2.46 5.2-3.01zm-4.03-3.96h-2.08v6h2.08v-6zm-4.61 4.61L79.51 65l5.05-3.24-2.32-3.62-5.05 3.23zm2.31.4l-2.3 3.64 5.07 3.2 2.3-3.63-5.07-3.2zm.24 8.24h1.93v-6h-1.93v6zm4.5-1.46l1.47-2.47L80.56 63l-1.47 2.46 5.15 3.08zm-1.1-1h.04v-6h-.04v6zm-2.53-1.46l1.49 2.47 5.14-3.1L85.75 63l-5.14 3.09zm8.23-6.33v3h3v-3h-3zm-1.06 0v-3h-3v3h3zm0 1.4h-3v3h3v-3zm1.03 0h3v-3h-3v3zm3.22 5.83l.59 2.94 2.4-.48v-2.46h-3zm0-1.33h3v-3.26l-3.25.27.25 2.99zm-1.44-4.5v-3h-3v3h3zm1.41 0v3h3v-3h-3zm0-1.4h3v-3h-3v3zm-1.4 0h-3v3h3v-3zm0-1.74h3v-3h-3v3zm-1.76 0v-3h-3v3h3zm0-1.26h-1.06v6h1.06v-6zm-4.06 3v1.4h6v-1.4h-6zm3 4.4h1.03v-6h-1.03v6zm-1.97-3v3.8h6v-3.8h-6zm0 3.8c0 1.04.19 2.64 1.51 3.83a5.64 5.64 0 003.89 1.26v-6c-.3 0-.4-.03-.39-.02a1.59 1.59 0 01.97.98c.04.13.02.14.02-.05h-6zm5.4 5.1c.5 0 1.02-.05 1.4-.13l-1.17-5.88.06-.01h.01-.06l-.24.01v6zm3.82-3.07v-1.33h-6v1.33h6zm-3.25-4.32c.01 0 .01 0 0 0a1.5 1.5 0 01-.13 0v6c.22 0 .45 0 .63-.02l-.5-5.98zm-.13 0c-.06 0 .03 0 .21.04a2.37 2.37 0 011.64 1.53c.1.28.1.48.1.49h-6c0 .68.12 2.02 1.3 3.02 1.03.89 2.25.92 2.75.92v-6zm1.94 2.06v-3.58h-6v3.58h6zm-3-.58H92v-6h-1.4v6zm4.41-3v-1.4h-6v1.4h6zm-3-4.4h-1.4v6H92v-6zm1.6 3V58h-6v1.74h6zm-3-4.73h-1.76v6h1.75v-6zm-4.76 3v1.74h6V58h-6zm8 8.99h-3v3h3v-3zm1.85 0v3h3v-3h-3zm2.3-5.76l-.82 2.89 3.82 1.1v-3.99h-3zm0-1.55h3V57.2l-2.44-.46-.56 2.95zm-2.27 1.06v3h2.12l.7-2-2.82-1zm-.08 0h-3v3h3v-3zm0-1h3v-3h-3v3zm-1.8 0v-3h-3v3h3zm0 10.25h1.85v-6h-1.84v6zm4.85-3v-4.14h-6V67h6zm0-4.14c0-.13.03.26-.35.73a1.78 1.78 0 01-.96.58.64.64 0 01-.1.01v-6a4.5 4.5 0 00-3.54 1.55 4.81 4.81 0 00-1.05 3.13h6zm-1.41 1.32a2.67 2.67 0 01.16 0h-.03a1.59 1.59 0 01-.24-.05l1.64-5.77a5.91 5.91 0 00-1.53-.18v6zm3.7-2.94V59.7h-6v1.55h6zm-2.43-4.5c-.34-.07-.72-.1-1.13-.1v6h.05-.04l1.12-5.9zm-1.13-.1a4.74 4.74 0 00-4.53 3.1l5.66 2c-.1.29-.26.5-.44.64-.23.18-.5.26-.7.26v-6zm-1.7 1.1h-.08v6h.08v-6zm2.92 3v-1h-6v1h6zm-3-4h-1.8v6h1.8v-6zm-4.8 3V67h6v-7.25h-6zm12.5 6.38v-3h-1.79l-.85 1.58 2.64 1.42zm.08 0h3v-3h-3v3zm0 .88h-3v3h3v-3zm1.7 0v3h3v-3h-3zm-5.87-5.04l-3-.13-.13 3.13h3.13v-3zm1.69 0v3h2.76l.22-2.75-2.98-.25zm2.4.82v3h3v-3h-3zm0 1.08h3v-3h-3v3zm-1.97 6.25c2.04 0 3.74-.96 4.61-2.57l-5.28-2.84c.12-.22.29-.4.48-.5.2-.1.3-.1.2-.1v6zm1.97-1h.08v-6h-.08v6zm-2.92-3v.9h6v-.88h-6zm3 3.89h1.7v-6h-1.7v6zm4.7-3v-4.9h-6V67h6zm0-4.9a5.2 5.2 0 00-2.01-4.24 6.39 6.39 0 00-3.93-1.23v6c.19 0 .3.02.35.04.05.01 0 0-.09-.06a.93.93 0 01-.26-.34c-.07-.14-.06-.21-.06-.17h6zm-5.94-5.47a6.1 6.1 0 00-4.27 1.52 5.3 5.3 0 00-1.65 3.68l6 .27-.05.13a.9.9 0 01-.35.4l-.05.04s.11-.04.37-.04v-6zm-2.93 8.33h1.69v-6h-1.69v6zm4.67-2.75a2 2 0 01-.72 1.35c-.46.39-.9.43-1.06.43v-6a4.3 4.3 0 00-2.78.96 3.99 3.99 0 00-1.41 2.77l5.97.49zm-1.78 1.78a1.8 1.8 0 01-1.16-.52c-.55-.5-.64-1.1-.64-1.35h6c0-.98-.3-2.13-1.26-3.03a4.24 4.24 0 00-2.94-1.1v6zm-1.8-1.87v.66h6v-.66h-6zm3-2.34h-1.77v6h1.77v-6zm-1.77 0a5.9 5.9 0 00-3.87 1.29 4.95 4.95 0 00-1.7 3.85h6c0 .02 0 .13-.07.3a1.2 1.2 0 01-.33.43c-.27.23-.4.14-.02.14v-6zM96 64.9a5.1 5.1 0 001.65 3.84 5.51 5.51 0 003.73 1.36v-6c-.13 0 .05-.03.3.19.11.1.2.24.26.37.05.13.06.22.06.24h-6zm5.96-2.11c.2 0 .6.04 1 .36a2.1 2.1 0 01.83 1.63h-6c0 1.3.6 2.43 1.54 3.14.86.65 1.83.87 2.63.87v-6zm1.83 2c0 .46-.2 1.13-.78 1.61-.51.44-1 .45-1.04.45v-6c-.84 0-1.9.2-2.82.96a3.84 3.84 0 00-1.36 2.97h6zm-1.82 2.06h1.38v-6h-1.38v6zm-1.62-3v.76h6v-.76h-6zm0 .76c0-.6.29-1.13.7-1.46.35-.3.7-.36.91-.36v6c1.86 0 4.4-1.3 4.4-4.18h-6z"
/>
<path
fill="#000"
d="M64.77 67v-6.24h.05L68.97 67h1.53v-9.33h-1.72v6.2h-.06l-4.14-6.2h-1.53V67h1.72zm10.9.13c1.94 0 2.89-1.16 3.06-2.32h-1.67c-.15.59-.66.95-1.38.95-.91 0-1.53-.7-1.53-1.8v-.2h4.64v-.71c0-2.09-1.22-3.43-3.2-3.43-1.9 0-3.2 1.26-3.2 3.38v.66c0 2.23 1.3 3.47 3.28 3.47zm-1.52-4.51v-.02c0-.93.58-1.64 1.46-1.64.87 0 1.44.7 1.44 1.64v.02h-2.9zM84.67 67h2.02l-2.35-3.63 2.37-3.62h-1.99L83.3 62.2h-.05l-1.44-2.46h-2.08l2.31 3.62-2.3 3.63h1.94l1.47-2.47h.04L84.67 67zm4.17-7.25h-1.06v1.4h1.03v3.8c0 1.48.6 2.1 2.4 2.1.36 0 .68-.04.82-.07v-1.33l-.38.01c-.75 0-1.06-.22-1.06-.94v-3.58H92v-1.4h-1.4v-1.73h-1.76v1.74zm5 7.25h1.85v-4.14c0-.97.4-1.68 1.59-1.68.28 0 .57.02.7.06V59.7a3.05 3.05 0 00-.56-.05c-1 0-1.54.64-1.7 1.1h-.08v-1h-1.8V67zm7.53.1c1.07 0 1.68-.45 1.97-.98h.08V67h1.7v-4.9c0-1.69-1.27-2.47-2.94-2.47-2.1 0-2.87 1.12-2.93 2.33h1.69c.04-.58.47-.97 1.2-.97.76 0 1.2.4 1.2 1.13v.66h-1.77c-1.68 0-2.58.83-2.58 2.13 0 1.37.97 2.2 2.38 2.2zm.58-1.3c-.6 0-1.17-.33-1.17-1 0-.56.39-.94 1.18-.94h1.38v.76c0 .7-.61 1.18-1.39 1.18z"
/>
<path
className="theme-1"
fill="#000"
d="M53.13 6.53c0-1.63.7-2.54 1.92-2.54 1.04 0 1.74.7 1.75 1.7h1.3V5.6c0-1.62-1.29-2.76-3.06-2.76-2.06 0-3.25 1.4-3.25 3.69v.98c0 2.28 1.2 3.65 3.25 3.65 1.77 0 3.06-1.1 3.06-2.65v-.09h-1.3c-.01.94-.7 1.6-1.75 1.6-1.22 0-1.92-.9-1.92-2.5v-1zM64.58 4.8h-1.3v3.74c0 .92-.58 1.42-1.36 1.42-.7 0-1.31-.32-1.31-1.4V4.8h-1.3v4.12c0 1.43.87 2.16 2.15 2.16 1 0 1.58-.46 1.78-.95h.06V11h1.28V4.8zM66 6.6c0 1.14.92 1.52 2.05 1.76.83.17 1.55.27 1.55.92 0 .46-.38.85-1.2.85-.74 0-1.18-.34-1.25-.85h-1.27c0 1.11.94 1.82 2.43 1.82 1.56 0 2.56-.73 2.56-1.98 0-1.18-.9-1.53-2.06-1.74-.7-.13-1.56-.25-1.56-.9 0-.52.45-.82 1.11-.82.85 0 1.12.48 1.16.91h1.17c0-1.1-.83-1.88-2.3-1.88-1.25 0-2.39.58-2.39 1.92zm6.58-1.8h-.88v1.04h.86v3.41c0 1.24.41 1.78 1.92 1.78.26 0 .51-.02.62-.04v-1c-.08.02-.19.02-.3.02-.7 0-.95-.2-.95-.87v-3.3h1.21V4.81h-1.2V3.3h-1.28v1.5zm6.3-.1c-1.77 0-2.75 1.25-2.75 2.93v.5c0 1.75.97 2.97 2.76 2.97 1.78 0 2.74-1.22 2.74-2.97v-.5c0-1.68-.96-2.94-2.74-2.94zm0 1.03c.97 0 1.45.79 1.45 1.92v.47c0 1.12-.47 1.93-1.44 1.93-.98 0-1.45-.82-1.45-1.93v-.47c0-1.12.48-1.92 1.45-1.92zM83.06 11h1.3V7.17c0-.9.53-1.34 1.2-1.34.73 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.45-1.35 1.23-1.35.75 0 1.19.49 1.19 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.05-2.07-1.03 0-1.67.5-1.9 1.03h-.04c-.23-.62-.8-1.03-1.76-1.03-.88 0-1.42.49-1.6.93h-.07V4.8h-1.27V11zM93.3 3.3c0 .42.36.73.78.73.42 0 .77-.3.77-.74a.74.74 0 00-.77-.73c-.42 0-.78.3-.78.73zm.13 7.7h1.3V4.8h-1.3V11zm2.73 0h4.78V9.94H97.8v-.05l3.08-4.2v-.88H96.2v1.06h3.08v.04l-3.13 4.25V11zm8.52.1c1.53 0 2.34-.88 2.52-1.88h-1.23c-.16.53-.61.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.65-2.9-1.62 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.72 2.93zm-1.43-3.8v-.02c0-.88.54-1.57 1.38-1.57.83 0 1.37.69 1.37 1.57v.01h-2.75zm7.59-2.58c-1.52 0-2.42 1.18-2.42 2.91v.54c0 1.76.86 2.91 2.42 2.91.83 0 1.48-.39 1.8-1.02h.04V11h1.27V2.58h-1.3v3.11h-.05c-.3-.56-.94-.97-1.76-.97zm.32 1.08c.92 0 1.5.72 1.5 1.88v.46c0 1.2-.57 1.88-1.48 1.88-.84 0-1.44-.63-1.44-1.89v-.45c0-1.26.6-1.88 1.42-1.88z"
/>
<path
className="theme-2"
fill="#000"
d="M50.34 11V5.47h.04l2.08 4.68h.95l2.07-4.68h.05V11h1.2V3H55.4l-2.44 5.63h-.04L50.48 3h-1.34v8h1.2zm8.08-7.7c0 .42.35.73.77.73.42 0 .77-.3.77-.74a.74.74 0 00-.77-.73c-.42 0-.77.3-.77.73zm.12 7.7h1.3V4.8h-1.3V11zm6.59 0h1.48l-2.05-3.1 2.04-3.1h-1.45L63.8 7.04h-.02L62.41 4.8H60.9l2 3.1-2.02 3.1h1.41l1.4-2.21h.03l1.4 2.21zm4.83.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.15.53-.6.86-1.27.86-.88 0-1.44-.7-1.44-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.71 2.93zm-1.42-3.8v-.02c0-.88.54-1.57 1.38-1.57.82 0 1.37.69 1.37 1.57v.01h-2.75zm7.58-2.58c-1.51 0-2.42 1.18-2.42 2.91v.54c0 1.76.86 2.91 2.42 2.91.84 0 1.49-.39 1.8-1.02h.05V11h1.26V2.58h-1.3v3.11h-.04c-.3-.56-.94-.97-1.77-.97zm.33 1.08c.92 0 1.5.72 1.5 1.88v.46c0 1.2-.57 1.88-1.49 1.88-.83 0-1.43-.63-1.43-1.89v-.45c0-1.26.6-1.88 1.42-1.88zm9.78 5.2V4.14h2.35V3h-6.02v1.14h2.35V11h1.32zm3.3 0h1.3V7.3c0-.8.45-1.46 1.37-1.46.77 0 1.34.45 1.34 1.45V11h1.3V7.02c0-1.51-.92-2.3-2.18-2.3-1.01 0-1.57.54-1.78.95h-.05V2.58h-1.3V11zm9.33.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.6.86-1.27.86-.88 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.39-1.57.82 0 1.37.69 1.37 1.57v.01h-2.76zm5.42 3.7h1.3V7.17c0-.9.53-1.34 1.2-1.34.73 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.45-1.35 1.23-1.35.75 0 1.19.49 1.19 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.05-2.07-1.03 0-1.67.5-1.89 1.03h-.05c-.23-.62-.8-1.03-1.76-1.03-.88 0-1.42.49-1.6.93h-.06V4.8h-1.28V11zm12.77.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.6.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.38-1.57.83 0 1.38.69 1.38 1.57v.01h-2.76z"
/>
<path
className="theme-3"
fill="#000"
d="M52.3 3v8h2.75c2.38 0 3.56-1.44 3.56-4.01C58.6 4.4 57.44 3 55.05 3H52.3zm1.33 1.12h1.28c1.64 0 2.32 1.06 2.32 2.88 0 2.06-.83 2.88-2.32 2.88h-1.28V4.12zm8.79.58c-1.78 0-2.76 1.26-2.76 2.94v.5c0 1.75.97 2.97 2.76 2.97 1.79 0 2.75-1.22 2.75-2.97v-.5c0-1.68-.97-2.94-2.75-2.94zm0 1.04c.97 0 1.44.79 1.44 1.92v.47c0 1.12-.47 1.93-1.44 1.93s-1.45-.82-1.45-1.93v-.47c0-1.12.48-1.92 1.45-1.92zm3.9 2.41c0 1.74 1 2.96 2.68 2.96 1.44 0 2.34-.74 2.5-1.98h-1.23c-.09.48-.47.9-1.2.9-.88 0-1.44-.73-1.44-1.88v-.53c0-1.14.54-1.84 1.44-1.84.62 0 1.06.46 1.17.98h1.23C71.42 5.67 70.5 4.7 69 4.7c-1.68 0-2.67 1.2-2.67 2.9v.55zm6.24-1.53c0 1.13.92 1.51 2.05 1.75.83.17 1.55.27 1.55.92 0 .46-.38.85-1.2.85-.74 0-1.18-.34-1.25-.85h-1.26c0 1.11.93 1.82 2.42 1.82 1.56 0 2.56-.73 2.56-1.98 0-1.18-.9-1.53-2.06-1.74-.7-.13-1.56-.25-1.56-.9 0-.52.45-.82 1.11-.82.85 0 1.12.48 1.16.91h1.17c0-1.1-.83-1.88-2.3-1.88-1.24 0-2.39.58-2.39 1.92zM84.06 11V4.14h2.34V3h-6.02v1.14h2.35V11h1.32zm3.3 0h1.3V7.3c0-.8.44-1.46 1.36-1.46.77 0 1.35.45 1.35 1.45V11h1.29V7.02c0-1.51-.91-2.3-2.17-2.3-1.02 0-1.58.54-1.8.95h-.04V2.58h-1.3V11zm9.33.1c1.52 0 2.33-.88 2.52-1.88h-1.24c-.15.53-.6.86-1.27.86-.88 0-1.44-.7-1.44-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.72 2.93zm-1.43-3.8v-.02c0-.88.54-1.57 1.38-1.57.82 0 1.37.69 1.37 1.57v.01h-2.75zm5.41 3.7h1.3V7.17c0-.9.53-1.34 1.2-1.34.73 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.46-1.35 1.23-1.35.75 0 1.19.49 1.19 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.05-2.07-1.03 0-1.67.5-1.89 1.03h-.05c-.23-.62-.8-1.03-1.76-1.03-.88 0-1.42.49-1.6.93h-.06V4.8h-1.28V11zm12.77.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.6.86-1.27.86-.88 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.39-1.57.82 0 1.37.69 1.37 1.57v.01H112z"
/>
<path
className="theme-4"
fill="#000"
d="M53.09 11h3.13c1.67 0 2.79-.83 2.79-2.25 0-1.16-.75-1.85-1.76-1.96v-.06a1.7 1.7 0 001.32-1.76c0-1.22-.9-1.97-2.3-1.97H53.1v8zm1.32-6.94h1.6c.78 0 1.25.42 1.25 1.13 0 .8-.53 1.2-1.72 1.2H54.4V4.05zm0 3.32h1.7c.99 0 1.54.5 1.54 1.32 0 .85-.56 1.25-1.96 1.25H54.4V7.38zM60.34 11h1.3V2.58h-1.3V11zm5.5-6.3c-1.78 0-2.76 1.26-2.76 2.94v.5c0 1.75.97 2.97 2.76 2.97 1.79 0 2.75-1.22 2.75-2.97v-.5c0-1.68-.97-2.94-2.75-2.94zm0 1.04c.97 0 1.44.79 1.44 1.92v.47c0 1.12-.47 1.93-1.44 1.93s-1.45-.82-1.45-1.93v-.47c0-1.12.48-1.92 1.45-1.92zm6.69 6.53c-.75 0-1.24-.39-1.35-.85H69.9c.12 1.03.94 1.85 2.62 1.85 1.4 0 2.76-.72 2.76-2.36V4.8H74v.9h-.04c-.27-.55-.94-.99-1.79-.99-1.43 0-2.41 1.02-2.41 2.88v.44c0 1.88.99 2.89 2.41 2.89.86 0 1.52-.44 1.76-.98h.05v.9c0 .9-.56 1.42-1.45 1.42zm.02-6.48c.87 0 1.43.7 1.43 1.87v.37c0 1.18-.53 1.87-1.43 1.87-.92 0-1.47-.69-1.47-1.87v-.37c0-1.2.55-1.87 1.47-1.87zm9.7 5.21V4.14h2.36V3h-6.02v1.14h2.35V11h1.32zm3.3 0h1.3V7.3c0-.8.45-1.46 1.37-1.46.78 0 1.35.45 1.35 1.45V11h1.3V7.02c0-1.51-.92-2.3-2.18-2.3-1.01 0-1.57.54-1.79.95h-.04V2.58h-1.3V11zm9.34.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.61.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.38-1.57.83 0 1.37.69 1.37 1.57v.01h-2.75zm5.42 3.7h1.29V7.17c0-.9.54-1.34 1.21-1.34.72 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.45-1.35 1.22-1.35.76 0 1.2.49 1.2 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.06-2.07-1.02 0-1.67.5-1.88 1.03h-.06c-.22-.62-.8-1.03-1.75-1.03-.88 0-1.42.49-1.6.93h-.07V4.8h-1.28V11zm12.77.1c1.53 0 2.34-.88 2.52-1.88h-1.23c-.16.53-.61.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.64-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.7 2.93zm-1.43-3.8v-.02c0-.88.54-1.57 1.38-1.57.83 0 1.37.69 1.37 1.57v.01h-2.75z"
/>
<style jsx>{`
svg {
opacity: 0.8;
pointer-events: none;
}
.theme-1,
.theme-2,
.theme-3,
.theme-4 {
will-change: opacity, transform;
animation: switching 8s ease infinite;
}
.theme-2 {
animation-delay: -2s;
}
.theme-3 {
animation-delay: -4s;
}
.theme-4 {
animation-delay: -6s;
}
@keyframes switching {
0% {
opacity: 0;
transform: translate3d(-80%, 0, 0);
}
25% {
opacity: 0.2;
transform: translate3d(-40%, 0, 0);
}
50% {
opacity: 1;
transform: translate3d(0%, 0, 0);
}
75% {
opacity: 0.2;
transform: translate3d(40%, 0, 0);
}
100% {
opacity: 0;
transform: translate3d(80%, 0, 0);
}
}
.dash-ring {
animation: rotation 3s linear infinite;
}
@keyframes rotation {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -14;
}
}
`}</style>
</svg>
)
}
================================================
FILE: docs/app/_components/framer-motion.ts
================================================
'use client'
import { motion } from 'framer-motion'
export const MotionDiv = motion.div
export const MotionH3 = motion.h3
================================================
FILE: docs/app/_components/i18n-demo.tsx
================================================
'use client'
import { ArrowRightIcon } from '@components/icons'
import cn from 'clsx'
import type { FC } from 'react'
import { useState } from 'react'
import styles from '../page.module.css'
const LANGUAGES = [
{ lang: 'en', name: 'English' },
{ lang: 'de', name: 'Deutsch' },
{ lang: 'ja', name: '日本語' }
]
export const I18n: FC = () => {
const [active, setActive] = useState('')
return (
<div className={styles.comparison}>
<div style={{ display: 'flex', flexDirection: 'column', gap: '.5rem' }}>
{LANGUAGES.map(({ lang }) => (
<span
key={lang}
onPointerOver={() => setActive(lang)}
className={cn(styles.file, active === lang && styles.active)}
>
/{lang}/hello.mdx
</span>
))}
</div>
<ArrowRightIcon width="1.2em" />
<div className="overflow-auto rounded-md bg-white py-1 text-sm shadow-lg ring-1 ring-black/5 dark:bg-neutral-800 dark:ring-white/20">
{LANGUAGES.map(({ lang, name }) => (
<div
key={lang}
onPointerOver={() => setActive(lang)}
className={cn(
'relative cursor-default px-4 py-1.5 whitespace-nowrap select-none',
active === lang
? 'x:text-primary-600 x:bg-primary-50 x:dark:bg-primary-500/10'
: 'text-gray-800 dark:text-gray-100'
)}
>
{name}
</div>
))}
</div>
</div>
)
}
================================================
FILE: docs/app/_components/overview-page.tsx
================================================
import { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'
import type { PageMapItem } from 'nextra'
import { Cards } from 'nextra/components'
import { getIndexPageMap, getPageMap } from 'nextra/page-map'
import type { FC } from 'react'
export const OverviewPage: FC<{
filePath: string
icons?: Record<string, FC>
pageMap?: PageMapItem[]
}> = async ({ filePath, icons, pageMap: $pageMap }) => {
const { h2: H2 } = getMDXComponents()
const currentRoute = filePath.replace('app', '').replace('/page.mdx', '')
const pageMap = $pageMap ?? (await getPageMap(currentRoute))
return getIndexPageMap(pageMap).map((pageItem, index) => {
if (!Array.isArray(pageItem)) {
return <H2 key={index}>{pageItem.title}</H2>
}
return (
<Cards key={index}>
{pageItem.map(item => {
const icon = item.frontMatter?.icon
const Icon = icons?.[icon]
if (icon && !Icon) {
throw new Error(
`Icon "${icon}" is defined in front matter but isn't provided`
)
}
return (
// @ts-expect-error -- fixme
<Cards.Card
key={item.name}
// @ts-expect-error -- fixme
title={item.title}
// @ts-expect-error -- fixme
href={item.route || item.href}
icon={Icon && <Icon />}
/>
)
})}
</Cards>
)
})
}
================================================
FILE: docs/app/_meta.global.tsx
================================================
import type { MetaRecord } from 'nextra'
import { LinkArrowIcon } from 'nextra/icons'
import type { FC, ReactNode } from 'react'
import { useMDXComponents } from '../mdx-components'
// eslint-disable-next-line react-hooks/rules-of-hooks -- isn't react hook
const { code: Code } = useMDXComponents()
const ExternalLink: FC<{ children: ReactNode }> = ({ children }) => {
return (
<>
{children} 
<LinkArrowIcon
// based on font-size
height="1em"
className="x:inline x:align-baseline x:shrink-0"
/>
</>
)
}
const FILE_CONVENTIONS: MetaRecord = {
_: {
type: 'separator',
title: 'Files'
},
'page-file': 'page.mdx',
'meta-file': '_meta.js',
_2: {
href: 'https://nextjs.org/docs/app/api-reference/file-conventions/page',
title: <ExternalLink>page.jsx</ExternalLink>
},
_3: {
href: 'https://nextjs.org/docs/app/api-reference/file-conventions/layout',
title: <ExternalLink>layout.jsx</ExternalLink>
},
_4: {
type: 'separator',
title: 'Top-Level Files'
},
'mdx-components-file': 'mdx-components.js',
_5: {
type: 'separator',
title: 'Top-Level Folders'
},
'content-directory': 'content',
'src-directory': 'src',
_6: {
href: 'https://nextjs.org/docs/app/getting-started/installation?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar#create-the-app-directory',
title: <ExternalLink>app</ExternalLink>
},
_7: {
href: 'https://nextjs.org/docs/app/building-your-application/optimizing/static-assets?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar',
title: <ExternalLink>public</ExternalLink>
}
}
const GUIDE: MetaRecord = {
markdown: '',
'syntax-highlighting': '',
link: '',
image: '',
ssg: '',
i18n: '',
'custom-css': '',
'static-exports': '',
search: {
items: {
index: '',
ai: {
title: <span className="badge-new">Ask AI</span>
}
},
theme: {
collapsed: false
}
},
'github-alert-syntax': '',
turbopack: '',
_: {
title: 'Deploying',
href: 'https://nextjs.org/docs/app/building-your-application/deploying?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar'
}
}
const ADVANCED: MetaRecord = {
npm2yarn: '',
mermaid: '',
'tailwind-css': '',
latex: '',
table: '',
typescript: '',
remote: ''
}
const BLOG_THEME: MetaRecord = {
start: '',
'get-posts-and-tags': '',
// prettier-ignore
posts: <><Code>/posts</Code> Page</>,
// prettier-ignore
tags: <><Code>/tags/:id</Code> Page</>,
// prettier-ignore
rss: <><Code>/rss.xml</Code> Route</>
}
export default {
index: {
type: 'page',
display: 'hidden'
},
docs: {
type: 'page',
title: 'Documentation',
items: {
index: '',
'file-conventions': { items: FILE_CONVENTIONS },
guide: { items: GUIDE },
advanced: { items: ADVANCED },
'built-ins': '',
_: {
type: 'separator',
title: 'Themes'
},
'docs-theme': {
items: {
start: '',
'built-ins': {
items: {
layout: ''
}
}
}
},
'blog-theme': { items: BLOG_THEME },
'custom-theme': '',
__: {
type: 'separator',
title: 'More'
},
'about-link': {
title: 'About Nextra',
href: '/about'
},
'next.js-link': {
title: 'Next.js Docs',
href: 'https://nextjs.org?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar'
},
'migration-from-v3': {
title: 'Migration from Nextra v3',
href: 'https://the-guild.dev/blog/nextra-4?utm_source=nextra.site&utm_campaign=sidebar&utm_content=sidebar_link#nextra-theme-docs-changes'
}
}
},
api: {
type: 'page'
},
versions: {
type: 'menu',
title: 'Versions',
items: {
_3: {
title: 'Nextra v3 Docs',
href: 'https://nextra-v2-7hslbun8z-shud.vercel.app'
},
_2: {
title: 'Nextra v2 Docs',
href: 'https://nextra-v2-oe0zrpzjp-shud.vercel.app'
}
}
},
blog: {
type: 'page',
theme: {
typesetting: 'article',
toc: false
}
},
about: {
type: 'page',
theme: {
typesetting: 'article'
}
},
showcase: {
type: 'page',
theme: {
copyPage: false,
typesetting: 'article',
layout: 'full',
timestamp: false,
toc: false
}
},
sponsors: {
type: 'page',
theme: {
copyPage: false,
typesetting: 'article',
layout: 'full',
timestamp: false,
toc: false
}
}
}
================================================
FILE: docs/app/about/page.mdx
================================================
---
sidebarTitle: About
description:
Learn about Nextra's history, team, and contributors, and explore how
open-source technologies power Nextra's features.
---
import { Image } from 'nextra/components'
import { cloneElement } from 'react'
export default function MdxLayout(props) {
return cloneElement(props.children, {
components: {
img: props => <Image {...props} className="inline" />
}
})
}
# About Nextra
Nextra was initially created by [Vercel](https://vercel.com) members
[Shu Ding](https://twitter.com/shuding_) and
[Paco Coursey](https://twitter.com/pacocoursey) in 2020. Since 2021,
[Yixuan Xu](https://twitter.com/yixuanxu94) contributed tremendously to the
project.
In 2022, [Dimitri Postolov](https://twitter.com/dimaMachina_) from
[The Guild](https://the-guild.dev) joined the core team to help with the
development of Nextra 2.
In 2024 Nextra 3 was released, current primary maintainer Dimitri Postolov fully
developed it, and [Oscar Xie](https://github.com/87xie)
[actively contributed](https://github.com/shuding/nextra/pulls?q=sort%3Aupdated-desc+is%3Apr+author%3A87xie+is%3Aclosed+created%3A%3C2024-10-03)
to this release.
In 2025 Nextra 4 with [App Router](https://nextjs.org/docs/app) support was
released, Dimitri Postolov fully developed it too.
## Team
Currently, the project is maintained by Dimitri Postolov. You can check out
[the full list of contributors](https://github.com/shuding/nextra/graphs/contributors)
on GitHub.
## Credits
Nextra is powered by these incredible open source projects:
- https://reactjs.org
- https://nextjs.org
- https://turbo.build
- https://mdxjs.com
- https://pnpm.io
- https://tailwindcss.com
- https://github.com/pacocoursey/next-themes
- https://github.com/shikijs/shiki
- https://github.com/cloudcannon/pagefind
- https://github.com/atomiks/rehype-pretty-code
- https://github.com/Brooooooklyn/simple-git
- https://github.com/francoismassart/eslint-plugin-tailwindcss
## Design assets
Feel free to use the Nextra logo and other assets in your project. But please
don't modify the logo, and don't use the logo to represent your project or
product.
| Name | Description | Preview |
| :---------: | :----------------------------------------------: | :-----------------------------------: |
| Icon | Useful for favicons, app icons, link icons, etc. |  |
| Logo | Full Nextra logo |  |
| Social Card | The Nextra social card |  |
## License
The Nextra project and themes are licensed under
[the MIT license](https://github.com/shuding/nextra/blob/main/LICENSE).
================================================
FILE: docs/app/api/[name]/page.tsx
================================================
import path from 'node:path'
import { generateApiReference } from '@components/generate-api-reference'
import type { ApiReference } from '@components/generate-api-reference'
import { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'
import type { MdxFile } from 'nextra'
import { generateDefinition } from 'nextra/tsdoc'
import type { FC } from 'react'
type AllApiReference = ApiReference & { filePath?: string }
const API_REFERENCE: (
| AllApiReference
| { type: 'separator'; title: string; name: string }
)[] = [
{ type: 'separator', title: 'Types', name: '_' },
{
name: 'NextraConfig',
packageName: 'nextra',
isFlattened: false,
filePath: 'packages/nextra/src/server/schemas.ts'
},
{
name: 'MdxOptions',
code: `import type { NextraConfig } from 'nextra'
type $ = NonNullable<NextraConfig['mdxOptions']>
export default $`,
isFlattened: false,
filePath: 'packages/nextra/src/server/schemas.ts'
},
{ type: 'separator', title: 'Functions', name: '_2' },
{
name: 'nextra',
code: "export { default } from 'nextra'",
isFlattened: false
},
{
name: 'useMDXComponents',
packageName: 'nextra/mdx-components',
isFlattened: false
},
{ name: 'getPageMap', packageName: 'nextra/page-map' },
{ name: 'generateStaticParamsFor', packageName: 'nextra/pages' },
{ name: 'importPage', packageName: 'nextra/pages' },
{ name: 'compileMdx', packageName: 'nextra/compile' },
{ name: 'generateDefinition', packageName: 'nextra/tsdoc' },
{ name: 'proxy', packageName: 'nextra/locales' },
{ name: 'evaluate', packageName: 'nextra/evaluate' },
{ name: 'normalizePages', packageName: 'nextra/normalize-pages' }
]
const routes = API_REFERENCE.filter((o): o is AllApiReference => !('type' in o))
const separatorIndex = API_REFERENCE.findIndex(
o => 'title' in o && o.title === 'Functions'
)
const functionsIndex = routes.indexOf(
API_REFERENCE[separatorIndex + 1] as AllApiReference
)
export const generateStaticParams = () =>
routes.map(o => ({ name: o.name.toLowerCase() }))
// @ts-expect-error -- fixme
export const pageMap: (MdxFile & { title: string })[] = API_REFERENCE.map(o =>
'type' in o
? o
: {
name: o.name.toLowerCase(),
route: `/api/${o.name.toLowerCase()}`,
title: o.name
}
)
const Wrapper = getMDXComponents().wrapper
async function getReference(props: PageProps) {
const params = await props.params
const apiRefIndex = routes.findIndex(
o => o.name.toLowerCase() === params.name
)
const apiRef = routes[apiRefIndex]
if (!apiRef) {
throw new Error(`API reference not found for "${params.name}"`)
}
const isType = functionsIndex > apiRefIndex
const definition = generateDefinition({
code:
apiRef.code ??
`export { ${apiRef.name} as default } from '${apiRef.packageName}'`,
flattened: apiRef.isFlattened !== false
})
const result = await generateApiReference(apiRef, {
title: isType ? 'Type' : 'Function',
subtitle: isType ? 'Fields' : 'Signature',
definition
})
const filePath =
definition.filePath &&
path
.relative('..', definition.filePath)
.replace(/\.d.ts$/, '.ts')
.replace('/dist/', '/src/')
// Add edit on GitHub link to points on a source file
result.metadata.filePath = `https://github.com/shuding/nextra/tree/main/${apiRef.filePath ?? filePath}`
return result
}
export async function generateMetadata(props: PageProps) {
const { metadata } = await getReference(props)
return metadata
}
type PageProps = Readonly<{
params: Promise<{ name: string }>
}>
const Page: FC<PageProps> = async props => {
const {
default: MDXContent,
toc,
metadata,
sourceCode
} = await getReference(props)
return (
<Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>
<MDXContent />
</Wrapper>
)
}
export default Page
================================================
FILE: docs/app/api/page.mdx
================================================
import { Callout, Cards } from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
import { createIndexPage } from 'nextra/page-map'
import { pageMap } from './[name]/page'
# API
<Callout type="info">
This API reference is automatically generated from the catch-all route file
`/api/[name]/page.tsx` using the new [Nextra `<TSDoc />`
component](/docs/built-ins/tsdoc).
</Callout>
<MDXRemote
compiledSource={await createIndexPage(pageMap)}
components={{
Cards
}}
/>
================================================
FILE: docs/app/blog/page.mdx
================================================
---
asIndexPage: true
description:
Stay updated with the latest news and updates from the Nextra team, including
new releases, features, and community highlights.
---
import { Link } from 'nextra-theme-docs'
# Blog
<BlogPage />
export function BlogPage() {
return [
{
route:
'https://the-guild.dev/blog/nextra-4?utm_source=nextra.site&utm_campaign=blog_page&utm_content=blog_link',
title: 'Nextra 4',
description:
'App Router support, Turbopack support, compiled by React Compiler, new Rust-powered search Pagefind, RSC i18n, server/client components, smallest bundle size EVER for a Nextra-powered website, GitHub Alert Syntax, new _meta.global file and more.',
date: '2024-01-13'
},
{
route:
'https://the-guild.dev/blog/nextra-3?utm_source=nextra.site&utm_campaign=blog_page&utm_content=blog_link',
title: 'Nextra 3 – Your Favourite MDX Framework, Now on 🧪 Steroids',
description:
'MDX 3, new i18n, new _meta files with JSX support, more powerful TOC, remote MDX, better bundle size, MathJax, new code block styles, shikiji, ESM-only and more.',
date: '2023-12-12'
},
{
route:
'https://the-guild.dev/blog/nextra-2?utm_source=nextra.site&utm_campaign=blog_page&utm_content=blog_link',
title: 'Nextra 2 – Next.js Static Site Generator',
description:
'Here are what the new version of Nextra 2 Framework includes.',
date: '2023-01-24'
}
].map(page => (
<div key={page.route} className="mt-12">
<h3 className="text-2xl font-semibold">{page.title}</h3>
<p className="my-6 leading-7 opacity-80">
{page.description}{' '}
{page.date && <Link href={page.route}>Read more</Link>}
</p>
{page.date ? (
<time
dateTime={new Date(page.date).toISOString()}
className="text-sm opacity-50"
>
{new Date(page.date).toLocaleDateString('en', {
month: 'long',
day: 'numeric',
year: 'numeric'
})}
</time>
) : (
<span className="text-sm opacity-50">Coming soon!</span>
)}
</div>
))
}
================================================
FILE: docs/app/docs/advanced/customize-the-cascade-layers/page.mdx
================================================
---
sidebarTitle: Customize Cascade Layers
---
import { Steps } from 'nextra/components'
# Customize the Cascade Layers
In some scenarios, you may need more control over the Nextra predefined CSS to
avoid unintended overrides of styles within cascade layers. Below is an example
of how `nextra-theme-docs` uses
[postcss-import](https://github.com/postcss/postcss-import) to place predefined
CSS into a specified cascade layer:
<Steps>
## Install `postcss-import`
Install `postcss-import` and add it to `postcss.config.mjs`:
```js filename="postcss.config.mjs"
export default {
plugins: {
'postcss-import': {}
// ... your other PostCSS plugins (e.g., `autoprefixer`, `cssnano`)
}
}
```
## Set up the cascade layers
In your CSS file (e.g. `styles.css`), import the `nextra-docs-theme` CSS and
specify the layers:
```css filename="styles.css"
@layer nextra, my-base;
@import 'nextra-theme-docs/dist/style.css' layer(nextra);
@layer my-base {
/* my base styles */
}
```
## Import your CSS file
Import your CSS file at the top-level layout of your application (e.g.
`app/layout.jsx`) to apply the styles.
```jsx filename="app/layout.jsx"
import '../path/to/your/styles.css'
export default async function RootLayout({ children }) {
// ... Your layout logic here
}
```
</Steps>
================================================
FILE: docs/app/docs/advanced/latex/page.mdx
================================================
---
icon: FormulaIcon
---
import { compileMdx } from 'nextra/compile'
import {
Callout,
MathJax,
MathJaxContext,
Steps,
Tabs
} from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
{/* <link rel="stylesheet"> is unsupported in Metadata API https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata */}
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/katex/dist/katex.css"
/>
# LaTeX
Nextra can use [KaTeX](https://katex.org) to pre-render LaTeX expressions
directly in MDX or [MathJax](https://mathjax.org) to dynamically render math in
the browser.
## Setup
<Steps>
### Enable the `latex` option
By default, LaTeX is disabled. To enable it, you need to set the `latex` option
in your `next.config.mjs` file:
```js filename="next.config.mjs" {4}
import nextra from 'nextra'
const withNextra = nextra({
latex: true
})
export default withNextra()
```
A value of `true{:js}` will use KaTeX as the math renderer. To explicitly
specify the renderer, you may instead provide an object
`{ renderer: 'katex' }{:js}` or `{ renderer: 'mathjax' }{:js}` as the value to
`latex: ...`.
When enabled, the required CSS and fonts will be automatically included in your
site, and you can start writing math expressions by enclosing inline math in
`$...$` or display math in a `math`-labeled fenced code block:
````mdx
```math
\int x^2
```
````
### Apply styles
<Callout type="warning">
This is applicable only to KaTeX as the math renderer.
</Callout>
<Tabs items={['Import CSS from `katex` package', 'Load CSS from CDN']}>
<Tabs.Tab>
1. Install the `katex` package
```bash npm2yarn
npm i katex
```
2. Import CSS in the root layout
```js filename="app/layout.jsx"
import 'katex/dist/katex.min.css'
```
</Tabs.Tab>
<Tabs.Tab>
Add `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex/dist/katex.css" />{:jsx}`
inside `<head>` element in your root `layout` file since `<link rel="stylesheet" />{:jsx}`
[isn't supported with Next.js Metadata API](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata).
Alternatively, you can include `<link rel="stylesheet" />{:jsx}` directly in
your MDX file:
````mdx filename="katex.mdx"
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/katex/dist/katex.css"
/>
# My page with single usage of KaTeX
```math
\int_2^3x^3\,\mathrm{d}x
```
````
</Tabs.Tab>
</Tabs>
</Steps>
## Example
For example, the following Markdown code:
````md filename="page.md"
The **Pythagorean equation** is $a=\sqrt{b^2 + c^2}$ and the quadratic formula:
```math
x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}
```
````
will be rendered as:
<div className="mt-6 rounded-xl border p-4 nextra-border">
The **Pythagorean equation** is $a=\sqrt{b^2 + c^2}$ and the quadratic formula:
```math
x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}
```
</div>
You can still use [Markdown and MDX syntax](../guide/markdown) in the same line
as your LaTeX expression.
> [!TIP]
>
> If you want to display `$` in your content instead of rendering it as an
> equation, you can escape it with a backslash (`\`). For example `\$e = mc^2\$`
> will be rendered as \$e = mc^2\$.
## API
### KaTeX
`rehype-katex` is used to pre-render LaTeX expressions in your content. You can
pass supported [KaTeX options](https://katex.org/docs/options) via the `options`
key in your Nextra config. For example, to add a macro `\RR` that renders as
`\mathbb{R}` you could use the following configuration.
```js filename="next.config.mjs" {4-8}
const withNextra = nextra({
latex: {
renderer: 'katex',
options: {
macros: {
'\\RR': '\\mathbb{R}'
}
}
}
})
```
See [KaTeX's documentation](https://katex.org/docs/supported) for a list of
supported commands.
### MathJax
When MathJax is enabled (by setting `latex: { renderer: 'mathjax' }{:js}`) math
is rendered on page load via
[`better-react-mathjax`](https://github.com/fast-reflexes/better-react-mathjax)
instead of being pre-rendered. By default, **MathJax is served via the MathJax
CDN** instead of the files being directly included in your site.[^1]
[^1]:
This can be changed by setting
[`{ options: { src: ... } }{:js}`](https://github.com/fast-reflexes/better-react-mathjax#src-string--undefined)
in the Nextra config.
MathJax rendering is enabled by setting `renderer: 'mathjax'{:js}` in your
Nextra config.
```js filename="next.config.mjs" {3}
const withNextra = nextra({
latex: {
renderer: 'mathjax'
}
})
```
You can pass additional options to `better-react-mathjax` via the `options` key
in your Nextra config. The `config: ...` option sets the
[MathJax configuration](https://docs.mathjax.org/en/latest/options/index.html).
However, note that you can only pass serializable options to
`better-react-mathjax` via the `options` key in your Nextra config.[^2]
[^2]:
To pass non-serializable objects like Functions, you must use the
`<MathJaxContext config={...} />{:jsx}` component directly in your source.
For example, to configure MathJax to render `\RR` as `\mathbb{R}` you could use
the following configuration.
```js filename="next.config.mjs" {4-12}
const withNextra = nextra({
latex: {
renderer: 'mathjax',
options: {
config: {
tex: {
macros: {
RR: '\\mathbb{R}'
}
}
}
}
}
})
```
#### MathJax CDN
By default, MathJax is served via the MathJax CDN. To serve files from another
location (including locally in your project), you must pass the `src: ...`
option to the latex config. See the
[better-react-mathjax documentation](https://github.com/fast-reflexes/better-react-mathjax#src-string--undefined)
for details about the `src` option. Additionally, you may need to copy the
MathJax distribution into your `/public` folder for it to be served locally.
## KaTeX vs. MathJax
With KaTeX, math is pre-rendered which means flicker-free and faster page loads.
However, KaTeX does not support all the features of MathJax, especially features
related to accessibility.
The following two examples show the same formula rendered with KaTeX (first) and
MathJax (second).
```math
\int_2^3x^3\,\mathrm{d}x
```
<MathJaxExample />
Because of MathJax's accessibility features, the second formula is
tab-accessible and has a context menu that helps screen readers reprocess math
for the visually impaired.
export async function MathJaxExample() {
const rawMdx = `~~~math
\\int_2^3x^3\\,\\mathrm{d}x
~~~`
const rawJs = await compileMdx(rawMdx, {
latex: {
renderer: 'mathjax',
options: {
config: {
tex: {
macros: {
RR: '\\mathbb{R}'
}
}
}
}
}
})
return (
<MDXRemote
compiledSource={rawJs}
components={{ MathJax, MathJaxContext }}
/>
)
}
================================================
FILE: docs/app/docs/advanced/mermaid/page.mdx
================================================
---
icon: DiagramIcon
---
import { compileMdx } from 'nextra/compile'
import { Mermaid } from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
# Mermaid
Nextra supports [mermaid](https://mermaid.js.org) diagrams. Like in GitHub you
can use it in your Markdown files by using the `mermaid` code block language.
Out of the box, Nextra uses
[`@theguild/remark-mermaid`](https://npmjs.com/package/@theguild/remark-mermaid)
package that replaces the code block with the `<Mermaid>` component.
## Example
<Demo />
export async function Demo() {
const mermaidCodeblock = `\`\`\`mermaid
graph TD;
subgraph AA [Consumers]
A[Mobile app];
B[Web app];
C[Node.js client];
end
subgraph BB [Services]
E[REST API];
F[GraphQL API];
G[SOAP API];
end
Z[GraphQL API];
A --> Z;
B --> Z;
C --> Z;
Z --> E;
Z --> F;
Z --> G;
\`\`\``
const rawJs = await compileMdx(`${mermaidCodeblock}
## Usage
~~~md filename="Markdown"
${mermaidCodeblock}
~~~
`)
return <MDXRemote compiledSource={rawJs} components={{ Mermaid }} />
}
================================================
FILE: docs/app/docs/advanced/npm2yarn/page.mdx
================================================
---
icon: TerminalIcon
---
import { compileMdx } from 'nextra/compile'
import { Tabs } from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
# Npm2Yarn
Nextra uses
[`@theguild/remark-npm2yarn`](https://npmjs.com/package/@theguild/remark-npm2yarn)
package that replaces the code block that has `npm2yarn` metadata with
[`<Tabs>` and `<Tabs.Tab>` components](/docs/built-ins/tabs) from
`nextra/components`.
The chosen tab is saved in the local storage, which will be chosen in future
page renders.
## Example
<Page />
export async function Page() {
const codeBlock = `\`\`\`sh npm2yarn
npm i -D @graphql-eslint/eslint-plugin
\`\`\``
const rawJs = await compileMdx(`${codeBlock}
## Usage
~~~md filename="Markdown" /npm2yarn/
${codeBlock}
~~~`)
return <MDXRemote compiledSource={rawJs} components={{ $Tabs: Tabs }} />
}
================================================
FILE: docs/app/docs/advanced/page.mdx
================================================
---
asIndexPage: true
---
import {
CloudIcon,
DiagramIcon,
FormulaIcon,
TableIcon,
TailwindIcon
} from '@components/icons'
import { TerminalIcon, TypeScriptIcon } from 'nextra/icons'
import { OverviewPage } from '../../_components/overview-page'
# Advanced
<OverviewPage
filePath={metadata.filePath}
icons={{
TerminalIcon,
DiagramIcon,
TailwindIcon,
FormulaIcon,
TableIcon,
TypeScriptIcon,
CloudIcon
}}
/>
================================================
FILE: docs/app/docs/advanced/remote/page.mdx
================================================
---
icon: CloudIcon
---
import fs from 'node:fs/promises'
import { compileMdx } from 'nextra/compile'
import { Steps } from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
export async function Example() {
const filename = '/graphql-eslint/[[...slug]]/page.tsx'
const pageContent = await fs.readFile(
`../examples/swr-site/app/[lang]/${filename}`,
'utf8'
)
const rawJs = await compileMdx(
`~~~jsx filename="app${filename}" {27} showLineNumbers
${pageContent
.replace(
"lang: 'en',\n ...(route && { slug: route.split('/') })",
"slug: route.split('/')"
)
.trimEnd()}
~~~`,
{ defaultShowCopyCode: true }
)
return <MDXRemote compiledSource={rawJs} />
}
# Remote Content
> [!NOTE]
>
> You can check out the
> [SWR i18n example](https://github.com/shuding/nextra/blob/main/examples/swr-site/app/%5Blang%5D/graphql-eslint/%5B%5B...slug%5D%5D/page.tsx)
> source code.
<Steps>
## Create `[[...slug]]/page.tsx` file
Create `[[...slug]]/page.tsx` file in `app/` directory with the following
content:
<Example />
## Enhance `pageMap`
You need to modify `pageMap` list in `layout` file, to properly display sidebar
and mobile navigation.
```tsx filename="app/layout.tsx"
import { getPageMap } from 'nextra/page-map'
import { pageMap as graphqlEslintPageMap } from './graphql-eslint/[[...slug]]/page'
// ...
const pageMap = [...(await getPageMap()), graphqlEslintPageMap]
```
</Steps>
================================================
FILE: docs/app/docs/advanced/table/page.mdx
================================================
---
icon: TableIcon
---
# Rendering Tables
This guide covers different ways to render tables in MDX, including GFM syntax
and literal HTML tag.
## GFM syntax
In Markdown, it is preferable to write tables via
[GFM syntax](https://github.github.com/gfm/#tables-extension-).
```mdx filename="MDX"
| left | center | right |
| :----- | :----: | ----: |
| foo | bar | baz |
| banana | apple | kiwi |
```
will be rendered as:
| left | center | right |
| :----- | :----: | ----: |
| foo | bar | baz |
| banana | apple | kiwi |
## Literal HTML tables
If you try to render table with literal HTML elements `<table>{:js}`,
`<thead>{:js}`, `<tbody>{:js}`, `<tr>{:js}`, `<th>{:js}` and `<td>{:js}` – your
table will be unstyled because
[MDX](https://mdxjs.com/docs/using-mdx/#components) doesn't replace literal HTML
elements with components provided by `useMDXComponents(){:js}`[^1].
> [!TIP]
>
> Instead, use the [built-in `<Table>` component](/docs/built-ins/table)
> available via `nextra/components`.
## Changing default behaviour
If you want to use standard HTML elements for your tables but have them styled
with components provided by `useMDXComponents(){:js}`[^1], you can do this by
configuring Nextra.
To achieve this, pass the `whiteListTagsStyling` option to the Nextra function,
including an array of tags you want to replace.
Here's an example configuration in your `next.config.mjs` file:
```js filename="next.config.mjs" {4}
import nextra from 'nextra'
const withNextra = nextra({
whiteListTagsStyling: ['table', 'thead', 'tbody', 'tr', 'th', 'td']
})
export default withNextra()
```
In this example, the tags `<table>`, `<thead>`, `<tbody>`, `<tr>`, `<th>`, and
`<td>` will be replaced with corresponding MDX components, allowing for
customized styling.
[^1]: https://mdxjs.com/packages/react/#usemdxcomponentscomponents
================================================
FILE: docs/app/docs/advanced/tailwind-css/page.mdx
================================================
---
icon: TailwindIcon
---
import { Steps } from 'nextra/components'
# Tailwind CSS
Tailwind CSS is a CSS framework that provides a set of pre-defined CSS classes
to quickly style elements.
<Steps>
## Follow the official guide
Follow the official
[Tailwind CSS guide for Next.js](https://tailwindcss.com/docs/guides/nextjs) to
set up Tailwind CSS for your project.
## Create the `globals.css` file
Import Tailwind CSS into `globals.css`:
```css filename="globals.css"
@import 'tailwindcss';
/* Optional: import Nextra theme styles */
@import 'nextra-theme-docs/style.css'; /* or nextra-theme-blog/style.css */
@variant dark (&:where(.dark *));
```
## Import styles in the root layout
To apply the styles globally, import the `globals.css` file in your root layout
file:
```jsx filename="app/layout.jsx"
import '../path/to/your/globals.css'
export default async function RootLayout({ children }) {
// ... Your layout logic here
}
```
</Steps>
================================================
FILE: docs/app/docs/advanced/twoslash/page.mdx
================================================
# Twoslash Support
Twoslash provides an inline type hove inside the code block.
## Basic usage
You can enable twoslash to your code blocks by adding a `twoslash` metadata:
{/* prettier-ignore */}
````md copy=false filename="Markdown"
```ts twoslash
// @errors: 2540
interface Todo {
title: string
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users'.toUpperCase()
// ^?
}
todo.title = 'Hello'
Number.parseInt('123', 10)
// ^|
// Just comments, so Popup will be
// not behind the viewport of `<code>`
// element due his `position: absolute` style
//
```
````
Renders:
{/* prettier-ignore */}
```ts twoslash
// @errors: 2540
interface Todo {
title: string
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users'.toUpperCase()
// ^?
}
todo.title = 'Hello'
Number.parseInt('123', 10)
// ^|
```
## Custom log message
You can add log message to your code by adding:
- `@log: <message>` Custom log message
- `@error: <message>` Custom error message
- `@warn: <message>` Custom warn message
- `@annotate: <message>` Custom annotate message
```ts twoslash
// @log: Custom log message
const a = 1
// @error: Custom error message
const b = 1
// @warn: Custom warning message
const c = 1
// @annotate: Custom annotation message
```
================================================
FILE: docs/app/docs/advanced/typescript/page.mdx
================================================
---
icon: TypeScriptIcon
---
import { Steps } from 'nextra/components'
# TypeScript
Nextra is built with TypeScript and provides excellent TypeScript support out of
the box. This guide will help you leverage TypeScript in your Nextra project.
## Getting started
To use TypeScript in your Nextra project, you need to:
<Steps>
### Install TypeScript and types packages as `devDependencies`
```sh npm2yarn
npm i -D typescript @types/react @types/node
```
### `tsconfig.json`
You can manually create a `tsconfig.json` file in the root of your project or
rename the extension of some of the existing files to `.ts` or `.tsx` and then
Next.js will detect TypeScript in your project and create a `tsconfig.json` file
for you.
</Steps>
## Type definitions
Nextra provides type definitions for distribution code for its components and
configurations. You can leverage these types by renaming your theme
configuration file to `.ts` or `.tsx` extension and importing a theme config
type, e.g. for `nextra-theme-docs`:
```tsx filename="theme.config.tsx"
import type { DocsThemeConfig } from 'nextra-theme-docs'
const config: DocsThemeConfig = {
// Your theme configuration
}
export default config
```
By leveraging TypeScript in your Nextra project, you can catch errors early,
improve code quality, and enhance the developer experience with better
autocompletion and type inference.
================================================
FILE: docs/app/docs/blog-theme/get-posts-and-tags/page.mdx
================================================
---
icon: FilesIcon
---
import { ExampleCode } from 'components/example-code'
# Get Posts and Their Tags
The following code snippet demonstrates how to retrieve all posts along with
their associated tags.
<ExampleCode
example="blog"
filePath="app/posts/get-posts.js"
metadata="/getPageMap/"
/>
================================================
FILE: docs/app/docs/blog-theme/page.mdx
================================================
---
asIndexPage: true
sidebarTitle: Blog Theme
---
import {
ChevronRightIcon,
FilesIcon,
RSSIcon,
TagsIcon
} from '@components/icons'
import { FileIcon } from 'nextra/icons'
import { OverviewPage } from '../../_components/overview-page'
# Nextra Blog Theme
<OverviewPage
filePath={metadata.filePath}
icons={{
ChevronRightIcon,
FilesIcon,
FileIcon,
TagsIcon,
RSSIcon
}}
/>
================================================
FILE: docs/app/docs/blog-theme/posts/page.mdx
================================================
---
icon: FileIcon
---
import { ExampleCode } from 'components/example-code'
# Posts Page
The following code snippet demonstrates how to create `/posts` page.
<ExampleCode
example="blog"
filePath="app/posts/page.jsx"
metadata="/getPosts/ /getTags/"
/>
================================================
FILE: docs/app/docs/blog-theme/rss/page.mdx
================================================
---
icon: RSSIcon
---
import { ExampleCode } from 'components/example-code'
# Generate RSS feed
The following code snippet demonstrates how to create `/rss.xml` route.
<ExampleCode
example="blog"
filePath="app/rss.xml/route.js"
metadata="/getPosts/"
/>
================================================
FILE: docs/app/docs/blog-theme/start/page.mdx
================================================
---
icon: ChevronRightIcon
---
import InstallNextraTheme from '@components/install-nextra-theme.mdx'
import ReadyToGo from '@components/ready-to-go.mdx'
import { ExampleCode } from '@components/example-code'
import { Steps } from 'nextra/components'
# Get Started
> [!NOTE]
>
> An example of the blog theme can be found [here](https://demo.vercel.blog),
> with source code [here](https://github.com/shuding/nextra/tree/main/examples/blog).
Similar to the [Docs Theme](/docs/docs-theme/start), you can install the blog
theme with the following commands:
## Start as a new project
<Steps>
### Install
To create a Nextra Blog site manually, you have to install **Next.js**,
**React**, **Nextra**, and **Nextra Blog Theme**. In your project directory, run
the following command to install the dependencies:
```sh npm2yarn
npm i next react react-dom nextra nextra-theme-blog
```
> [!NOTE]
>
> If you already have Next.js installed in your project, you only need to
> install `nextra` and `nextra-theme-blog` as the add-ons.
<InstallNextraTheme />
<ExampleCode example="blog" filePath="app/layout.jsx" />
{/*
### Create Blog Theme Config
Lastly, create the corresponding `theme.config.jsx` file in your project's root
directory. This will be used to configure the Nextra Blog theme:
```jsx filename="theme.config.jsx"
export default {
footer: <p>MIT 2023 © Nextra.</p>,
head: ({ title, meta }) => (
<>
{meta.description && (
<meta name="description" content={meta.description} />
)}
{meta.tag && <meta name="keywords" content={meta.tag} />}
{meta.author && <meta name="author" content={meta.author} />}
</>
),
readMore: 'Read More →',
postFooter: null,
darkMode: false,
navs: [
{
url: 'https://github.com/shuding/nextra',
name: 'Nextra'
}
]
}
```
*/}
<ReadyToGo />
</Steps>
## Layout Props
<APIDocs
componentName="Layout"
packageName="../packages/nextra-theme-blog"
/>
================================================
FILE: docs/app/docs/blog-theme/tags/page.mdx
================================================
---
icon: TagsIcon
---
import { ExampleCode } from 'components/example-code'
# Tags Page
The following code snippet demonstrates how to create `/tags/:id` pages.
<ExampleCode
example="blog"
filePath="app/tags/[tag]/page.jsx"
metadata="/getPosts/ /getTags/"
/>
================================================
FILE: docs/app/docs/built-ins/[name]/page.tsx
================================================
import path from 'node:path'
import { generateApiReference } from '@components/generate-api-reference'
import type { ApiReference } from '@components/generate-api-reference'
import { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'
import type { MdxFile } from 'nextra'
import { generateDefinition } from 'nextra/tsdoc'
import type { FC } from 'react'
type ComponentApiReference = ApiReference & { groupKeys?: string }
const API_REFERENCE: (
| ComponentApiReference
| { type: 'separator'; title: string; name: string }
)[] = [
{ type: 'separator', title: 'Layout Components', name: '_' },
{
name: 'Banner',
packageName: 'nextra/components',
groupKeys: 'HTMLAttributes<HTMLDivElement>'
},
{
name: 'Head',
packageName: 'nextra/components',
isFlattened: true
},
{
name: 'Search',
packageName: 'nextra/components',
isFlattened: false,
groupKeys:
"Omit<ComboboxInputProps, 'className' | 'onChange' | 'onFocus' | 'onBlur' | 'value' | 'placeholder'>"
},
{ type: 'separator', title: 'Content Components', name: '_2' },
{
name: 'Bleed',
packageName: 'nextra/components',
groupKeys: 'HTMLAttributes<HTMLDivElement>'
},
{
name: 'Callout',
packageName: 'nextra/components',
groupKeys: 'HTMLAttributes<HTMLDivElement>'
},
{
// TODO: add
// <APIDocs componentName="Cards.Card" />
name: 'Cards',
packageName: 'nextra/components',
groupKeys: 'HTMLAttributes<HTMLDivElement>'
},
{
// TODO: add
// <APIDocs componentName="FileTree.Folder" />
// <APIDocs componentName="FileTree.File" />
name: 'FileTree',
packageName: 'nextra/components',
groupKeys: 'HTMLAttributes<HTMLUListElement>'
},
{
name: 'Steps',
packageName: 'nextra/components',
groupKeys: 'HTMLAttributes<HTMLDivElement>'
},
{
// TODO: add
// <APIDocs componentName="Table.Tr" groupKeys="ComponentProps<'tr'>" />
// <APIDocs componentName="Table.Th" groupKeys="ComponentProps<'th'>" />
// <APIDocs componentName="Table.Td" groupKeys="ComponentProps<'td'>" />
name: 'Table',
packageName: 'nextra/components',
groupKeys: 'HTMLAttributes<HTMLTableElement>'
},
{ name: 'Tabs', packageName: 'nextra/components' },
{ type: 'separator', title: 'Other Components', name: '_3' },
{ name: 'MDXRemote', packageName: 'nextra/mdx-remote' },
{ name: 'Playground', packageName: 'nextra/components' },
{ name: 'TSDoc', packageName: 'nextra/tsdoc' }
]
const routes = API_REFERENCE.filter(
(o): o is ComponentApiReference => !('type' in o)
)
export const generateStaticParams = () =>
routes.map(o => ({ name: o.name.toLowerCase() }))
// @ts-expect-error -- fixme
export const pageMap: (MdxFile & { title: string })[] = API_REFERENCE.map(o =>
'type' in o
? o
: {
name: o.name.toLowerCase(),
route: `/docs/built-ins/${o.name.toLowerCase()}`,
title:
o.name === 'TSDoc' ? (
<span className="badge-new">{o.name}</span>
) : (
o.name
)
}
)
const Wrapper = getMDXComponents().wrapper
async function getReference(props: PageProps) {
const params = await props.params
const apiRefIndex = routes.findIndex(
o => o.name.toLowerCase() === params.name
)
const apiRef = routes[apiRefIndex]
if (!apiRef) {
throw new Error(`API reference not found for "${params.name}"`)
}
const { name, packageName, groupKeys, isFlattened } = apiRef
const result = groupKeys
? `Omit<MyProps, keyof ${groupKeys}> & { '...props': ${groupKeys} }>`
: 'MyProps'
const code =
apiRef.code ??
`
import type { ComponentProps, HTMLAttributes } from 'react'
import type { ComboboxInputProps } from '../packages/nextra/node_modules/@headlessui/react'
import { ${name} as MyComponent } from '${packageName}'
type MyProps = ComponentProps<typeof MyComponent>
type $ = ${result}
export default $`
const flattened = isFlattened !== false
const fcPropsDefinition = generateDefinition({ code, flattened })
const {
// @ts-expect-error -- exist
signatures: _signatures,
...fcDefinition
} = generateDefinition({
code: `export { ${name} as default } from '${packageName}'`,
flattened
})
const definition = {
...fcPropsDefinition,
...fcDefinition
}
const res = await generateApiReference(apiRef, {
title: 'Component',
subtitle: 'Props',
definition
// bottomMdxContent: `<Callout type="default">
// **Tip for TypeScript users:**<br/>
// You can retrieve the props type for the \`<${name}>\` component using \`React.ComponentProps<typeof ${name}>\`.
// </Callout>`
})
const filePath =
fcDefinition.filePath &&
path
.relative('..', fcDefinition.filePath)
.replace(/\.d.ts$/, '.tsx')
.replace('/dist/', '/src/')
// Add edit on GitHub link to points on a source file
res.metadata.filePath = `https://github.com/shuding/nextra/tree/main/${filePath}`
return res
}
export async function generateMetadata(props: PageProps) {
const { metadata } = await getReference(props)
return metadata
}
type PageProps = Readonly<{
params: Promise<{ name: string }>
}>
const Page: FC<PageProps> = async props => {
const {
default: MDXContent,
toc,
metadata,
sourceCode
} = await getReference(props)
return (
<Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>
<MDXContent />
</Wrapper>
)
}
export default Page
================================================
FILE: docs/app/docs/built-ins/page.mdx
================================================
---
asIndexPage: true
sidebarTitle: Built-In Components
---
import {
CardsIcon,
FolderTreeIcon,
IdCardIcon,
OneIcon,
TableIcon
} from '@components/icons'
import { Callout } from 'nextra/components'
import { GitHubWarningIcon } from 'nextra/icons'
import { OverviewPage } from '../../_components/overview-page'
import { getEnhancedPageMap } from '../../../components/get-page-map'
# Built-Ins
<Callout type="info">
This API reference is automatically generated from the catch-all route file
`/docs/built-ins/[name]/page.tsx` using the new [Nextra `<TSDoc />`
component](/docs/built-ins/tsdoc).
</Callout>
Nextra includes a couple of built-in components that you can use to better style
your content:
{/* `pageMap` prop will be removed once Nextra will add dynamic routes in pageMap */}
<OverviewPage
filePath={metadata.filePath}
pageMap={
(await getEnhancedPageMap())
.find(o => o.name === 'docs')
.children.find(o => o.name === 'built-ins').children
}
icons={{
WarningIcon: GitHubWarningIcon,
IdCardIcon,
FolderTreeIcon,
OneIcon,
TableIcon,
CardsIcon
}}
/>
================================================
FILE: docs/app/docs/custom-theme/old.mdx
================================================
### Render metadata for the active page
> [!WARNING]
>
> Docs from Nextra 3
Other than `children`, some other useful props are passed to the theme layout
too. With the `pageOpts` props, the theme can access the page's meta
information.
For example, let's implement these features:
- Render the page title in `<title>`
- Show a simple Table of Contents via MDX `<Wrapper>` component
- Add a meta tag for `og:image` via the front matter
```tsx filename="theme.tsx" /pageOpts/
import Head from 'next/head'
import type { NextraThemeLayoutProps } from 'nextra'
import { MDXProvider } from 'nextra/mdx'
export default function Layout({ children, pageOpts }: NextraThemeLayoutProps) {
const { title, frontMatter } = pageOpts
return (
<>
<Head>
<title>{title}</title>
<meta name="og:image" content={frontMatter.image} />
</Head>
<MDXProvider components={{ wrapper: MyWrapper }}>{children}</MDXProvider>
</>
)
}
function MyWrapper({ children, toc }) {
return (
<>
<h1>My Theme</h1>
Table of Contents:
<ul>
{toc.map(heading => (
<li key={heading.value}>{heading.value}</li>
))}
</ul>
<div style={{ border: '1px solid' }}>{children}</div>
</>
)
}
```
### Use page map of the entire site
> [!WARNING]
>
> Docs from Nextra 3
Now, if you want to render something like a sidebar or a navigation bar, which
relies on information of not only the current page but also other pages, you can
use the `pageMap` value.
For example, we can render a simple navigation list with all the pages in the
top level:
```tsx filename="theme.tsx" /pageMap/
import Link from 'next/link'
import type { NextraThemeLayoutProps } from 'nextra'
export default function Layout({ children, pageOpts }: NextraThemeLayoutProps) {
const { pageMap } = pageOpts
return (
<div>
<h1>My Theme</h1>
{pageMap.map(item => {
if ('route' in item && !('children' in item)) {
return (
<Link key={item.name} href={item.route}>
{item.route}
</Link>
)
}
})}
<div style={{ border: '1px solid' }}>{children}</div>
</div>
)
}
```
There are other item kinds such as `Folder` (for directories) and `Meta` (for
`_meta` files). All the items are typed so you can easily know the properties.
================================================
FILE: docs/app/docs/custom-theme/page.mdx
================================================
import { ExampleCode } from 'components/example-code'
import { Steps } from 'nextra/components'
import OldDocs from './old.mdx'
# Custom Theme
A theme in Nextra works like a layout, that will be rendered as a wrapper for
all pages. This docs will walk you through the process of creating a custom
theme.
> [!NOTE]
>
> Source code for the following custom theme can be found
> [here](https://github.com/shuding/nextra/tree/main/examples/custom-theme).
## Create a custom theme
<Steps>
### Create a root layout
<ExampleCode example="custom-theme" filePath="app/layout.tsx" />
### Create [`mdx-components` file](/docs/file-conventions/mdx-components-file)
<ExampleCode
example="custom-theme"
filePath="mdx-components.jsx"
metadata="/toc/2 {9}"
/>
<ExampleCode
example="custom-theme"
filePath="app/_components/toc.tsx"
metadata="/toc/"
/>
### Create a basic theme
You can now start working on your theme! Create the `nextra-theme.tsx` file, it
accepts a `children` prop, which is the MDX content of the current page, and
wraps some other elements around the content:
<ExampleCode
example="custom-theme"
filePath="app/_components/nextra-theme.tsx"
metadata="/children/"
/>
### Create navbar and footer
<ExampleCode example="custom-theme" filePath="app/_components/footer.tsx" />
<ExampleCode
example="custom-theme"
filePath="app/_components/navbar.tsx"
metadata="/topLevelNavbarItems/"
/>
### Create sidebar
<ExampleCode
example="custom-theme"
filePath="app/_components/sidebar.tsx"
metadata="/docsDirectories/"
/>
### Add first MDX page
After creating the theme, you can simply add a MDX file as `app/page.mdx` and
see the result:

<br />
Inside your theme layout, you can use CSS imports or other ways to style it.
Next.js hooks such as `usePathname` are also available.
{process.env.NODE_ENV !== 'production' && <OldDocs />}
</Steps>
================================================
FILE: docs/app/docs/docs-theme/api/page.mdx
================================================
# API
## `useThemeConfig` hook
The `useThemeConfig` hook returns values of your
[theme configuration](/docs/docs-theme/theme-configuration) and is made to
dynamically configure your project.
```js
import { useThemeConfig } from 'nextra-theme-docs'
```
<APIDocs
code="export type { useThemeConfig as default } from 'nextra-theme-docs'"
flattened
/>
## `useConfig` hook
```js
import { useConfig } from 'nextra-theme-docs'
```
The `useConfig` hook returns data from your current page context.
<APIDocs
code="export type { useConfig as default } from 'nextra-theme-docs'"
flattened
/>
================================================
FILE: docs/app/docs/docs-theme/built-ins/footer/page.mdx
================================================
---
sidebarTitle: Footer
---
import { ToggleVisibilitySection } from 'components/toggle-visibility-section'
# Footer Component
The footer area of the website. You can specify content for your default footer.
## Props
<APIDocs
componentName="Footer"
packageName="nextra-theme-docs"
groupKeys="ComponentProps<'footer'>"
/>
## Example
You can add content, such as copyright information by passing it as `children`
of the `Footer` component:
```jsx filename="app/layout.jsx"
import { Footer, Layout } from 'nextra-theme-docs'
export default function MyLayout({ children, ...props }) {
return (
<Layout>
{children}
<Footer>
MIT {new Date().getFullYear()} ©{' '}
<a href="https://nextra.site" target="_blank">
Nextra
</a>
.
</Footer>
{children}
</Layout>
)
}
```
<ToggleVisibilitySection element="`<Footer>`" property="footer" />
================================================
FILE: docs/app/docs/docs-theme/built-ins/layout/old.mdx
================================================
## MDX Components [!TODO]
Provide custom [MDX components](https://mdxjs.com/table-of-components) to render
the content. For example, you can use a custom `pre` component to render code
blocks.
================================================
FILE: docs/app/docs/docs-theme/built-ins/layout/page.mdx
================================================
---
sidebarTitle: Layout
---
import { ToggleVisibilitySection } from 'components/toggle-visibility-section'
export function PartialTSDoc({ flattened, props }) {
return (
<APIDocs
flattened={flattened}
code={`
import { Layout } from 'nextra-theme-docs'
type $ = Pick<React.ComponentProps<typeof Layout>, ${props.map(prop => JSON.stringify(prop)).join('|')}>
export default $`}
/>
)
}
# Layout Component
The theme is configured with the `<Layout>` component. You should pass your
config options as Layout's `props`, for example:
```jsx filename="app/layout.jsx" {8-9}
import { Layout } from 'nextra-theme-docs'
export default function MyLayout({ children, ...props }) {
return (
<html lang="en">
<body>
<Layout
sidebar={{ autoCollapse: true }}
docsRepositoryBase="https://github.com/shuding/nextra/tree/main/docs"
>
{children}
</Layout>
</body>
</html>
)
}
```
Detailed information for each option is listed below.
## Props
## Page Map
<PartialTSDoc props={['pageMap']} />
## Banner
<PartialTSDoc props={['banner']} />
## Navbar
<PartialTSDoc props={['navbar']} />
<ToggleVisibilitySection element="`<Navbar>`" property="navbar" />
## Footer
<PartialTSDoc props={['footer']} />
<ToggleVisibilitySection element="`<Footer>`" property="footer" />
## Search
<PartialTSDoc props={['search']} />
## Docs Repository
Set the repository URL of the documentation. It's used to generate the
"[Edit this page](#edit-link)" link, the "[Feedback](#feedback-link)" link and
"[Report of broken link](./not-found)" on
[not found page](https://nextjs.org/docs/app/api-reference/file-conventions/not-found).
<PartialTSDoc props={['docsRepositoryBase']} />
### Specify a Path
If the documentation is inside a monorepo, a subfolder, or a different branch of
the repository, you can simply set the `docsRepositoryBase` to the root path of
the `app/` (App Router) folder of your docs. For example:
```jsx filename="app/layout.jsx"
<Layout docsRepositoryBase="https://github.com/shuding/nextra/tree/main/docs">
{children}
</Layout>
```
Then Nextra will automatically generate the correct file path for all pages.
## Dark Mode and Themes
Customize the theme behavior of the website.
<PartialTSDoc props={['darkMode', 'nextThemes']} />
import Old from './old.mdx'
{process.env.NODE_ENV !== 'production' && <Old />}
## Edit Link
Show an "Edit this page" link on the page that points to the file URL on GitHub
(or other places).
<PartialTSDoc props={['editLink']} />
> [!TIP]
>
> To disable it, you can set `editLink` to `null`.
## Feedback Link
The built-in feedback link provides a way for users to submit feedback about the
documentation.
<PartialTSDoc props={['feedback']} flattened />
> [!TIP]
>
> To disable it, you can set `feedback.content` to `null`.
## I18n
<PartialTSDoc props={['i18n']} />
## Last Updated Date
Show the last updated date of a page. It's useful for showing the freshness of
the content.
<PartialTSDoc props={['lastUpdated']} />
<ToggleVisibilitySection element="last update date" property="timestamp" />
## Navigation
Show previous and next page links on the bottom of the content. It's useful for
navigating between pages.
<PartialTSDoc props={['navigation']} />

```jsx filename="app/layout.jsx"
<Layout
navigation={{
prev: true,
next: true
}}
>
{children}
</Layout>
```
The above is also equivalent to `navigation: true{:js}`.
<ToggleVisibilitySection element="navigation" property="pagination" />
## Sidebar
<PartialTSDoc props={['sidebar']} flattened />
### Menu Collapse Level
By default, the sidebar menu is collapsed at level `2`. You can change it by
setting `sidebar.defaultMenuCollapseLevel` to a different number. For example,
when set to `1`, every folder will be collapsed by default and when set to
`Infinity`, all nested folders will be expanded by default.
If `sidebar.autoCollapse` is set to `true`, then all folders that do not contain
an active/focused route will automatically collapse up to the level set by
`sidebar.defaultMenuCollapseLevel`. e.g. if `defaultMenuCollapseLevel` is `2`,
then top-level folders will not auto-collapse.
### Customize Sidebar Content
Together with the [Separators](/docs/docs-theme/page-configuration#separators)
item, you can customize how the sidebar content is rendered by using JSX
elements:
```jsx filename="_meta.jsx" {5-10}
export default {
index: 'Intro',
'--': {
type: 'separator',
title: (
<div className="flex items-center gap-2">
<MyLogo />
{children}
</div>
)
},
frameworks: 'JS Frameworks & Libs',
about: 'About'
}
```

<ToggleVisibilitySection element="`<Sidebar>`" property="sidebar" />
### Customize Sidebar with Front Matter
In addition, you can customize the sidebar title using the `sidebarTitle`
property in your front matter:
```mdx filename="getting-started.mdx"
---
sidebarTitle: Getting Started 🚀
---
```
The priority of the sidebar title is as follows:
1. A non-empty title from the `_meta` file.
1. `sidebarTitle` in the front matter.
1. `title` in the front matter.
1. The title derived from the first `h1` Markdown heading (e.g.
`# Dima Machina`).
1. If none of the above are available, it falls back to the filename of the
page, formatted according to [The Chicago Manual of Style](https://title.sh).
## Theme Switch
<PartialTSDoc props={['themeSwitch']} />
You are able to customize the option names for localization or other purposes:
```jsx filename="app/layout.jsx"
<Layout
themeSwitch={{
dark: 'Темный',
light: 'Светлый',
system: 'Системный'
}}
>
{children}
</Layout>
```
## Table of Contents (TOC)
Show a table of contents on the right side of the page. It's useful for
navigating between headings.
<PartialTSDoc props={['toc']} flattened />
### Floating TOC
When enabled, the TOC will be displayed on the right side of the page, and it
will be sticky when scrolling. If it's disabled, the TOC will be displayed
directly on the page sidebar.
<ToggleVisibilitySection element="`<TOC>`" property="toc" />
================================================
FILE: docs/app/docs/docs-theme/built-ins/navbar/page.mdx
================================================
---
sidebarTitle: Navbar
---
import { ToggleVisibilitySection } from 'components/toggle-visibility-section'
import { generateTsFromZod } from 'nextra/tsdoc'
# Navbar Component
## Props
<APIDocs componentName="Navbar" packageName="nextra-theme-docs" />
### Logo
The logo of the website rendered on the navbar.
<figure>
<></>
{/* prettier-ignore */}
<figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-yrlccm?file=theme.config.jsx)</figcaption>
</figure>
```jsx filename="app/layout.jsx"
<Navbar
logo={
<>
<svg width="24" height="24" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M14.683 14.828a4.055 4.055 0 0 1-1.272.858a4.002 4.002 0 0 1-4.875-1.45l-1.658 1.119a6.063 6.063 0 0 0 1.621 1.62a5.963 5.963 0 0 0 2.148.903a6.035 6.035 0 0 0 3.542-.35a6.048 6.048 0 0 0 1.907-1.284c.272-.271.52-.571.734-.889l-1.658-1.119a4.147 4.147 0 0 1-.489.592z M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10s10-4.486 10-10S17.514 2 12 2zm0 2c2.953 0 5.531 1.613 6.918 4H5.082C6.469 5.613 9.047 4 12 4zm0 16c-4.411 0-8-3.589-8-8c0-.691.098-1.359.264-2H5v1a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2h2a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2v-1h.736c.166.641.264 1.309.264 2c0 4.411-3.589 8-8 8z"
/>
</svg>
<span style={{ marginLeft: '.4em', fontWeight: 800 }}>
My Cool Project
</span>
</>
}
/>
```
### Project link
Show a button that links to your project's homepage on the navbar. By default,
it links to Nextra's GitHub repository.
You can configure `projectLink` and `projectIcon` to customize the project link,
for example make it link to your GitLab repository:

```jsx filename="app/layout.jsx"
<Navbar
projectLink="https://gitlab.com/inkscape/inkscape"
projectIcon={
<svg width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="m231.9 169.8l-94.8 65.6a15.7 15.7 0 0 1-18.2 0l-94.8-65.6a16.1 16.1 0 0 1-6.4-17.3L45 50a12 12 0 0 1 22.9-1.1L88.5 104h79l20.6-55.1A12 12 0 0 1 211 50l27.3 102.5a16.1 16.1 0 0 1-6.4 17.3Z" />
</svg>
}
/>
```
### Chat link
Show a button that links to your project's forum or other social media on the
navbar.
You can configure `chatLink` and `chatIcon` to customize the chat link, for
example make it link to your Twitter account:
```jsx filename="app/layout.jsx"
<Navbar
chatLink="https://twitter.com/shuding_"
chatIcon={
<svg width="24" height="24" viewBox="0 0 248 204">
<path
fill="currentColor"
d="M221.95 51.29c.15 2.17.15 4.34.15 6.53 0 66.73-50.8 143.69-143.69 143.69v-.04c-27.44.04-54.31-7.82-77.41-22.64 3.99.48 8 .72 12.02.73 22.74.02 44.83-7.61 62.72-21.66-21.61-.41-40.56-14.5-47.18-35.07a50.338 50.338 0 0 0 22.8-.87C27.8 117.2 10.85 96.5 10.85 72.46v-.64a50.18 50.18 0 0 0 22.92 6.32C11.58 63.31 4.74 33.79 18.14 10.71a143.333 143.333 0 0 0 104.08 52.76 50.532 50.532 0 0 1 14.61-48.25c20.34-19.12 52.33-18.14 71.45 2.19 11.31-2.23 22.15-6.38 32.07-12.26a50.69 50.69 0 0 1-22.2 27.93c10.01-1.18 19.79-3.86 29-7.95a102.594 102.594 0 0 1-25.2 26.16z"
/>
</svg>
}
/>
```
### Menu and custom links
Check out [Page Configuration](/docs/docs-theme/page-configuration#navbar-items)
to learn how to add custom menus or links to the navbar.
<ToggleVisibilitySection element="`<Navbar>`" property="navbar" />
================================================
FILE: docs/app/docs/docs-theme/built-ins/not-found/page.mdx
================================================
---
sidebarTitle: NotFoundPage
---
# NotFoundPage Component
Options to configure report of broken link on not found page.
## Props
<APIDocs componentName="NotFoundPage" packageName="nextra-theme-docs" />
## Example
```jsx filename="app/not-found.jsx"
import { NotFoundPage } from 'nextra-theme-docs'
export default function NotFound() {
return (
<NotFoundPage content="Submit an issue" labels="broken-link">
<h1>The page is not found</h1>
</NotFoundPage>
)
}
```
================================================
FILE: docs/app/docs/docs-theme/built-ins/page.mdx
================================================
---
asIndexPage: true
sidebarTitle: Built-In Components
icon: BoxIcon
---
import { OverviewPage } from '../../../_components/overview-page'
# Built-Ins
<OverviewPage filePath={metadata.filePath} />
================================================
FILE: docs/app/docs/docs-theme/page.mdx
================================================
---
asIndexPage: true
sidebarTitle: Docs Theme
---
# Nextra Docs Theme
import { BoxIcon, ChevronRightIcon } from '@components/icons'
import { OverviewPage } from '../../_components/overview-page'
<OverviewPage
filePath={metadata.filePath}
icons={{
ChevronRightIcon,
BoxIcon
}}
/>
================================================
FILE: docs/app/docs/docs-theme/start/page.mdx
================================================
---
sidebarTitle: Get Started
icon: ChevronRightIcon
---
import InstallNextraTheme from '@components/install-nextra-theme.mdx'
import ReadyToGo from '@components/ready-to-go.mdx'
import { Steps } from 'nextra/components'
# Docs Theme
Nextra Docs Theme is a theme that includes almost everything you need to build a
modern documentation website. It includes:
- a top navigation bar
- a search bar
- a pages sidebar
- a table of contents (TOC)
- and other built-in components
> [!TIP]
>
> This website itself is built with the Nextra Docs Theme.
## Start as a New Project
<Steps>
### Install
To create a Nextra Docs site manually, you have to install **Next.js**,
**React**, **Nextra**, and **Nextra Docs Theme**. In your project directory, run
the following command to install the dependencies:
```sh npm2yarn
npm i next react react-dom nextra nextra-theme-docs
```
> [!NOTE]
>
> If you already have Next.js installed in your project, you only need to
> install `nextra` and `nextra-theme-docs` as the add-ons.
<InstallNextraTheme />
```jsx filename="app/layout.jsx"
import { Footer, Layout, Navbar } from 'nextra-theme-docs'
import { Banner, Head } from 'nextra/components'
import { getPageMap } from 'nextra/page-map'
import 'nextra-theme-docs/style.css'
export const metadata = {
// Define your metadata here
// For more information on metadata API, see: https://nextjs.org/docs/app/building-your-application/optimizing/metadata
}
const banner = <Banner storageKey="some-key">Nextra 4.0 is released 🎉</Banner>
const navbar = (
<Navbar
logo={<b>Nextra</b>}
// ... Your additional navbar options
/>
)
const footer = <Footer>MIT {new Date().getFullYear()} © Nextra.</Footer>
export default async function RootLayout({ children }) {
return (
<html
// Not required, but good for SEO
lang="en"
// Required to be set
dir="ltr"
// Suggested by `next-themes` package https://github.com/pacocoursey/next-themes#with-app
suppressHydrationWarning
>
<Head
// ... Your additional head options
>
{/* Your additional tags should be passed as `children` of `<Head>` element */}
</Head>
<body>
<Layout
banner={banner}
navbar={navbar}
pageMap={await getPageMap()}
docsRepositoryBase="https://github.com/shuding/nextra/tree/main/docs"
footer={footer}
// ... Your additional layout options
>
{children}
</Layout>
</body>
</html>
)
}
```
<ReadyToGo />
</Steps>
See the [File Conventions](/docs/file-conventions) for more details on
organizing your documentation structure, and check out the
[Layout Component](/docs/docs-theme/built-ins/layout) for configuring the docs
site's theme.
================================================
FILE: docs/app/docs/file-conventions/content-directory/page.mdx
================================================
---
icon: FolderIcon
sidebarTitle: content
description:
The `content` directory in Nextra allows you to organize your Markdown files
without adhering to the `page` filename convention, simplifying the migration
from Next.js `pages` router.
---
import fs from 'node:fs/promises'
import { compileMdx } from 'nextra/compile'
import { FileTree, Steps } from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
export async function MDXPathPage() {
const filename = '[[...mdxPath]]/page.jsx'
const rawMdx = `~~~jsx filename="${filename}" showLineNumbers
${(await fs.readFile(`../examples/docs/src/app/docs/${filename}`, 'utf8')).trimEnd()}
~~~`
const rawJs = await compileMdx(rawMdx, { defaultShowCopyCode: true })
return <MDXRemote compiledSource={rawJs} />
}
# `content` Directory
The `content` directory is designed to:
1. Migrate your existing Next.js `pages` router with minimal changes, you just
need to rename your `pages` directory to `content`.
1. Avoid having `page` filename convention, e.g. `app/configuration/page.mdx` ->
`content/configuration.mdx`
## Setup
<Steps>
### Create your first MDX page as `content/index.mdx`:
```mdx filename="content/index.mdx"
# Welcome to Nextra
Hello, world!
```
> [!TIP]
>
> You can keep `content` directory in root of your project, or in
> [`src` directory](./src-directory).
### Set `contentDirBasePath` option in `next.config` file (_optional_)
If you want to serve your content from a different path, you can set
`contentDirBasePath` option:
```js filename="next.config.mjs" {4}
import nextra from 'nextra'
const withNextra = nextra({
contentDirBasePath: '/docs' // Or even nested e.g. `/docs/advanced`
})
```
### Add `[[...mdxPath]]/page.jsx` file
Place this file in `app` directory with the following content:
<MDXPathPage />
you should get the following structure:
<FileTree>
<FileTree.Folder name="app" open>
<FileTree.File name="layout.jsx" />
<FileTree.Folder name="[[...mdxPath]]" open active>
<FileTree.File name="page.jsx" active />
</FileTree.Folder>
</FileTree.Folder>
<FileTree.Folder name="content" open>
<FileTree.File name="index.mdx" />
</FileTree.Folder>
<FileTree.File name="next.config.js" />
<FileTree.File name="package.json" />
</FileTree>
> [!TIP]
>
> Consider the single catch-all route `[[...mdxPath]]/page.jsx` as a gateway to
> your `content` directory.
>
> If you set `contentDirBasePath` option in `next.config` file, you should put
> `[[...mdxPath]]/page.jsx` in the corresponding directory.
### You are ready to go!
> [!NOTE]
>
> Many existing solutions such as
> [Refreshing the Next.js App Router When Your Markdown Content Changes](https://steveruiz.me/posts/nextjs-refresh-content)
> rely on extra dependencies like `concurrently` and `ws`. These approaches
> include
> [Dan Abramov workaround with `<AutoRefresh>` component and dev web socket server](https://github.com/hashicorp/next-remote-watch/issues/42#issuecomment-1794052655).
>
> Nextra's `content` directory delivers a streamlined solution right out of the
> box:
>
> - you don't need to install unnecessary dependencies
> - you don't need to restart your server on changes in `content` directory
> - hot reloading works out of the box
> - you can use `import` statements in MDX files and
> [static images](/docs/guide/image#static-image) works as well
>
> Checkout Nextra's
> [docs website](https://github.com/shuding/nextra/tree/main/examples/docs) and
> [i18n website example](https://github.com/shuding/nextra/tree/main/examples/swr-site).
</Steps>
================================================
FILE: docs/app/docs/file-conventions/mdx-components-file/page.mdx
================================================
---
icon: MdxIcon
sidebarTitle: mdx-components.js
description:
The `mdx-components` file in Nextra is essential for customizing styles via
the `useMDXComponents` function, allowing you to define and override MDX
components globally.
---
# `mdx-components.js` File
The `mdx-components` file is **required**, you use it to customize styles via
`useMDXComponents` function.
## Example
The `mdx-components.js` file must export
[a single function named `useMDXComponents`](/api/usemdxcomponents).
```ts filename="mdx-components.js"
import { useMDXComponents as getThemeComponents } from 'nextra-theme-docs' // nextra-theme-blog or your custom theme
// Get the default MDX components
const themeComponents = getThemeComponents()
// Merge components
export function useMDXComponents(components) {
return {
...themeComponents,
...components
}
}
```
## Errors
### Module not found: Can't resolve `'next-mdx-import-source-file'`
To fix this, update the `turbopack.resolveAlias` section in your `next.config`
file:
> [!NOTE]
>
> - If you're using Next.js < 15.3, use `experimental.turbopack.resolveAlias`
> - If you're using Next.js ≥ 15.3, use `turbopack.resolveAlias`
```diff filename="next.config.mjs"
import nextra from 'nextra'
const withNextra = nextra()
export default withNextra({
+ turbopack: {
+ resolveAlias: {
+ // Path to your `mdx-components` file with extension
+ 'next-mdx-import-source-file': './src/mdx-components.tsx'
+ }
+ }
})
```
> [!TIP]
>
> - You can keep `mdx-components` file in root of your project, or in
> [`src` directory](./src-directory).
> - The `.js`, `.jsx`, or `.tsx` file extensions can be used for
> `mdx-components` file.
> - When importing `useMDXComponents`, alias it as `getMDXComponents` to avoid a
> false positive error from the ESLint React Hooks plugin.
>
> ```bash filename="react-hooks/rules-of-hooks"
> React Hook "useMDXComponents" cannot be called at the top level.
> React Hooks must be called in a React function component or a custom React Hook function.
> ```
================================================
FILE: docs/app/docs/file-conventions/meta-file/page.mdx
================================================
---
icon: FileIcon
sidebarTitle: _meta.js
description:
The `_meta` file in Nextra allows you to customize page sidebar titles, order,
and theme visibility, enhancing site organization and user experience.
---
import { ContentAndAppFileTee } from 'components/content-and-app-file-tree'
import { Video } from 'components/video'
import { FileTree } from 'nextra/components'
import { generateTsFromZod } from 'nextra/tsdoc'
import { pageThemeSchema } from 'private-next-root-dir/../packages/nextra/dist/server/schemas'
export function Block({ children }) {
return (
<div className="flex gap-2 *:last:w-full *:last:min-w-0 max-lg:flex-wrap">
{children}
</div>
)
}
# `_meta.js` File
In Nextra, the site and individual page structure can be configured via the
co-located `_meta` files. Those configurations affect the overall layout of your
Nextra theme, especially the navigation bar and the sidebar:
<figure>
<></>
{/* prettier-ignore */}
<figcaption>Example: [Nextra Docs Theme](/docs/docs-theme) has sidebar and navbar generated automatically from Markdown files.</figcaption>
</figure>
{/* It's very common to customize each page's title, rather than just relying on filenames. Having a page titled "Index" lacks clarity. It is preferable to assign a meaningful title that accurately represents the content, such as "Home". */}
{/* That's where `_meta` files comes in. You can have an `_meta` file in each directory, and it will be used to override the default configuration of each page. */}
## Organizing files
Nextra allows you to organize files in the following ways:
- **In Next.js'
[`app` directory](https://nextjs.org/docs/app/getting-started/project-structure#top-level-folders):**<br />Nextra
gathers all `page` files, including
[`page.md` and `page.mdx` files](/docs/file-conventions/page-file) as well as
`_meta` files.
- **In Nextra's
[`content` directory](/docs/file-conventions/content-directory):**<br/>Nextra
collects all `.md` and `.mdx` files, along with `_meta` files.
Below the same file-based routing structure is represented for `content` and
`app`-only directories:
<ContentAndAppFileTee>
<FileTree.Folder name="about" defaultOpen>
<FileTree.File name="_meta.js" active />
<FileTree.File name="index.mdx" />
<FileTree.File name="legal.md" />
</FileTree.Folder>
<FileTree.File name="_meta.js" active />
<FileTree.File name="contact.md" />
<FileTree.File name="index.mdx" />
</ContentAndAppFileTee>
> [!NOTE]
>
> You can combine both organizational ways for your project:
>
> - [x] the `content` directory with `.mdx` files
> - [x] the `app` directory with `page` files
### `pageMap` structure
Afterward, Nextra generates a `pageMap` array containing information about your
entire site's routes and directories structure. Features such as the navigation
bar and sidebar can be generated based on the `pageMap` information.
The generated `pageMap` will be:
```jsonc filename="pageMap" copy=false
[
// content/_meta.js
{ "data": {} },
{
// content/index.mdx
"name": "index",
"route": "/",
"title": "Index",
"frontMatter": {}
},
{
// content/contact.md
"name": "contact",
"route": "/contact",
"title": "Contact",
"frontMatter": {}
},
{
// content/about
"name": "about",
"route": "/about",
"title": "About",
"children": [
// content/about/_meta.js
{ "data": {} },
{
// content/about/index.mdx
"name": "index",
"route": "/about",
"title": "Index",
"frontMatter": {}
},
{
// content/about/legal.md
"name": "legal",
"route": "/about/legal",
"title": "Legal",
"frontMatter": {}
}
]
}
]
```
And the global `pageMap` will be imported to each page by Nextra. Then,
configured theme will render the actual UI with that `pageMap`.
## API
The title and order of a page shown in the sidebar/navbar can be configured in
the `_meta` file as key-value pairs.
```ts filename="_meta.ts"
import type { MetaRecord } from 'nextra'
/**
* type MetaRecordValue =
* | TitleSchema
* | PageItemSchema
* | SeparatorSchema
* | MenuSchema
*
* type MetaRecord = Record<string, MetaRecordValue>
**/
const meta: MetaRecord = {
// ...
}
export default meta
```
### `title` type
When specifying a `title` in `_meta` file, you can define it as either a simple
string or a JSX element.
```ts copy=false
type TitleSchema = string | ReactElement
```
For the below file structure:
<ContentAndAppFileTee className="shrink-0">
<FileTree.File name="_meta.js" active />
<FileTree.File name="about.mdx" />
<FileTree.File name="contact.mdx" />
<FileTree.File name="index.mdx" />
</ContentAndAppFileTee>
The following `_meta` file defines pages titles:
```jsx filename="_meta.jsx"
import { GitHubIcon } from 'nextra/icons'
export default {
index: 'My Homepage',
// You can use JSX elements to change the look of titles in the sidebar, e.g. insert icons
contact: (
<Italic className="my-class">
<GitHubIcon height="20" />
Contact Us
</Italic>
),
about: {
// Alternatively, you can set title with `title` property
title: 'About Us'
// ... and provide extra configurations
}
}
// Custom component for italicized text
function Italic({ children, ...props }) {
return <i {...props}>{children}</i>
}
```
### Pages
In `_meta` file you can define how the pages are shown in the sidebar, e.g. for
the following file structure:
<Block>
<ContentAndAppFileTee className='shrink-0'>
<FileTree.File name="_meta.js" active />
<FileTree.File name="about.mdx" />
<FileTree.File name="contact.mdx" />
<FileTree.File name="index.mdx" />
</ContentAndAppFileTee>
```js filename="_meta.js" copy=false
export default {
index: 'My Homepage',
contact: 'Contact Us',
about: 'About Us'
}
```
</Block>
> [!NOTE]
>
> If any routes are not listed in the `_meta` file, they will be appended to the
> end of the sidebar and sorted alphabetically (except for `index` key which
> comes first if it's not specified in `_meta` file).
```ts
type PageItemSchema = {
type: 'page' | 'doc' // @default 'doc'
display: 'normal' | 'hidden' | 'children' // @default 'normal'
title?: TitleSchema
theme?: PageThemeSchema
}
```
#### `type: 'page'` option
By defining a top-level page or folder as `type: 'page'{:js}`, it will be shown
as a special page on the navigation bar, instead of the sidebar. With this
feature, you can have multiple "sub docs", and special pages or links such as
"Contact Us" that are always visible.
For example, you can have 2 docs folders `frameworks` and `fruits` in your
project. In your top-level `_meta` file, you can set everything as a page,
instead of a normal sidebar item:
<Block>
<ContentAndAppFileTee className='shrink-0'>
<FileTree.Folder name="frameworks" defaultOpen active>
<FileTree.File name="react.mdx" />
<FileTree.File name="svelte.mdx" />
<FileTree.File name="vue.mdx" />
</FileTree.Folder>
<FileTree.Folder name="fruits" defaultOpen active>
<FileTree.File name="apple.mdx" />
<FileTree.File name="banana.mdx" />
</FileTree.Folder>
<FileTree.File name="_meta.js" active />
<FileTree.File name="about.mdx" />
<FileTree.File name="index.mdx" />
</ContentAndAppFileTee>
```js filename="_meta.js" copy=false {4,8,12,16}
export default {
index: {
title: 'Home',
type: 'page'
},
frameworks: {
title: 'Frameworks',
type: 'page'
},
fruits: {
title: 'Fruits',
type: 'page'
},
about: {
title: 'About',
type: 'page'
}
}
```
</Block>
And it will look like this:
<figure>
<Video src="/assets/docs/sub-docs.mp4" />
{/* prettier-ignore */}
<figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-eszspq?file=pages%2F_meta.js)</figcaption>
</figure>
> [!TIP]
>
> You can also hide links like `Home` from the navbar with the
> [`display: 'hidden'{:js}`](#display-hidden-option) option.
>
> You can have external links in the navbar, similar to the
> [links section](#links):
>
> ```js filename="_meta.js" {4-5}
> export default {
> contact: {
> title: 'Contact Us',
> type: 'page',
> href: 'https://example.com/contact'
> }
> }
> ```
#### `display: 'hidden'` option
By default, all MDX routes in the filesystem will be shown on the sidebar. But
you can hide a specific pages or folders by using the `display: 'hidden'{:ts}`
configuration:
```js filename="_meta.js" {3}
export default {
contact: {
display: 'hidden'
}
}
```
> [!NOTE]
>
> The page will still be accessible via the `/contact` URL, but it will not be
> shown in the sidebar.
#### `theme` option
You can configure the theme for each page using the `theme` option. For example,
you can disable or enable specific components for specific pages:
```js filename="_meta.js" {4}
export default {
about: {
theme: {
sidebar: false
}
}
}
```
> [!WARNING]
>
> This option will be inherited by all child pages if set to a folder.
<APIDocs
code={`type $ = ${generateTsFromZod(pageThemeSchema)}
export default $`}
/>
##### Layouts
By default, each page has `layout: 'default'{:js}` in their theme config, which
is the default behavior. You might want to render some page with the full
container width and height, but keep all the other styles. You can use the
`'full'{:js}` layout to do that:
```js filename="_meta.js" {4}
export default {
about: {
theme: {
layout: 'full'
}
}
}
```
##### Typesetting [#typesetting-section]
The `typesetting` option controls typesetting details like font features,
heading styles and components like `<li>` and `<code>`. There are
`'default'{:js}` and `'article'{:js}` typesettings available in the docs theme.
The default one is suitable for most cases like documentation, but you can use
the `'article'{:js}` typesetting to make it look like an elegant article page:
<figure>
```js filename="_meta.js" {4}
export default {
about: {
theme: {
typesetting: 'article'
}
}
}
```
<figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-hg77h3?file=pages%2F_meta.js,pages%2Findex.mdx)</figcaption>
</figure>
### Folders
Folders can be configured in the same way as pages.
For example, the following top-level `_meta` file contains the meta information
for the top-level pages and folders.<br/> The nested `_meta` file contains the
meta information for pages in the same folder:
<Block>
<ContentAndAppFileTee className='shrink-0'>
<FileTree.Folder name="fruits" defaultOpen>
<FileTree.File name="_meta.js" active />
<FileTree.File name="apple.mdx" />
<FileTree.File name="banana.mdx" />
</FileTree.Folder>
<FileTree.File name="_meta.js" active />
<FileTree.File name="about.mdx" />
<FileTree.File name="contact.mdx" />
<FileTree.File name="index.mdx" />
</ContentAndAppFileTee>
<div className='mt-6'>
```js filename="_meta.js" copy=false
export default {
index: 'My Homepage',
contact: 'Contact Us',
fruits: 'Delicious Fruits',
about: 'About Us'
}
```
```js filename="fruits/_meta.js" copy=false
export default {
apple: 'Apple',
banana: 'Banana'
}
```
</div>
</Block>
> [!NOTE]
>
> You can move directories around without having to change the `_meta` file
> since information for pages are grouped together in directories.
#### With `/index` page
To create a folder with an index page, add `asIndexPage: true{:js}` to its front
matter.
For example, to create a `/fruits` route, setting `asIndexPage: true{:js}` tells
Nextra that `/fruits` is a folder with an index page. Clicking the folder in the
sidebar will expand it and display the MDX page.
<Block>
<ContentAndAppFileTee className="shrink-0">
<FileTree.Folder name="fruits" defaultOpen active>
<FileTree.File name="_meta.js" />
<FileTree.File name="apple.mdx" />
<FileTree.File name="banana.mdx" />
<FileTree.File name="index.mdx" active />
</FileTree.Folder>
<FileTree.File name="_meta.js" />
<FileTree.File name="about.mdx" />
<FileTree.File name="contact.mdx" />
<FileTree.File name="index.mdx" />
</ContentAndAppFileTee>
```mdx filename="content/fruits/index.mdx or app/fruits/page.mdx" copy=false {4}
---
title: All Fruits
sidebarTitle: 🍒 Fruits
asIndexPage: true
---
```
</Block>
### Links
```ts
type LinkSchema = {
href: string
title?: TitleSchema
}
```
You can add external links to the sidebar by adding an item with `href` in
`_meta` file:
```js filename="_meta.js" {2-5}
export default {
github_link: {
title: 'Nextra',
href: 'https://github.com/shuding/nextra'
}
}
```
> [!TIP]
>
> You can use this option to link to relative internal links too.
### Separators
```ts
type SeparatorSchema = {
type: 'separator'
title?: TitleSchema
}
```
You can use a "placeholder" item with `type: 'separator'{:js}` to create a
separator line between items in the sidebar:
```js filename="_meta.js" {3-4}
export default {
'###': {
type: 'separator',
title: 'My Items' // Title is optional
}
}
```
### Menus
You can also add menus to the navbar using `type: 'menu'{:js}` and the `items`
option:
<figure>
<></>
{/* prettier-ignore */}
<figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-2qopvp?file=pages%2F_meta.js)</figcaption>
</figure>
```ts
type MenuItemSchema =
| TitleSchema
| { title: TitleSchema }
| (LinkSchema & { type?: 'page' | 'doc' })
| SeparatorSchema
type MenuSchema = {
type: 'menu'
title?: TitleSchema
items: Record<string, MenuItemSchema>
}
```
```js filename="_meta.js"
export default {
company: {
title: 'Company',
type: 'menu',
items: {
about: {
title: 'About',
href: '/about'
},
contact: {
title: 'Contact Us',
href: 'mailto:hi@example.com'
}
}
}
}
```
### Fallbacks
In the [`type: 'page'{:js}` option](#type-page-option) above, we have to define
the `type: 'page'{:js}` option for every page. To make it easier, you can use
the `'*'` key to define the fallback configuration for all items in this folder:
```js filename="_meta.js" {2-4}
export default {
'*': {
type: 'page'
},
index: 'Home',
frameworks: 'Frameworks',
fruits: 'Fruits',
about: 'About'
}
```
They are equivalent where all items have `type: 'page'{:js}` set.
### `_meta.global` file
You can also define all your pages in a single `_meta` file, suffixed with
`.global`. The API remains the same as for folder-specific `_meta` files, with 1
exception: **folder items must include an `items` field**.
For the following structure, you might use the following `_meta` files:
<Block>
<ContentAndAppFileTee className='shrink-0'>
<FileTree.Folder name="fruits" open>
<FileTree.File name="_meta.js" active />
<FileTree.File name="apple.mdx" />
<FileTree.File name="banana.mdx" />
</FileTree.Folder>
<FileTree.File name="_meta.js" active />
<FileTree.File name="index.mdx" />
</ContentAndAppFileTee>
<div className='mt-6'>
```js filename="_meta.js" copy=false
export default {
fruits: {
type: 'page',
title: '✨ Fruits'
}
}
```
```js filename="fruits/_meta.js" copy=false
export default {
apple: '🍎 Apple',
banana: '🍌 BaNaNa'
}
```
</div>
</Block>
With single `_meta.global` file it can be defined as below:
```js filename="_meta.global.js" copy=false
export default {
fruits: {
type: 'page',
title: '✨ Fruits',
items: {
apple: '🍎 Apple',
banana: '🍌 BaNaNa'
}
}
}
```
> [!WARNING]
>
> You can't use both `_meta.global` and `_meta` files in your project.
## Good to know
### Sorting pages
You can use ESLint's built-in `sort-keys` rule, append
`/* eslint sort-keys: error */` comment at the top of your `_meta` file, and you
will receive ESLint's errors about incorrect order.
### Type of `_meta` keys
The type of your `_meta` keys should always **be a string** and **not a number**
because
[numbers are always ordered first](https://dev.to/frehner/the-order-of-js-object-keys-458d)
in JavaScript objects.
For example, consider the following:
```js filename="_meta.js" copy=false
export default {
foo: '',
1992_10_21: '',
1: ''
}
```
will be converted to:
{/* prettier-ignore */}
```js filename="_meta.js" copy=false
export default {
'1': '',
'19921021': '',
foo: ''
}
```
> [!TIP]
>
> The `.js`, `.jsx`, or `.tsx` file extensions can be used for `_meta` file.
================================================
FILE: docs/app/docs/file-conventions/page-file/page.mdx
================================================
---
icon: FileIcon
sidebarTitle: page.mdx
description:
The `page.mdx` file in Nextra is a special Next.js App Router convention file
that allows you to define UI unique to a route. By default, `.js`, `.jsx`, or
`.tsx` file extensions can be used for `page`, and Nextra enhances them with
`.md` and `.mdx` extensions.
---
import { FileTree } from 'nextra/components'
# `page.mdx` File
[`page` file](https://nextjs.org/docs/app/api-reference/file-conventions/page)
is a special
[Next.js App Router convention file](https://nextjs.org/docs/app/getting-started/project-structure#routing-files)
which allows you to define UI that is unique to a route:
<FileTree>
<FileTree.Folder name="app" open>
<FileTree.File name="layout.jsx" />
<FileTree.File name="page.jsx" active />
<FileTree.Folder name="docs" open>
<FileTree.File name="page.mdx" active />
<FileTree.Folder name="getting-started" open>
<FileTree.File name="page.mdx" active />
</FileTree.Folder>
</FileTree.Folder>
</FileTree.Folder>
</FileTree>
> [!TIP]
>
> By default, the `.js`, `.jsx`, or `.tsx` file extensions can be used for
> `page`.<br/> Nextra enhance them with `.md` and `.mdx` extensions.
================================================
FILE: docs/app/docs/file-conventions/page.mdx
================================================
---
asIndexPage: true
description:
Nextra's File Conventions guide details the structure and organization of
files and directories within a Nextra project, including the use of
`page.mdx`, `_meta.js`, and `mdx-components.js` files, as well as the
`content` and `src` directories.
---
import { FileIcon, FolderIcon, MdxIcon } from 'nextra/icons'
import { OverviewPage } from '../../_components/overview-page'
# File Conventions
<OverviewPage
filePath={metadata.filePath}
icons={{ FileIcon, FolderIcon, MdxIcon }}
/>
================================================
FILE: docs/app/docs/file-conventions/src-directory/page.mdx
================================================
---
icon: FolderIcon
sidebarTitle: src
description:
The `src` directory in Nextra allows you to organize your application code
separately from project configuration files, enhancing code structure and
maintainability.
---
import { FileTree } from 'nextra/components'
# `src` Directory
As an alternative to having the special Nextra `content` directory and
`mdx-components` file in the root of your project, Nextra also supports the
common pattern of placing application code under the `src` directory.
This separates application code from project configuration files which mostly
live in the root of a project, which is preferred by some individuals and teams.
To use the `src` directory, move the `content` directory and `mdx-components`
file to `src/content` or `src/mdx-components` respectively.
export const nextConfigPackageJson = (
<>
<FileTree.File name="next.config.js" />
<FileTree.File name="package.json" />
</>
)
export const folders = (
<>
<FileTree.Folder name="app" open>
<FileTree.Folder name="[[...mdxPath]]" open>
<FileTree.File name="page.jsx" />
</FileTree.Folder>
<FileTree.File name="layout.jsx" />
</FileTree.Folder>
<FileTree.Folder name="content" open active>
<FileTree.File name="index.mdx" active />
</FileTree.Folder>
<FileTree.File name="mdx-components.js" active />
</>
)
<FileTree>
**Without `src` directory**
<FileTree.Folder name="your-project" open>
{folders}
{nextConfigPackageJson}
</FileTree.Folder>
</FileTree>
<FileTree>
**With `src` directory**
<FileTree.Folder name="your-project" open>
<FileTree.Folder name="src" open active>
{folders}
</FileTree.Folder>
{nextConfigPackageJson}
</FileTree.Folder>
</FileTree>
================================================
FILE: docs/app/docs/guide/custom-css/page.mdx
================================================
---
sidebarTitle: Custom CSS
icon: BrushIcon
---
# Custom CSS Support
Nextra is 100% compatible with the
[built-in CSS support of Next.js](https://nextjs.org/docs/app/getting-started/css),
including `.css`, `.module.css`, and Sass (`.scss`, `.sass`, `.module.scss`,
`.module.sass`) files.
For example, consider the following stylesheet named `styles.css`:
```css filename="styles.css"
body {
font-family:
'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', 'Helvetica', 'Arial',
sans-serif;
padding: 20px 20px 60px;
max-width: 680px;
margin: 0 auto;
}
```
To apply your global styles, import your CSS file in the root layout file:
```jsx filename="app/layout.jsx"
import '../path/to/your/styles.css'
export default async function RootLayout({ children }) {
// ... Your layout logic here
}
```
For more information on how to use CSS in Next.js, check out the
[Next.js CSS Support documentation](https://nextjs.org/docs/app/getting-started/css).
================================================
FILE: docs/app/docs/guide/github-alert-syntax/page.mdx
================================================
---
icon: InformationCircleIcon
---
# GitHub Alert Syntax
`nextra-theme-docs` and `nextra-theme-blog` support replacing
[GitHub alert syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)
with `<Callout>` component for `.md`/`.mdx` files.
## Usage
```md filename="Markdown"
> [!NOTE]
>
> Useful information that users should know, even when skimming content.
> [!TIP]
>
> Helpful advice for doing things better or more easily.
> [!IMPORTANT]
>
> Key information users need to know to achieve their goal.
> [!WARNING]
>
> Urgent info that needs immediate user attention to avoid problems.
> [!CAUTION]
>
> Advises about risks or negative outcomes of certain actions.
```
## Example
> [!NOTE]
>
> Useful information that users should know, even when skimming content.
> [!TIP]
>
> Helpful advice for doing things better or more easily.
> [!IMPORTANT]
>
> Key information users need to know to achieve their goal.
> [!WARNING]
>
> Urgent info that needs immediate user attention to avoid problems.
> [!CAUTION]
>
> Advises about risks or negative outcomes of certain actions.
## Usage with your own theme
If you want to benefit this feature with your own theme and your own `<Callout>`
component:
import { Steps } from 'nextra/components'
<Steps>
### Create a `<Blockquote>` component
To create a `<Blockquote>` component, start by importing `withGitHubAlert` from
`nextra/components`. You should then create the `<Blockquote>` component by
invoking the `withGitHubAlert` function.
The first argument should be a React HOC component that handles the GitHub alert
syntax, and the second argument should be your standard `<blockquote>`
component.
The `type` prop can be one of the following:
`'note' | 'tip' | 'important' | 'warning' | 'caution'{:ts}`.
```jsx
import { withGitHubAlert } from 'nextra/components'
const Blockquote = withGitHubAlert(({ type, ...props }) => {
return <MyCalloutComponent type={type} {...props} />
}, MyBlockquoteComponent)
```
### Provide `<Blockquote>` to `useMDXComponents`
To make the `<Blockquote>` component available, you should integrate it into the
`useMDXComponents` function:
```jsx filename="mdx-components.jsx"
export function useMDXComponents(components) {
return {
blockquote: Blockquote,
...components
}
}
```
</Steps>
================================================
FILE: docs/app/docs/guide/i18n/page.mdx
================================================
---
icon: GlobeIcon
---
import { ExampleCode } from '@components/example-code'
import { Steps } from 'nextra/components'
# Next.js I18n
> [!WARNING]
>
> This feature is only available in `nextra-theme-docs`.
Nextra supports
[Next.js Internationalized Routing](https://nextjs.org/docs/advanced-features/i18n-routing)
out of the box. These docs explain how to configure and use it.
<Steps>
## Add i18n config
To add multi-language pages to your Nextra application, you need to config
`i18n` in `next.config.mjs` first:
```js filename="next.config.mjs" {8-11}
import nextra from 'nextra'
const withNextra = nextra({
// ... other Nextra config options
})
export default withNextra({
i18n: {
locales: ['en', 'zh', 'de'],
defaultLocale: 'en'
}
})
```
> [!NOTE]
>
> You can use any format of
> [UTS Locale Identifiers](https://www.unicode.org/reports/tr35/tr35-59/tr35.html#Identifiers)
> for defining your locales in the `next.config` file, e.g. language with region
> format `en-US` (English as spoken in the United States).
## Configure the docs theme
Add the `i18n` option to your `theme.config.jsx` to configure the language
dropdown:
```js filename="theme.config.jsx"
i18n: [
{ locale: 'en', name: 'English' },
{ locale: 'zh', name: '中文' },
{ locale: 'de', name: 'Deutsch' },
{ locale: 'ar', name: 'العربية', direction: 'rtl' }
]
```
## Automatically detect and redirect to user-selected language (_optional_)
You can automatically detect the user's preferred language and redirect them to
the corresponding version of the site. To achieve this, create a `proxy.ts` or
`proxy.js` file in the root of your project and export Nextra's middleware
function from `nextra/locales`:
<ExampleCode example="swr-site" filePath="proxy.ts" metadata="{1}" />
> [!WARNING]
>
> This approach will not work for i18n sites that are statically exported with
> `output: 'export'` in `nextConfig`.
## Custom 404 page (_optional_)
You can have a custom `not-found.jsx` with translations for an i18n website that
uses a shared theme layout. For guidance on implementing this, you can check out
the
[SWR i18n example](https://github.com/shuding/nextra/blob/c9d0ffc8687644401412b8adc34af220cccddf82/examples/swr-site/app/%5Blang%5D/not-found.ts).
</Steps>
================================================
FILE: docs/app/docs/guide/image/page.mdx
================================================
---
icon: PictureIcon
---
# Next.js Image
The standard way to use
[Next.js Image](https://nextjs.org/docs/app/getting-started/images) inside MDX
is to directly import the component:
```mdx filename="MDX"
import Image from 'next/image'
<Image src="/demo.png" alt="Hello" width={500} height={500} />
```
## Static image
> [!NOTE]
>
> This feature is enabled via `staticImage: true` in the Nextra config by
> default.
Nextra supports automatically optimizing your static image imports with the
Markdown syntax. You do not need to specify the width and height of the image,
just use the `![]()` Markdown syntax:
```md filename="Markdown"

```
This loads the `demo.png` file inside the `public` folder, and automatically
wraps it with Next.js `<Image>`.
> [!TIP]
>
> You can also use `` to load the image from a relative
> path, if you don't want to host it via `public`.
With Next.js Image, there will be no layout shift, and a beautiful blurry
placeholder will be shown by default when loading the images:

## Image zoom
> [!NOTE]
>
> The image zoom feature is enabled globally by default.
In the default configuration, if you want to use this feature, simply insert
images using `![]()` Markdown syntax.
### Disable image zoom
For `nextra-docs-theme` and `nextra-blog-theme`, you can disable image zoom by
replacing the `img` component used in MDX.
```jsx filename="theme.config.jsx"
import { Image } from 'nextra/components'
export default {
// ... your other configurations
components: {
img: props => <Image {...props} />
}
}
```
### Enable/disable image zoom for specific images
When zoom is **disabled globally**, but you want to enable it for specific
images, you can do so by using the `<ImageZoom>` component:
```mdx
import { ImageZoom } from 'nextra/components'
<ImageZoom src="/demo.png" />
```
When zoom is **enabled globally**, and you want to disable zoom for a specific
image, you can simply use the `<Image>` component:
```mdx
import { Image } from 'nextra/components'
<Image src="/demo.png" />
```
================================================
FILE: docs/app/docs/guide/link/page.mdx
================================================
---
icon: LinkIcon
---
# Next.js Link
All relative Markdown links are automatically converted into
[Next.js links](https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating).
This means that the target page will be prefetched. When you click on a link,
the page will be loaded on the client-side like a
[Single-Page Application (SPA)](https://en.wikipedia.org/wiki/Single-page_application),
without making a full page load. For example:
```md filename="Markdown"
Click [here](/about) to read more.
```
Will be equivalent to:
```mdx filename="MDX"
import Link from 'next/link'
Click <Link href="/about">here</Link> to read more.
```
This feature makes navigation between Nextra pages fast and seamless.
================================================
FILE: docs/app/docs/guide/markdown/_counter.tsx
================================================
'use client'
import type { FC, ReactNode } from 'react'
import { useState } from 'react'
export const Counter: FC<{ children: ReactNode }> = ({ children }) => {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(prev => prev + 1)}>
{children}
{count}
</button>
)
}
================================================
FILE: docs/app/docs/guide/markdown/page.mdx
================================================
---
icon: MarkdownIcon
---
import { Shadow } from '@components/shadow'
import { Counter } from './_counter'
# Markdown
## MDX
With Nextra, all your `.mdx` files under the `content` directory will be
rendered with [MDX](https://mdxjs.com/about), it's an advanced Markdown format
with React component support.
For example, you can use import and use React components inside your MDX files
like this:
```mdx filename="MDX"
## Hello MDX
import { useState } from 'react'
export function Counter({ children }) {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(prev => prev + 1)}>
{children}
{count}
</button>
)
}
<Counter>**Clicks**: </Counter>
```
Generates:
<Shadow mode="open" className="nextra-border mt-6 rounded-xl border p-4">
<h2>Hello MDX</h2>
<Counter>**Clicks**: </Counter>
</Shadow>
Besides basic MDX, Nextra also has some advanced Markdown features built-in.
## GitHub Flavored Markdown
[GFM](https://github.github.com/gfm) is an extension of Markdown, created by
GitHub, that adds support for strikethrough, task lists, tables, and more.
### Strikethrough
~~removed~~
```md filename="Markdown"
~~removed~~
```
### Task list
- [x] Write the press release
- [ ] Update the website
- [ ] Contact the media
```md filename="Markdown"
- [x] Write the press release
- [ ] Update the website
- [ ] Contact the media
```
### Table
| Syntax | Description | Test Text |
| :------------ | :---------: | ----------: |
| Header | Title | Here's this |
| Paragraph | Text | And more |
| Strikethrough | | ~~Text~~ |
```md filename="Markdown"
| Syntax | Description | Test Text |
| :------------ | :---------: | ----------: |
| Header | Title | Here's this |
| Paragraph | Text | And more |
| Strikethrough | | ~~Text~~ |
```
### Autolinks
Visit https://nextjs.org.
```md
Visit https://nextjs.org.
```
### Custom heading id
You can specify custom heading id using the format `## My heading [#custom-id]`.
For example:
```md filename="Markdown"
## Long heading about Nextra [#about-nextra]
```
In this example, `#about-nextra` will be used as the heading link, replacing the
default `#long-heading-about-nextra`.
================================================
FILE: docs/app/docs/guide/page.mdx
================================================
---
asIndexPage: true
---
import {
BrushIcon,
GlobeIcon,
LightningIcon,
PictureIcon,
StarsIcon
} from '@components/icons'
import { InformationCircleIcon, LinkIcon, MarkdownIcon } from 'nextra/icons'
import { OverviewPage } from '../../_components/overview-page'
# Guide
The following features are configured via the Next.js configuration and are
available in all themes.
<OverviewPage
filePath={metadata.filePath}
icons={{
MarkdownIcon,
StarsIcon,
LinkIcon,
PictureIcon,
LightningIcon,
GlobeIcon,
BrushIcon,
InformationCircleIcon
}}
/>
================================================
FILE: docs/app/docs/guide/search/ai/page.mdx
================================================
import { Steps } from 'nextra/components'
# Ask AI
Enhance your Nextra documentation site with AI-powered chat assistance using
[Inkeep](https://docs.inkeep.com/cloud). This integration allows users to get
instant help and answers directly within your documentation, improving user
experience and reducing support burden.
## Setup
<Steps>
### Get an API key
Follow
[these steps](https://docs.inkeep.com/cloud/projects/overview#create-a-web-assistant)
to create an API key for your web assistant.
Copy and add the API key to your environment variables:
```dotenv filename=".env"
NEXT_PUBLIC_INKEEP_API_KEY="your_actual_api_key_here"
```
### Install the component library
Install the Inkeep React component library:
```sh npm2yarn
npm i @inkeep/cxkit-react
```
### Create the chat button component
Create a new file `inkeep-chat-button.tsx`:
```tsx filename="inkeep-chat-button.tsx"
'use client'
import { InkeepChatButton } from '@inkeep/cxkit-react'
import type { FC } from 'react'
export const ChatButton: FC = () => {
return (
<InkeepChatButton
aiChatSettings={{
apiKey: process.env.NEXT_PUBLIC_INKEEP_API_KEY!,
// Customize your AI assistant's appearance
aiAssistantAvatar: '/icon.svg', // Path to your assistant's avatar
aiAssistantName: 'Nextra Assistant' // Name shown to users
}}
baseSettings={{
// Match your site's brand colors
primaryBrandColor: '#238aff',
// Sync with your site's dark/light mode
colorMode: {
sync: {
target: 'html',
attributes: ['class'],
isDarkMode(attrs) {
return attrs.class === 'dark'
}
}
}
}}
/>
)
}
```
### Add to your root layout
Import and add the `ChatButton` component to your root layout file:
```tsx filename="app/layout.tsx"
import { Layout } from 'nextra-theme-docs' // or nextra-theme-blog or your custom theme
import { Head } from 'nextra/components'
import { getPageMap } from 'nextra/page-map'
import type { FC } from 'react'
import { ChatButton } from '../path/to/your/inkeep-chat-button'
const RootLayout: FC<LayoutProps<'/'>> = async ({ children }) => {
const pageMap = await getPageMap()
return (
<html lang="en" dir="ltr" suppressHydrationWarning>
<Head />
<body>
<ChatButton />
<Layout
pageMap={pageMap}
// ... other layout props
>
{children}
</Layout>
</body>
</html>
)
}
export default RootLayout
```
> [!IMPORTANT]
>
> The chat button will appear on all pages of your documentation site.
</Steps>
## Additional resources
- [Inkeep's official Nextra integration guide](https://docs.inkeep.com/cloud/integrations/nextra)
- [Inkeep React component documentation](https://docs.inkeep.com/cloud/ui-components/react/chat-button)
- [Inkeep Dashboard](https://portal.inkeep.com) for configuration and analytics
================================================
FILE: docs/app/docs/guide/search/page.mdx
================================================
import { Steps, Tabs } from 'nextra/components'
# Search Engine
Nextra includes a full-page search feature that makes it easy for users to find
relevant content across your entire documentation site.
> [!TIP]
>
> Check the
> [migration guide](https://the-guild.dev/blog/nextra-4#new-search-engine--pagefind)
> for more information.
## Setup
Nextra integrates with [Pagefind](https://pagefind.app), a static search library
that indexes your HTML files and provides lightning-fast, client-side full-text
search — all with no server required.
<Steps>
### Install `pagefind` as a dev dependency
```sh npm2yarn
npm i -D pagefind
```
### Add a `postbuild` script
Pagefind indexes `.html` files, so the indexing must happen **after building**
your application.
Add a `postbuild` script to your `package.json`:
<Tabs items={['Server builds', 'Static exports']}>
<Tabs.Tab>
```json filename="package.json"
"scripts": {
"postbuild": "pagefind --site .next/server/app --output-path public/_pagefind"
}
```
</Tabs.Tab>
<Tabs.Tab>
```json filename="package.json"
"scripts": {
"postbuild": "pagefind --site .next/server/app --output-path out/_pagefind"
}
```
</Tabs.Tab>
</Tabs>
### Ignore generated files
Add `_pagefind/` to your `.gitignore` file to avoid committing generated index
files.
### Verify indexing output
After building and running the `postbuild` script, check that a `_pagefind/`
directory exists in `public/` or `out/`. Start your app and test the search bar
to confirm everything is working.
</Steps>
## Configuration
Search is enabled by default. You can disable it entirely by setting
`search: false{:js}` in your `next.config.mjs` file:
```js filename="next.config.mjs" {4}
import nextra from 'nextra'
const withNextra = nextra({
search: false
})
export default withNextra()
```
To disable code block indexing while keeping search enabled set
`search: { codeblocks: false }{:js}`:
```js filename="next.config.mjs" {4}
import nextra from 'nextra'
const withNextra = nextra({
search: { codeblocks: false }
})
export default withNextra()
```
================================================
FILE: docs/app/docs/guide/ssg/page.mdx
================================================
---
icon: LightningIcon
---
import { compileMdx } from 'nextra/compile'
import { Callout } from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
# Next.js Static Rendering
[Static Rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#static-rendering-default)
is default server rendering strategy, where routes are rendered at **build
time** or in the background after
[data revalidation](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration).
The result is cached and can be distributed via a
[Content Delivery Network (CDN)](https://developer.mozilla.org/docs/Glossary/CDN)
for optimal performance.
Static rendering is ideal for routes with non-personalized data that can be
determined at build time, such as blog posts or product pages.
<SSGPage />
export async function SSGPage() {
const starsComponent = `{/* Via async components */}
export async function Stars() {
const response = await fetch('https://api.github.com/repos/shuding/nextra')
const repo = await response.json()
const stars = repo.stargazers_count
return <b>{stars}</b>
}
{/* Via async functions */}
export async function getUpdatedAt() {
const response = await fetch('https://api.github.com/repos/shuding/nextra')
const repo = await response.json()
const updatedAt = repo.updated_at
return new Date(updatedAt).toLocaleDateString()
}
<Callout emoji="🏆">
Nextra has <Stars /> stars on GitHub!
Last repository update _{await getUpdatedAt()}_.
</Callout>`
const mdx = `${starsComponent}
The number above was generated at build time via MDX server components. With
[Incremental Static Regeneration](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration)
enabled, it will be kept up to date.
## Example
Here's the MDX code for the example above:
~~~mdx filename="MDX"
${starsComponent}
~~~
`
const rawJs = await compileMdx(mdx)
return <MDXRemote compiledSource={rawJs} components={{ Callout }} />
}
================================================
FILE: docs/app/docs/guide/static-exports/page.mdx
================================================
import { Steps } from 'nextra/components'
# Static Exports
Export your pages statically, and deploy with [Nginx](https://nginx.org),
[GitHub Pages](https://pages.github.com) and more.
## Getting started
<Steps>
### Configuration
To enable a static export, update the options in `next.config.mjs` file as
follows:
```js filename="next.config.mjs" {7-10}
import nextra from 'nextra'
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: 'export',
images: {
unoptimized: true // mandatory, otherwise won't export
}
// Optional: Change the output directory `out` -> `dist`
// distDir: "build"
}
const withNextra = nextra({
// ... other Nextra config options
})
export default withNextra(nextConfig)
```
### Update `postbuild` script
Update the Pagefind [search engine setup](./search#add-a-postbuild-script) to
set the correct output path:
```json filename="package.json"
"scripts": {
"postbuild": "pagefind --site .next/server/app --output-path out/_pagefind"
}
```
### Building
Run the `build` command according to your package manager:
```sh npm2yarn
npm run build
```
By default, static export will be stored in `out` directory in the root of your
project.
For more in detail documentation for static export visit
[Next.js docs](https://nextjs.org/docs/app/building-your-application/deploying/static-exports).
</Steps>
================================================
FILE: docs/app/docs/guide/syntax-highlighting/_dynamic-code.tsx
================================================
'use client'
import { Button } from 'nextra/components'
import type { FC, ReactNode } from 'react'
import { useEffect, useRef } from 'react'
export const DynamicCode: FC<{ children: ReactNode }> = ({ children }) => {
const ref = useRef<HTMLDivElement>(null!)
const tokenRef = useRef<HTMLSpanElement>(undefined)
// Find the corresponding token from the DOM
useEffect(() => {
tokenRef.current = [
...ref.current.querySelectorAll<HTMLSpanElement>('code > span > span')
].find(el => el.textContent === '1')
}, [])
return (
<>
<div ref={ref} className="mt-6">
{children}
</div>
<div className="mt-3 flex justify-center gap-3 text-sm">
<Button
variant="outline"
onClick={() => {
const token = tokenRef.current!
const prev = token.textContent
token.textContent = String((+prev || 0) + 1)
}}
>
Increase the number
</Button>
<Button
variant="outline"
onClick={() => {
tokenRef.current!.textContent = '1 + 1'
}}
>
Change to `1 + 1`
</Button>
</div>
</>
)
}
================================================
FILE: docs/app/docs/guide/syntax-highlighting/page.mdx
================================================
---
icon: StarsIcon
---
import { OptionTable } from 'components/_table'
import { compileMdx } from 'nextra/compile'
import { MDXRemote } from 'nextra/mdx-remote'
# Syntax Highlighting
Nextra uses [Shiki](https://shiki.style) to do syntax highlighting at build
time. It's very reliable and performant. For example, adding this in your
Markdown file:
````md copy=false filename="Markdown"
```js
console.log('hello, world')
```
````
Results in:
```js copy=false
console.log('hello, world')
```
## Features
### Inlined code
Inlined syntax highlighting like `let x = 1{:jsx}` is also supported via the
`{:}` syntax:
```md copy=false filename="Markdown"
Inlined syntax highlighting is also supported `let x = 1{:jsx}` via:
```
### Highlighting lines
You can highlight specific lines of code by adding a `{}` attribute to the code
block:
````md copy=false filename="Markdown"
```js {1,4-5}
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```
````
Result:
```js copy=false {1,4-5}
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```
### Highlighting substrings
You can highlight specific substrings of code by adding a `//` attribute to the
code block:
````md copy=false filename="Markdown"
```js /useState/
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```
````
```js copy=false /useState/
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```
You can highlight only a part of the occurrences of that substring by adding a
number it: `/str/1`, or multiple: `/str/1-3`, `/str/1,3`.
### Copy button
By adding a `copy` attribute, a copy button will be added to the code block when
the user hovers over it:
````md copy=false filename="Markdown"
```js copy
console.log('hello, world')
```
````
Renders:
```js copy
console.log('hello, world')
```
> [!NOTE]
>
> You can enable this feature globally by setting `defaultShowCopyCode: true` in
> your Nextra configuration (`next.config.mjs` file). Once it's enabled
> globally, you can disable it via the `copy=false` attribute.
### Line numbers
You can add line numbers to your code blocks by adding a `showLineNumbers`
attribute:
````md copy=false filename="Markdown"
```js showLineNumbers
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```
````
Renders:
```js copy=false showLineNumbers
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```
### Filenames and titles
You can add a filename or a title to your code blocks by adding a `filename`
attribute:
````md copy=false filename="Markdown"
```js filename="example.js"
console.log('hello, world')
```
````
Renders:
```js copy=false filename="example.js"
console.log('hello, world')
```
### ANSI highlighting
You can highlight ANSI escape codes:
<ANSI />
export async function ANSI() {
const rawAnsi = `\`\`\`ansi
[0m [0;32m✓[0m [0;2msrc/[0mindex[0;2m.test.ts (1)[0m
[0;2m Test Files [0m [0;1;32m1 passed[0;98m (1)[0m
[0;2m Tests [0m [0;1;32m1 passed[0;98m (1)[0m
[0;2m Start at [0m 23:32:41
[0;2m Duration [0m 11ms
[42;1;39;0m PASS [0;32m Waiting for file changes...[0m
[0;2mpress [0;1mh[0;2m to show help, press [0;1mq[0;2m to quit
\`\`\``
const rawJs = await compileMdx(`~~~md filename="Markdown"
${rawAnsi}
~~~
Renders:
${rawAnsi}
`)
return <MDXRemote compiledSource={rawJs} />
}
## Supported languages
Check [this list](https://github.com/shikijs/shiki/blob/main/docs/languages.md)
for all supported languages.
{/* ## Customize the Theme */}
{/* Nextra uses CSS variables to define the colors for tokens. */}
## With dynamic content
Since syntax highlighting is done at build time, you can't use dynamic content
in your code blocks. However, since MDX is very powerful there is a workaround
via client JS. For example:
import { DynamicCode } from './_dynamic-code'
<DynamicCode>
```js copy=false filename="dynamic-code.js"
function hello() {
const x = 2 + 3
console.log(1)
}
```
</DynamicCode>
This workaround has a limitation that updated content won't be re-highlighted.
For example if we update the number to `1 + 1`, it will be incorrectly
highlighted.
Check out the
[code](https://github.com/shuding/nextra/blob/main/docs/app/docs/guide/syntax-highlighting/_dynamic-code.tsx)
to see how it works.
## Disable syntax highlighting
You can opt out of syntax highlighting for using one of your own. You can
disable syntax highlighting globally by setting `codeHighlight: false` in your
Nextra configuration (`next.config.mjs` file).
<OptionTable
options={[
[
'codeHighlight',
'boolean',
'Enable or disable syntax highlighting. Defaults to `true`.'
]
]}
/>
## Custom grammar
Shiki accepts a
[VSCode TextMate Grammar](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide)
for syntax highlighting with custom language grammars.
You can provide these grammars by overriding the `getHighlighter` function in
`mdxOptions.rehypePrettyCodeOptions` option in your Nextra config inside
`next.config.mjs`:
```js copy=false filename="next.config.mjs" {13-18}
import { BUNDLED_LANGUAGES } from 'shiki'
nextra({
// ... other Nextra config options
mdxOptions: {
rehypePrettyCodeOptions: {
getHighlighter: options =>
getHighlighter({
...options,
langs: [
...BUNDLED_LANGUAGES,
// custom grammar options, see the Shiki documentation for how to provide these options
{
id: 'my-lang',
scopeName: 'source.my-lang',
aliases: ['mylang'], // Along with id, aliases will be included in the allowed names you can use when writing Markdown
path: '../../public/syntax/grammar.tmLanguage.json'
}
]
})
}
}
})
```
## Custom themes
Within `mdxOptions.rehypePrettyCodeOptions` you may also provide custom themes
instead of [relying on CSS Variables](/docs/guide/syntax-highlighting):
```js copy=false filename="next.config.mjs" {4}
nextra({
// ... other Nextra config options
mdxOptions: {
rehypePrettyCodeOptions: {
// VSCode theme or built-in Shiki theme, see Shiki documentation for more information
theme: JSON.parse(
readFileSync('./public/syntax/arctis_light.json', 'utf8')
)
}
}
})
```
### Multiple themes (dark and light mode)
Pass your themes to `theme`, where the keys represent the color mode:
```js copy=false filename="next.config.mjs" {5-8}
nextra({
// ... other Nextra config options
mdxOptions: {
rehypePrettyCodeOptions: {
theme: {
dark: 'nord',
light: 'min-light'
}
}
}
})
```
================================================
FILE: docs/app/docs/guide/turbopack/page.mdx
================================================
# Usage with Turbopack
To use [Turbopack](https://nextjs.org/docs/architecture/turbopack), simple
append the `--turbopack` flag to your development command:
```diff filename="package.json"
"scripts": {
- "dev": "next dev"
+ "dev": "next dev --turbopack"
}
```
> [!NOTE]
>
> Without `--turbopack` flag Next.js under the hood uses
> [Webpack](https://github.com/webpack/webpack), written in JavaScript.
## Only serializable options are supported
For this moment only JSON serializable values can be passed in `nextra`
function. This mean that with Turbopack enabled you can't pass custom
`remarkPlugins`, `rehypePlugins` or `recmaPlugins` since they are functions.
The following options could be passed only without Turbopack or only while
building your app with `next build`
([since Turbopack isn't support `next build` for now](https://nextjs.org/docs/architecture/turbopack#unsupported-features)
and Webpack is used instead).
```js filename="next.config.js" {5-7}
import nextra from 'nextra'
const withNextra = nextra({
mdxOptions: {
remarkPlugins: [myRemarkPlugin],
rehypePlugins: [myRehypePlugin],
recmaPlugins: [myRecmaPlugin]
}
})
```
If you try to pass them, you'll get an error from Turbopack:
```text copy=false
Error: loader nextra/loader for match "./{src/app,app}/**/page.{md,mdx}" does not have serializable options.
Ensure that options passed are plain JavaScript objects and values.
```
================================================
FILE: docs/app/docs/page.mdx
================================================
---
description:
Nextra is a framework built on top of Next.js that enables the creation of
content-focused websites. It combines the robust features of Next.js with
enhanced capabilities for crafting Markdown-based content.
---
import { Cards, Image } from 'nextra/components'
import { cloneElement } from 'react'
export default function MdxLayout(props) {
return cloneElement(props.children, {
components: {
img: Image
}
})
}
# Introduction
**Nextra** is a framework on top of Next.js, that lets you build content focused
websites. It has all the great features from Next.js, plus extra power to create
Markdown-based content with ease.
## Quick start
To start using Nextra, you need to select a theme first:
<Cards num={2}>
<Cards.Card arrow title="Documentation theme" href="/docs/docs-theme/start">
<></>
</Cards.Card>
<Cards.Card arrow title="Blog theme" href="/docs/blog-theme/start">
<></>
</Cards.Card>
</Cards>
If you want to use Nextra without using these built-in themes, you can follow
the [Custom Theme](/docs/custom-theme) docs.
## FAQ
The Nextra FAQ is a collection of useful questions and answers about the
project. If you have a question that isn't answered here, please
[open a discussion](https://github.com/shuding/nextra/discussions).
<details>
{/* prettier-ignore */}
<summary>Can I use Nextra with Next.js `pages` router?</summary>
Nextra 4 only works with the `app` router. Only Nextra 1/2/3 supports the
`pages` router.
</details>
<details>
<summary>Can I use X with Nextra?</summary>
The answer is "yes" for most things. Since Nextra is just a Next.js plugin, almost all the things
that can be done with React can be done with Nextra. Here are some examples and guides:
- [Use Tailwind CSS](/docs/guide/tailwind-css)
- [Use custom CSS and Sass](/docs/guide/custom-css)
- [Use custom fonts](https://nextjs.org/docs/basic-features/font-optimization)
</details>
<details>
{/* prettier-ignore */}
<summary>How can I add a live coding component in Nextra?</summary>
There are libraries like [Sandpack](https://sandpack.codesandbox.io) and
[react-live](https://github.com/FormidableLabs/react-live) that can help you
add live coding components to your MDX.
</details>
================================================
FILE: docs/app/env.d.ts
================================================
declare module '*.svg?svgr' {
import type { FC, SVGProps } from 'react'
const ReactComponent: FC<SVGProps<SVGElement>>
export default ReactComponent
}
declare module '*.mdx' {
import type { FC } from 'react'
import type { MDXComponents } from 'nextra/mdx-components'
const ReactComponent: FC<{
components?: MDXComponents
}>
export default ReactComponent
}
================================================
FILE: docs/app/globals.css
================================================
@import 'nextra-theme-docs/style.css';
@import 'tailwindcss';
/* Whitelist Tailwind CSS classes from <Bleed> TSDoc examples */
@source inline('aspect-video');
@source inline('py-10');
@variant dark (&:where(.dark *));
@theme {
}
body {
font-feature-settings:
'rlig' 1,
'calt' 1;
}
.home-content p {
margin-top: 1.5em;
line-height: 1.75em;
}
code.text-\[\.9em\] {
font-size: 14px;
}
@media screen and (max-width: 1200px) {
.home-content .hide-medium {
display: none;
}
}
@media screen and (max-width: 720px) {
.home-content p {
font-size: 0.9rem;
}
.home-content .hide-small {
display: none;
}
}
/* adds labels to the sidebar links */
.badge-new {
@apply dark:after:border-blue-200/30 dark:after:bg-blue-900/30 dark:after:text-blue-200;
&:after {
@apply ms-1.5 rounded-full border border-blue-200 bg-blue-100 px-1.5 text-xs font-bold text-blue-900 content-["New"];
}
}
================================================
FILE: docs/app/layout.tsx
================================================
import { getEnhancedPageMap } from '@components/get-page-map'
import { NextraLogo, VercelLogo } from '@components/icons'
import { ChatButton } from '@components/inkeep-chat-button'
import cn from 'clsx'
import type { Metadata } from 'next'
import NextImage from 'next/image'
import { Footer, Layout, Link, Navbar } from 'nextra-theme-docs'
import { Anchor, Banner, Head } from 'nextra/components'
import type { FC } from 'react'
import inkeep from './showcase/_logos/inkeep.png'
import xyflow from './showcase/_logos/xyflow.png'
import './globals.css'
export const metadata: Metadata = {
description: 'Make beautiful websites with Next.js & MDX.',
metadataBase: new URL('https://nextra.site'),
keywords: [
'Nextra',
'Next.js',
'React',
'JavaScript',
'MDX',
'Markdown',
'Static Site Generator'
],
generator: 'Next.js',
applicationName: 'Nextra',
appleWebApp: {
title: 'Nextra'
},
title: {
default: 'Nextra – Next.js Static Site Generator',
template: '%s | Nextra'
},
openGraph: {
// https://github.com/vercel/next.js/discussions/50189#discussioncomment-10826632
url: './',
siteName: 'Nextra',
locale: 'en_US',
type: 'website'
},
other: {
'msapplication-TileColor': '#fff'
},
twitter: {
site: 'https://nextra.site'
},
alternates: {
// https://github.com/vercel/next.js/discussions/50189#discussioncomment-10826632
canonical: './'
}
}
const banner = (
<Banner>
🎉 Nextra 4.0 has been released.{' '}
<Link href="https://the-guild.dev/blog/nextra-4" className="text-current!">
Read blogpost
</Link>
</Banner>
)
const navbar = (
<Navbar
logo={
<NextraLogo
height="20"
className={cn(
'hover:transition-all hover:duration-1000 motion-reduce:hover:transition-none',
'[mask-image:linear-gradient(60deg,#000_25%,rgba(0,0,0,.2)_50%,#000_75%)] [mask-size:400%] [mask-position:0]',
'hover:[mask-position:100%]'
)}
/>
}
projectLink="https://github.com/shuding/nextra"
/>
)
const footer = (
<Footer className="flex-col items-center md:items-start">
<a
className="x:focus-visible:nextra-focus flex items-center gap-1"
target="_blank"
rel="noreferrer"
title="vercel.com homepage"
href="https://vercel.com?utm_source=nextra.site"
>
Powered by
<VercelLogo height="20" />
</a>
<p className="mt-6 text-xs">
© {new Date().getFullYear()} The Nextra Project.
</p>
</Footer>
)
const RootLayout: FC<LayoutProps<'/'>> = async ({ children }) => {
const pageMap = await getEnhancedPageMap()
return (
<html lang="en" dir="ltr" suppressHydrationWarning>
<Head />
<body>
<ChatButton />
<Layout
banner={banner}
navbar={navbar}
pageMap={pageMap}
docsRepositoryBase="https://github.com/shuding/nextra/tree/main/docs"
editLink="Edit this page on GitHub"
sidebar={{ defaultMenuCollapseLevel: 1 }}
footer={footer}
toc={{
extraContent: (
<>
<b className="mt-2 text-xs">Sponsored by:</b>
{[
{
url: 'https://inkeep.com',
alt: 'AI Agents that get real work done',
img: inkeep
},
{
url: 'https://xyflow.com',
alt: 'Wire your ideas with xyflow!',
img: xyflow
}
].map(o => (
<Anchor
key={o.url}
href={`${o.url}?utm_source=nextra.site&utm_campaign=nextra&utm_content=sidebarLink`}
>
<NextImage
src={o.img}
title={o.alt}
alt={o.alt}
className="nextra-border rounded-sm border"
/>
</Anchor>
))}
</>
)
}}
>
{children}
</Layout>
</body>
</html>
)
}
export default RootLayout
================================================
FILE: docs/app/not-found.ts
================================================
export { NotFoundPage as default } from 'nextra-theme-docs'
================================================
FILE: docs/app/og/route.tsx
================================================
/* eslint react/no-unknown-property: ['error', { ignore: ['tw'] }] */
import { NextraLogo } from '@components/icons'
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
// eslint-disable-next-line unicorn/prefer-top-level-await -- this will break og image
const font = fetch(new URL('Inter-SemiBold.otf', import.meta.url)).then(res =>
res.arrayBuffer()
)
export async function GET(req: Request): Promise<Response> {
try {
const { searchParams } = new URL(req.url)
// ?title=<title>
const title =
searchParams.get('title')?.slice(0, 75) || 'Nextra Documentation'
return new ImageResponse(
<div
tw="text-white px-20 py-[70px] bg-[#030303] h-full w-full flex justify-between flex-col"
style={{
backgroundImage:
'radial-gradient(circle at 25px 25px, #333 2%, transparent 0%), radial-gradient(circle at 75px 75px, #333 2%, transparent 0%)',
backgroundSize: '100px 100px',
backgroundPosition: '-30px -10px'
}}
>
<NextraLogo height="40" />
<h1
tw="text-transparent text-[82px] m-0 mb-10 tracking-tighter leading-[1.1]"
style={{
textShadow: '0 2px 30px #000',
backgroundImage: 'linear-gradient(90deg, #fff 40%, #aaa)',
backgroundClip: 'text',
// To preserve new line
whiteSpace: 'pre'
}}
>
{title}
</h1>
<p tw="m-0 text-3xl tracking-tight">
Create beautiful websites with Next.js & MDX.
</p>
</div>,
{
width: 1200,
height: 630,
fonts: [
{
name: 'inter',
data: await font,
style: 'normal'
}
]
}
)
} catch (error) {
console.error(error)
return new Response('Failed to generate the image', { status: 500 })
}
}
================================================
FILE: docs/app/page.css
================================================
.content-container {
max-width: var(--nextra-content-width);
padding-left: max(env(safe-area-inset-left), 1.5rem);
padding-right: max(env(safe-area-inset-right), 1.5rem);
margin: 0 auto;
}
.features-container {
margin: 8rem 0 0;
padding: 4rem 0;
background-color: #f3f4f6;
}
.features-container .content-container {
margin-top: -8rem;
}
.dark .features-container {
background-color: #000;
}
.headline {
display: inline-flex;
font-size: 3.125rem;
font-size: min(4.375rem, max(8vw, 2.5rem));
font-weight: 700;
font-feature-settings: initial;
letter-spacing: -0.12rem;
margin-left: -0.2rem;
margin-top: 3.4rem;
line-height: 1.1;
background-image: linear-gradient(146deg, #000, #757a7d);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.dark .headline {
background-image: linear-gradient(146deg, #fff, #757a7d);
}
.subtitle {
font-size: 1.3rem;
font-size: min(1.3rem, max(3.5vw, 1.2rem));
font-feature-settings: initial;
line-height: 1.6;
}
#docs-card {
color: #fff;
text-shadow: 0 0 1rem rgba(0, 0, 0, 0.1);
}
#docs-card img {
object-fit: cover;
object-position: left;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100%;
z-index: 0;
user-select: none;
pointer-events: none;
}
#docs-card img:nth-child(2) {
display: none;
}
.dark #docs-card img:nth-child(2) {
display: initial;
}
.dark #docs-card img:nth-child(1) {
display: none;
}
#highlighting-card {
min-height: 300px;
background-image:
linear-gradient(to top, transparent, #fff 50%),
url(/assets/syntax-highlighting.svg);
background-size: 634px;
background-position: -6px calc(100% + 4px);
background-repeat: no-repeat;
}
.dark #highlighting-card {
background-image:
linear-gradient(to top, transparent, #202020 50%),
url(/assets/syntax-highlighting.svg);
}
.feat-darkmode {
min-height: 300px;
}
.feat-darkmode h3 {
font-size: 48px;
}
#search-card {
display: flex;
flex-direction: column;
justify-content: center;
}
#search-card p {
max-width: 320px;
}
#search-card video {
position: absolute;
right: 0;
top: 24px;
height: 430px;
pointer-events: none;
max-width: 60%;
}
#fs-card {
min-height: 240px;
}
#fs-card h3 {
text-align: left;
width: min(300px, 41%);
min-width: 155px;
}
#a11y-card {
background-image: url(/assets/high-contrast.png);
background-position: -160px 160px;
}
@media screen and (max-width: 1300px) {
#a11y-card {
background-image:
linear-gradient(to bottom, white, transparent),
url(/assets/high-contrast.png);
}
}
@media screen and (max-width: 1200px) {
#highlighting-card {
aspect-ratio: auto;
}
.feat-darkmode h3 {
font-size: 4vw;
font-size: min(48px, max(4vw, 30px));
}
#search-card video {
aspect-ratio: 787/623;
height: auto;
}
.headline {
letter-spacing: -0.08rem;
}
}
@media screen and (max-width: 1024px) {
#docs-card {
aspect-ratio: 135/86;
}
#search-card {
aspect-ratio: 8/3;
}
#search-card h3 {
text-align: left;
}
#highlighting-card {
background-size: 136%;
}
#a11y-card {
background-image: url(/assets/high-contrast.png);
background-position: center 160px;
}
}
@media screen and (max-width: 768px) {
#docs-card {
min-height: 348px;
width: 100%;
aspect-ratio: auto;
}
#docs-card img {
object-position: -26px 0;
width: 250%;
max-width: initial;
}
}
@media screen and (max-width: 640px) {
#search-card {
aspect-ratio: 2.5/2;
justify-content: flex-start;
align-items: stretch;
min-height: 350px;
}
#search-card h3 {
text-align: center;
}
#search-card p {
max-width: 100%;
}
#search-card video {
position: relative;
margin: 0.75em -1.75em 0;
max-width: calc(100% + 3.5em);
}
.dark #search-card video {
mix-blend-mode: lighten;
}
}
================================================
FILE: docs/app/page.module.css
================================================
.file {
display: inline-block;
font-size: 0.9em;
padding: 1px 6px;
border-radius: 0.375rem;
border: 1px solid #0077ff;
color: #0077ff;
font-weight: 600;
cursor: default;
user-select: none;
}
.file.active {
background-color: #0077ff;
color: white;
}
.comparison {
display: flex;
justify-content: space-evenly;
align-items: center;
}
.comparison > svg {
opacity: 0.3;
}
.optimization {
display: flex;
justify-content: center;
margin: 0;
padding: 1.5rem 1rem;
background: linear-gradient(27deg, #3d3d3d, #000000);
color: #e3e3e3;
border-radius: 0.375rem;
font-weight: 300;
}
:global(.dark) .optimization {
background: linear-gradient(27deg, #3d3d3d, #252525);
}
a.cta {
display: inline-block;
background: linear-gradient(to bottom, #238aff, #0077ff);
text-decoration: none;
border-radius: 9999px;
color: white;
padding: 0.75rem 1.5rem;
margin-top: 0.5rem;
text-shadow: 0 1px 1px #00387838;
box-shadow: 0 1px 2px #00295738;
transition: all 0.2s ease;
-webkit-user-drag: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
a.cta span {
display: inline-block;
transition: all 0.2s ease;
}
a.cta:hover span {
transform: translateX(3px);
}
a.cta:hover {
box-shadow: 0 5px 30px -10px #0078ffab;
filter: brightness(1.05);
}
a.cta:active {
box-shadow: 0 1px 3px #00295738;
filter: brightness(0.95);
}
a.cta:active span {
transform: translateX(5px);
}
a.cta:focus-visible {
outline: 2px solid
hsl(var(--nextra-primary-hue) var(--nextra-primary-saturation) 77%);
outline-offset: 2px;
}
a.cta:focus-visible span {
transform: translateX(3px);
}
================================================
FILE: docs/app/page.tsx
================================================
import { ArrowRightIcon } from '@components/icons'
import type { Metadata } from 'next'
import Image from 'next/image'
import { Link } from 'nextra-theme-docs'
import { MdxIcon } from 'nextra/icons'
import docsCardDark from 'public/assets/card-1.dark.png'
import docsCard from 'public/assets/card-1.png'
import { Feature, Features } from './_components/features'
import { MotionDiv, MotionH3 } from './_components/framer-motion'
import { I18n } from './_components/i18n-demo'
import styles from './page.module.css'
import './page.css'
import type { FC } from 'react'
export const metadata: Metadata = {
description:
'Build fast, customizable, and content-rich websites with Nextra. Powered by Next.js, it offers seamless Markdown support, customizable themes, file conventions, and easy integration with MDX, making it perfect for documentation, blogs, and static websites.'
}
const IndexPage: FC = () => {
return (
<div className="home-content">
<div className="content-container">
<h1 className="headline">
Make beautiful websites <br className="max-sm:hidden" />
with Next.js & MDX
</h1>
<p className="subtitle">
Simple, powerful and flexible site generation framework{' '}
<br className="max-md:hidden" />
with everything you love from{' '}
<Link href="https://nextjs.org" className="text-current">
Next.js
</Link>
.
</p>
<p className="subtitle">
<Link className={styles.cta} href="/docs">
Get started <span>→</span>
</Link>
</p>
</div>
<div className="features-container x:border-b nextra-border">
<div className="content-container">
<Features>
<Feature
index={0}
large
centered
id="docs-card"
href="/docs/docs-theme/start"
>
<Image src={docsCard} alt="Background" loading="eager" />
<Image
src={docsCardDark}
alt="Background (Dark)"
loading="eager"
/>
<h3>
Full-power documentation <br className="show-on-mobile" />
in minutes
</h3>
</Feature>
<Feature index={1} centered href="/docs/guide/image">
<h3>
Links and images are <br className="show-on-mobile" />
always <span className="font-light">optimized</span>
</h3>
<p className="mb-8 text-start">
Nextra automatically converts Markdown links and images to use{' '}
<Link href="https://nextjs.org/docs/routing/introduction#linking-between-pages">
Next.js Link
</Link>{' '}
and{' '}
<Link href="https://nextjs.org/docs/app/getting-started/images#local-images">
Next.js Image
</Link>{' '}
when possible. No slow navigation or layout shift.
</p>
<div>
<div className={styles.optimization}>
<div style={{ fontSize: '.9rem' }} className="leading-8">
<code>[Learn more](/more)</code>
<br />
<code></code>
</div>
</div>
<ArrowRightIcon
width="1.2em"
className="mx-auto my-6 rotate-90 text-neutral-600 dark:text-neutral-400"
/>
<div className={styles.optimization}>
<div style={{ fontSize: '.9rem' }} className="leading-8">
<code>{'<Link .../>'}</code>
<br />
<code>{'<Image .../>'}</code>
</div>
</div>
</div>
</Feature>
<Feature
index={2}
id="highlighting-card"
href="/docs/guide/syntax-highlighting"
>
<h3>
Advanced syntax <br className="show-on-mobile" />
highlighting solution
</h3>
<p>
Performant and reliable build-time syntax highlighting powered
by <Link href="https://shiki.style">Shiki</Link>.
</p>
</Feature>
<Feature index={3} href="/docs/guide/i18n">
<h3>
I18n as easy as <br className="show-on-mobile" />
creating new files
</h3>
<p className="mb-4">
Place your page files in folders specific to each locale, Nextra
and Next.js will handle the rest for you.
</p>
<I18n />
</Feature>
<Feature
index={4}
centered
className="flex flex-col items-center justify-center bg-[url(/assets/gradient-bg.jpeg)] bg-cover bg-center text-white"
href="/docs/guide/markdown"
>
<MdxIcon className="w-4/6 [filter:drop-shadow(0_2px_10px_rgba(0,0,0,.1))]" />
<p style={{ textShadow: '0 2px 4px rgb(0 0 0 / 20%)' }}>
<Link
href="https://mdxjs.com/blog/v3"
className="!text-current"
>
MDX 3
</Link>{' '}
lets you use Components inside Markdown,{' '}
<br className="hide-medium" />
with huge performance boost since v1.
</p>
</Feature>
<Feature
index={5}
centered
className="feat-darkmode flex items-center justify-center"
>
<MotionDiv
animate={{
backgroundPosition: [
'0% 0%',
'50% 40%',
'50% 40%',
'100% 100%'
],
backgroundImage: [
'radial-gradient(farthest-corner, #e2e5ea, #e2e5ea)',
'radial-gradient(farthest-corner, #06080a, #e2e5ea)',
'radial-gradient(farthest-corner, #06080a, #e2e5ea)',
'radial-gradient(farthest-corner, #e2e5ea, #e2e5ea)'
]
}}
transition={{
backgroundPosition: {
times: [0, 0.5, 0.5, 1],
repeat: Infinity,
duration: 10,
delay: 1
},
backgroundImage: {
times: [0, 0.2, 0.8, 1],
repeat: Infinity,
duration: 10,
delay: 1
}
}}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundImage:
'radial-gradient(farthest-corner, #06080a, #e2e5ea)',
backgroundSize: '400% 400%',
backgroundRepeat: 'no-repeat'
}}
/>
<MotionH3
animate={{
color: ['#dae5ff', '#fff', '#fff', '#dae5ff']
}}
transition={{
color: {
times: [0.25, 0.35, 0.7, 0.8],
repeat: Infinity,
duration: 10,
delay: 1
}
}}
style={{
position: 'relative',
mixBlendMode: 'difference'
}}
>
Dark <br />
mode <br />
included
</MotionH3>
</Feature>
<Feature
index={6}
large
id="search-card"
href="/docs/docs-theme/theme-configuration#search"
>
<h3>
Full-text search,
<br />
zero-config needed
</h3>
<p className="z-2">
Nextra indexes your content automatically at build-time and
performs incredibly fast full-text search via{' '}
<Link href="https://github.com/cloudcannon/pagefind">
Pagefind
</Link>
.
</p>
<div className="absolute inset-0 z-1 size-full bg-[linear-gradient(to_right,white_250px,_transparent)] max-sm:hidden dark:bg-[linear-gradient(to_right,#202020_250px,_transparent)]" />
<video
autoPlay
loop
muted
playsInline
className="x:focus-visible:nextra-focus block dark:hidden"
>
<source src="/assets/search.mp4" type="video/mp4" />
</video>
<video
autoPlay
loop
muted
playsInline
className="x:focus-visible:nextra-focus hidden -translate-x-4 dark:block"
>
<source src="/assets/search-dark.mp4" type="video/mp4" />
</video>
</Feature>
<Feature
index={7}
large
id="fs-card"
style={{
color: 'white',
backgroundImage:
'url(/assets/routing.png), url(/assets/gradient-bg.jpeg)',
backgroundSize: '140%, 180%',
backgroundPosition: '130px -8px, top',
backgroundRepeat: 'no-repeat',
textShadow: '0 1px 6px rgb(38 59 82 / 18%)',
aspectRatio: '1.765'
}}
href="/docs/docs-theme/page-configuration"
>
<h3>
Organize pages intuitively, <br />
with file-system routing from Next.js
</h3>
</Feature>
<Feature
index={8}
id="a11y-card"
style={{
backgroundSize: 750,
backgroundRepeat: 'no-repeat',
minHeight: 288
}}
>
<h3>A11y as a top priority</h3>
<p>
Nextra respects system options <br className="show-on-mobile" />
such as <b>Increase Contrast</b> and <b>Reduce Motion</b>.
</p>
</Feature>
<Feature index={9} href="/docs/guide/ssg">
<h3>
Hybrid rendering, <br />
next generation
</h3>
<p className="mr-6">
You can leverage the hybrid rendering power from Next.js with
your Markdown content including{' '}
<Link href="https://nextjs.org/docs/app/building-your-application/rendering/server-components">
Server Components
</Link>
,{' '}
<Link href="https://nextjs.org/docs/app/building-your-application/rendering/client-components">
Client Components
</Link>
, and{' '}
<Link href="https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration">
Incremental Static Regeneration (ISR)
</Link>
.
</p>
</Feature>
<Feature index={10} large>
<h3>And more...</h3>
<p>
SEO / RTL Layout / Pluggable Themes / Built-in Components / Last
Git Edit Time / Multi-Docs...
<br />A lot of new possibilities to be explored.
</p>
<p className="subtitle">
<Link className="no-underline" href="/docs">
Start using Nextra →
</Link>
</p>
</Feature>
</Features>
</div>
</div>
</div>
)
}
export default IndexPage
================================================
FILE: docs/app/showcase/page.mdx
================================================
---
description:
Explore projects powered by Nextra, showcasing a diverse range of websites and
applications built with this powerful Next.js framework, from GraphQL tools to
JavaScript resources.
---
import { Cards, Image } from 'nextra/components'
import { cloneElement } from 'react'
# Showcase
Projects powered by Nextra
{/* prettier-ignore */}
<Cards>
<>[](https://reactflow.dev)</>
<>[](https://svelteflow.dev)</>
<>[](https://speakeasy.com/docs)</>
<>[](https://thegraph.com/docs/en)</>
<>[](https://graphql.org)</>
<>[](https://the-guild.dev/graphql/hive)</>
<>[](https://swr.vercel.app)</>
<>[](https://cobe.vercel.app)</>
<>[](https://javascriptpatterns.vercel.app)</>
<>[](https://codesandbox.io/docs/learn/introduction/overview)</>
<>[](https://docs.docsgpt.co.uk)</>
<>[](https://cloudquery.io)</>
<>[](https://edge-runtime.vercel.app)</>
<>[](https://docs.sound.xyz)</>
<>[](https://panda-css.com)</>
<>[](https://kuma-ui.com)</>
<>[](https://langfuse.com)</>
<>[](https://the-guild.dev)</>
<>[](https://the-guild.dev/graphql/yoga-server)</>
<>[](https://the-guild.dev/graphql/envelop)</>
<>[](https://the-guild.dev/graphql/inspector)</>
<>[](https://the-guild.dev/graphql/codegen)</>
<>[](https://the-guild.dev/graphql/mesh)</>
<>[](https://the-guild.dev/graphql/tools)</>
<>[](https://the-guild.dev/graphql/modules)</>
<>[](https://the-guild.dev/graphql/eslint)</>
<>[](https://the-guild.dev/graphql/config)</>
<>[](https
gitextract_ikx05y15/ ├── .changeset/ │ └── config.json ├── .editorconfig ├── .github/ │ ├── CODE_OF_CONDUCT.md │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── lint.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .node-version ├── .npmrc ├── .prettierignore ├── LICENSE ├── README.md ├── docs/ │ ├── app/ │ │ ├── _components/ │ │ │ ├── features/ │ │ │ │ ├── index.tsx │ │ │ │ ├── style.module.css │ │ │ │ └── themes-animation.tsx │ │ │ ├── framer-motion.ts │ │ │ ├── i18n-demo.tsx │ │ │ └── overview-page.tsx │ │ ├── _meta.global.tsx │ │ ├── about/ │ │ │ └── page.mdx │ │ ├── api/ │ │ │ ├── [name]/ │ │ │ │ └── page.tsx │ │ │ └── page.mdx │ │ ├── blog/ │ │ │ └── page.mdx │ │ ├── docs/ │ │ │ ├── advanced/ │ │ │ │ ├── customize-the-cascade-layers/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── latex/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── mermaid/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── npm2yarn/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── page.mdx │ │ │ │ ├── remote/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── table/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── tailwind-css/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── twoslash/ │ │ │ │ │ └── page.mdx │ │ │ │ └── typescript/ │ │ │ │ └── page.mdx │ │ │ ├── blog-theme/ │ │ │ │ ├── get-posts-and-tags/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── page.mdx │ │ │ │ ├── posts/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── rss/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── start/ │ │ │ │ │ └── page.mdx │ │ │ │ └── tags/ │ │ │ │ └── page.mdx │ │ │ ├── built-ins/ │ │ │ │ ├── [name]/ │ │ │ │ │ └── page.tsx │ │ │ │ └── page.mdx │ │ │ ├── custom-theme/ │ │ │ │ ├── old.mdx │ │ │ │ └── page.mdx │ │ │ ├── docs-theme/ │ │ │ │ ├── api/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── built-ins/ │ │ │ │ │ ├── footer/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ ├── layout/ │ │ │ │ │ │ ├── old.mdx │ │ │ │ │ │ └── page.mdx │ │ │ │ │ ├── navbar/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ ├── not-found/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ └── page.mdx │ │ │ │ ├── page.mdx │ │ │ │ └── start/ │ │ │ │ └── page.mdx │ │ │ ├── file-conventions/ │ │ │ │ ├── content-directory/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── mdx-components-file/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── meta-file/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── page-file/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── page.mdx │ │ │ │ └── src-directory/ │ │ │ │ └── page.mdx │ │ │ ├── guide/ │ │ │ │ ├── custom-css/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── github-alert-syntax/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── i18n/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── image/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── link/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── markdown/ │ │ │ │ │ ├── _counter.tsx │ │ │ │ │ └── page.mdx │ │ │ │ ├── page.mdx │ │ │ │ ├── search/ │ │ │ │ │ ├── ai/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ └── page.mdx │ │ │ │ ├── ssg/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── static-exports/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── syntax-highlighting/ │ │ │ │ │ ├── _dynamic-code.tsx │ │ │ │ │ └── page.mdx │ │ │ │ └── turbopack/ │ │ │ │ └── page.mdx │ │ │ └── page.mdx │ │ ├── env.d.ts │ │ ├── globals.css │ │ ├── layout.tsx │ │ ├── not-found.ts │ │ ├── og/ │ │ │ ├── Inter-SemiBold.otf │ │ │ └── route.tsx │ │ ├── page.css │ │ ├── page.module.css │ │ ├── page.tsx │ │ ├── showcase/ │ │ │ └── page.mdx │ │ └── sponsors/ │ │ └── page.mdx │ ├── components/ │ │ ├── _slider.tsx │ │ ├── _table/ │ │ │ ├── index.tsx │ │ │ └── style.module.css │ │ ├── content-and-app-file-tree.tsx │ │ ├── example-code.tsx │ │ ├── example-tsdoc.mdx │ │ ├── generate-api-reference.ts │ │ ├── get-page-map.ts │ │ ├── icons/ │ │ │ └── index.ts │ │ ├── inkeep-chat-button.tsx │ │ ├── install-nextra-theme.mdx │ │ ├── playground-demo.tsx │ │ ├── ready-to-go.mdx │ │ ├── shadow.jsx │ │ ├── toggle-visibility-section.tsx │ │ └── video.tsx │ ├── mdx-components.tsx │ ├── next-sitemap.config.js │ ├── next.config.ts │ ├── package.json │ ├── postcss.config.mjs │ ├── tsconfig.json │ └── vercel.json ├── examples/ │ ├── blog/ │ │ ├── app/ │ │ │ ├── _meta.global.js │ │ │ ├── layout.jsx │ │ │ ├── page.mdx │ │ │ ├── posts/ │ │ │ │ ├── (with-comments)/ │ │ │ │ │ ├── aaron-swartz-a-programmable-web/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ ├── code-blocks/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ ├── draft/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ ├── layout.jsx │ │ │ │ │ ├── lists/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ ├── nextra-components/ │ │ │ │ │ │ └── page.mdx │ │ │ │ │ └── table/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── get-posts.js │ │ │ │ └── page.jsx │ │ │ ├── rss.xml/ │ │ │ │ └── route.js │ │ │ └── tags/ │ │ │ └── [tag]/ │ │ │ └── page.jsx │ │ ├── mdx-components.jsx │ │ ├── next.config.js │ │ └── package.json │ ├── custom-theme/ │ │ ├── app/ │ │ │ ├── _components/ │ │ │ │ ├── footer.tsx │ │ │ │ ├── navbar.tsx │ │ │ │ ├── nextra-theme.tsx │ │ │ │ ├── sidebar.tsx │ │ │ │ └── toc.tsx │ │ │ ├── _meta.global.ts │ │ │ ├── docs/ │ │ │ │ ├── nested-level/ │ │ │ │ │ └── bar/ │ │ │ │ │ └── page.mdx │ │ │ │ ├── one-level/ │ │ │ │ │ └── page.mdx │ │ │ │ └── page.mdx │ │ │ ├── layout.tsx │ │ │ └── page.mdx │ │ ├── mdx-components.jsx │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── public/ │ │ │ └── .gitkeep │ │ └── tsconfig.json │ ├── docs/ │ │ ├── mdx-components.js │ │ ├── next.config.mjs │ │ ├── package.json │ │ └── src/ │ │ ├── app/ │ │ │ ├── _ignored/ │ │ │ │ ├── _meta.js │ │ │ │ └── page.mdx │ │ │ ├── _meta.js │ │ │ ├── blog/ │ │ │ │ └── page.jsx │ │ │ ├── docs/ │ │ │ │ └── [[...mdxPath]]/ │ │ │ │ └── page.jsx │ │ │ ├── layout.jsx │ │ │ ├── page.jsx │ │ │ └── showcase/ │ │ │ └── (overview)/ │ │ │ └── page.jsx │ │ └── content/ │ │ ├── _meta.js │ │ ├── advanced/ │ │ │ └── code-highlighting.mdx │ │ ├── features/ │ │ │ ├── _meta.js │ │ │ ├── i18n.mdx │ │ │ ├── image.mdx │ │ │ ├── latex.mdx │ │ │ ├── mdx.mdx │ │ │ ├── ssg.mdx │ │ │ └── themes.mdx │ │ ├── get-started.mdx │ │ ├── index.mdx │ │ ├── mermaid.mdx │ │ ├── page.mdx │ │ └── themes/ │ │ ├── _meta.js │ │ ├── blog/ │ │ │ ├── _meta.js │ │ │ └── index.mdx │ │ └── docs/ │ │ ├── _meta.js │ │ ├── bleed.mdx │ │ ├── callout.mdx │ │ ├── configuration.mdx │ │ ├── index.mdx │ │ └── tabs.mdx │ └── swr-site/ │ ├── README.md │ ├── app/ │ │ ├── [lang]/ │ │ │ ├── [[...mdxPath]]/ │ │ │ │ └── page.tsx │ │ │ ├── graphql-eslint/ │ │ │ │ └── [[...slug]]/ │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── not-found.ts │ │ │ ├── remote/ │ │ │ │ └── graphql-yoga/ │ │ │ │ └── [[...slug]]/ │ │ │ │ └── page.tsx │ │ │ └── styles.css │ │ ├── _components/ │ │ │ ├── authors.tsx │ │ │ ├── blog.tsx │ │ │ ├── example-dynamic-markdown-import.tsx │ │ │ ├── external.mdx │ │ │ ├── features.css │ │ │ ├── features.tsx │ │ │ └── video.tsx │ │ ├── _dictionaries/ │ │ │ ├── en.ts │ │ │ ├── es.ts │ │ │ ├── get-dictionary.ts │ │ │ ├── i18n-config.ts │ │ │ └── ru.ts │ │ ├── _icons/ │ │ │ └── index.ts │ │ ├── env.d.ts │ │ └── manifest.ts │ ├── content/ │ │ ├── en/ │ │ │ ├── _meta.ts │ │ │ ├── about/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── a-page.mdx │ │ │ │ ├── acknowledgement.mdx │ │ │ │ └── team.mdx │ │ │ ├── blog/ │ │ │ │ └── swr-v1.mdx │ │ │ ├── blog.mdx │ │ │ ├── docs/ │ │ │ │ ├── _meta.tsx │ │ │ │ ├── advanced/ │ │ │ │ │ ├── _meta.tsx │ │ │ │ │ ├── cache.mdx │ │ │ │ │ ├── code-highlighting.mdx │ │ │ │ │ ├── dynamic-markdown-import.mdx │ │ │ │ │ ├── file-name.with.DOTS.mdx │ │ │ │ │ ├── images.mdx │ │ │ │ │ ├── markdown-import.mdx │ │ │ │ │ ├── more/ │ │ │ │ │ │ ├── loooooooooooooooooooong-title.mdx │ │ │ │ │ │ └── tree/ │ │ │ │ │ │ ├── one.mdx │ │ │ │ │ │ ├── three.mdx │ │ │ │ │ │ └── two.mdx │ │ │ │ │ ├── performance.mdx │ │ │ │ │ ├── react-native.mdx │ │ │ │ │ └── scrollbar-x.mdx │ │ │ │ ├── advanced.mdx │ │ │ │ ├── arguments.mdx │ │ │ │ ├── callout.mdx │ │ │ │ ├── change-log.mdx │ │ │ │ ├── code-block-without-language.mdx │ │ │ │ ├── conditional-fetching.md │ │ │ │ ├── custom-header-ids.mdx │ │ │ │ ├── data-fetching.mdx │ │ │ │ ├── error-handling.mdx │ │ │ │ ├── getting-started.mdx │ │ │ │ ├── global-configuration.md │ │ │ │ ├── middleware.mdx │ │ │ │ ├── mutation.md │ │ │ │ ├── options.mdx │ │ │ │ ├── pagination.mdx │ │ │ │ ├── prefetching.md │ │ │ │ ├── revalidation.mdx │ │ │ │ ├── suspense.mdx │ │ │ │ ├── typescript.mdx │ │ │ │ ├── understanding.mdx │ │ │ │ ├── with-nextjs.mdx │ │ │ │ └── wrap-toc-items.mdx │ │ │ ├── examples/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── auth.mdx │ │ │ │ ├── basic.mdx │ │ │ │ ├── error-handling.mdx │ │ │ │ ├── full.mdx │ │ │ │ ├── infinite-loading.mdx │ │ │ │ └── ssr.mdx │ │ │ ├── foo.md │ │ │ ├── index.mdx │ │ │ └── test.md │ │ ├── es/ │ │ │ ├── _meta.ts │ │ │ ├── docs/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── advanced/ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ ├── file-name.with.DOTS.mdx │ │ │ │ │ └── performance.mdx │ │ │ │ ├── arguments.mdx │ │ │ │ ├── change-log.mdx │ │ │ │ ├── conditional-fetching.md │ │ │ │ ├── data-fetching.mdx │ │ │ │ ├── error-handling.mdx │ │ │ │ ├── getting-started.mdx │ │ │ │ ├── global-configuration.md │ │ │ │ ├── mutation.md │ │ │ │ ├── options.mdx │ │ │ │ ├── pagination.mdx │ │ │ │ ├── prefetching.md │ │ │ │ ├── revalidation.mdx │ │ │ │ ├── suspense.mdx │ │ │ │ ├── understanding.mdx │ │ │ │ ├── with-nextjs.mdx │ │ │ │ └── wrap-toc-items.mdx │ │ │ ├── examples/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── auth.mdx │ │ │ │ ├── basic.mdx │ │ │ │ ├── error-handling.mdx │ │ │ │ └── infinite-loading.mdx │ │ │ └── index.mdx │ │ └── ru/ │ │ ├── _meta.ts │ │ ├── blog/ │ │ │ └── swr-v1.mdx │ │ ├── blog.mdx │ │ ├── docs/ │ │ │ ├── _meta.ts │ │ │ ├── advanced/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── cache.mdx │ │ │ │ ├── file-name.with.DOTS.mdx │ │ │ │ ├── performance.mdx │ │ │ │ └── react-native.mdx │ │ │ ├── arguments.mdx │ │ │ ├── change-log.mdx │ │ │ ├── conditional-fetching.md │ │ │ ├── data-fetching.mdx │ │ │ ├── error-handling.mdx │ │ │ ├── getting-started.mdx │ │ │ ├── global-configuration.md │ │ │ ├── middleware.mdx │ │ │ ├── mutation.md │ │ │ ├── options.mdx │ │ │ ├── pagination.mdx │ │ │ ├── prefetching.md │ │ │ ├── revalidation.mdx │ │ │ ├── suspense.mdx │ │ │ ├── understanding.mdx │ │ │ ├── with-nextjs.mdx │ │ │ └── wrap-toc-items.mdx │ │ ├── examples/ │ │ │ ├── _meta.ts │ │ │ ├── auth.mdx │ │ │ ├── basic.mdx │ │ │ ├── error-handling.mdx │ │ │ ├── infinite-loading.mdx │ │ │ └── ssr.mdx │ │ └── index.mdx │ ├── mdx-components.ts │ ├── next.config.ts │ ├── nextra-remote-filepaths/ │ │ ├── fetch.js │ │ ├── graphql-eslint.json │ │ └── graphql-yoga.json │ ├── package.json │ ├── postcss.config.js │ ├── proxy.ts │ ├── public/ │ │ ├── favicon/ │ │ │ └── browserconfig.xml │ │ └── stork.wasm │ ├── tsconfig.json │ └── vercel.json ├── package.json ├── packages/ │ ├── esbuild-react-compiler-plugin/ │ │ ├── package.json │ │ ├── src/ │ │ │ ├── env.d.ts │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── eslint-config/ │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── nextra/ │ │ ├── CHANGELOG.md │ │ ├── default-entry.ts │ │ ├── loader.cjs │ │ ├── package.json │ │ ├── setup-files.ts │ │ ├── src/ │ │ │ ├── client/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── mdx-components.test-d.ts │ │ │ │ │ ├── remove-links.test.tsx │ │ │ │ │ └── use-fs-route.test.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── banner/ │ │ │ │ │ │ ├── close-banner-button.tsx │ │ │ │ │ │ ├── index.client.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── bleed.tsx │ │ │ │ │ ├── button.tsx │ │ │ │ │ ├── callout.tsx │ │ │ │ │ ├── cards.tsx │ │ │ │ │ ├── collapse.tsx │ │ │ │ │ ├── file-tree/ │ │ │ │ │ │ ├── file.tsx │ │ │ │ │ │ ├── folder.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── tree.tsx │ │ │ │ │ ├── head.tsx │ │ │ │ │ ├── image-zoom.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── playground.tsx │ │ │ │ │ ├── popup/ │ │ │ │ │ │ ├── index.client.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── search.tsx │ │ │ │ │ ├── select.tsx │ │ │ │ │ ├── skip-nav/ │ │ │ │ │ │ ├── index.client.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── steps.tsx │ │ │ │ │ └── tabs/ │ │ │ │ │ ├── index.client.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── evaluate.ts │ │ │ │ ├── hocs/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── with-github-alert.tsx │ │ │ │ │ └── with-icons.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-copy.ts │ │ │ │ │ ├── use-fs-route.ts │ │ │ │ │ ├── use-hash.ts │ │ │ │ │ └── use-mounted.ts │ │ │ │ ├── icons/ │ │ │ │ │ └── index.ts │ │ │ │ ├── mdx-components/ │ │ │ │ │ ├── anchor.tsx │ │ │ │ │ ├── code.tsx │ │ │ │ │ ├── details.tsx │ │ │ │ │ ├── image.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── pre/ │ │ │ │ │ │ ├── copy-to-clipboard.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── toggle-word-wrap-button.tsx │ │ │ │ │ ├── summary.tsx │ │ │ │ │ └── table.tsx │ │ │ │ ├── mdx-components.ts │ │ │ │ ├── mdx-remote.tsx │ │ │ │ ├── normalize-pages.ts │ │ │ │ ├── pages.ts │ │ │ │ ├── remove-links.ts │ │ │ │ └── setup-page.tsx │ │ │ ├── env.d.ts │ │ │ ├── icon.ts │ │ │ ├── server/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ ├── compile.test.ts.snap │ │ │ │ │ │ └── normalize.test.ts.snap │ │ │ │ │ ├── compile-metadata.test.ts │ │ │ │ │ ├── compile.test.ts │ │ │ │ │ ├── fixture/ │ │ │ │ │ │ └── page-maps/ │ │ │ │ │ │ ├── active-type-should-be-initialized-from-star/ │ │ │ │ │ │ │ ├── 1-level/ │ │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ │ └── foo.md │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ └── generated-page-map.ts │ │ │ │ │ │ ├── first-child-route-should-return-index-as-first/ │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ ├── blog/ │ │ │ │ │ │ │ │ ├── _.md │ │ │ │ │ │ │ │ ├── a.md │ │ │ │ │ │ │ │ └── index.md │ │ │ │ │ │ │ └── generated-page-map.ts │ │ │ │ │ │ ├── folder-index-page-and-folder-should-be-merged/ │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ ├── themes/ │ │ │ │ │ │ │ │ └── bar.md │ │ │ │ │ │ │ ├── themes-test/ │ │ │ │ │ │ │ │ └── foo.md │ │ │ │ │ │ │ ├── themes-test.md │ │ │ │ │ │ │ └── themes.md │ │ │ │ │ │ ├── folder-with-symlinks/ │ │ │ │ │ │ │ ├── docs/ │ │ │ │ │ │ │ │ └── test2.md │ │ │ │ │ │ │ ├── pages/ │ │ │ │ │ │ │ │ └── generated-page-map.ts │ │ │ │ │ │ │ └── test1.md │ │ │ │ │ │ ├── folder-without-markdown-files/ │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ └── test.ts │ │ │ │ │ │ ├── folder-without-meta-json/ │ │ │ │ │ │ │ ├── callout.md │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ └── tabs.md │ │ │ │ │ │ ├── hidden-route-should-have-theme-context/ │ │ │ │ │ │ │ ├── 1-level/ │ │ │ │ │ │ │ │ ├── 2-level/ │ │ │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ │ │ └── foo.md │ │ │ │ │ │ │ │ └── qux.md │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ ├── bar.md │ │ │ │ │ │ │ └── generated-page-map.ts │ │ │ │ │ │ ├── non-english-characters-in-filename/ │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ ├── тест.mdx │ │ │ │ │ │ │ └── 测试.mdx │ │ │ │ │ │ ├── page-map.ts │ │ │ │ │ │ ├── pages-order-without-type-page/ │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ ├── docs/ │ │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ │ └── bar.md │ │ │ │ │ │ │ ├── foo.md │ │ │ │ │ │ │ └── generated-page-map.ts │ │ │ │ │ │ ├── respect-order-for-type-separator-menu-and-item-with-href/ │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ └── one/ │ │ │ │ │ │ │ └── two/ │ │ │ │ │ │ │ ├── 1-one.md │ │ │ │ │ │ │ ├── 2024.md │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ ├── foo.md │ │ │ │ │ │ │ ├── one.md │ │ │ │ │ │ │ └── qux.md │ │ │ │ │ │ ├── should-move-file-with-index-name/ │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ ├── foo.mdx │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── should-rename-folder/ │ │ │ │ │ │ │ ├── _meta.js │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ └── test/ │ │ │ │ │ │ │ └── foo.md │ │ │ │ │ │ ├── title/ │ │ │ │ │ │ │ ├── 1-meta.mdx │ │ │ │ │ │ │ ├── 2-sidebar-title.mdx │ │ │ │ │ │ │ ├── 3-title.mdx │ │ │ │ │ │ │ ├── 4-from-filename.mdx │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ ├── folder/ │ │ │ │ │ │ │ │ ├── bar.mdx │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── folder-with-index/ │ │ │ │ │ │ │ │ ├── foo.mdx │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ └── generated-page-map.ts │ │ │ │ │ │ ├── type-menu-should-contain-items/ │ │ │ │ │ │ │ ├── _meta.ts │ │ │ │ │ │ │ ├── generated-page-map.ts │ │ │ │ │ │ │ ├── mix/ │ │ │ │ │ │ │ │ ├── not-specified.md │ │ │ │ │ │ │ │ └── qux.md │ │ │ │ │ │ │ └── pagesOnly/ │ │ │ │ │ │ │ ├── one.md │ │ │ │ │ │ │ └── two.md │ │ │ │ │ │ └── type-menu-should-contain-local-pages/ │ │ │ │ │ │ ├── mix/ │ │ │ │ │ │ │ ├── not-specified.md │ │ │ │ │ │ │ └── qux.md │ │ │ │ │ │ └── one/ │ │ │ │ │ │ └── bar.md │ │ │ │ │ ├── latex.test.ts │ │ │ │ │ ├── merge-meta-with-page-map.test.ts │ │ │ │ │ ├── nextra-config.test-d.ts │ │ │ │ │ ├── normalize.test.ts │ │ │ │ │ ├── page-map.test.ts │ │ │ │ │ ├── recma-rewrite.test.ts │ │ │ │ │ ├── rehype-extract-toc-content.test.ts │ │ │ │ │ ├── remark-mdx-frontmatter.test.ts │ │ │ │ │ ├── remark-mdx-title.test.ts │ │ │ │ │ ├── remark-remove-imports.test.ts │ │ │ │ │ ├── remark-static-images.test.ts │ │ │ │ │ ├── test-utils.ts │ │ │ │ │ ├── to-js.test.ts │ │ │ │ │ └── to-page-map.test.ts │ │ │ │ ├── compile-metadata.ts │ │ │ │ ├── compile.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── fetch-filepaths-from-github.ts │ │ │ │ ├── index.ts │ │ │ │ ├── loader.ts │ │ │ │ ├── locales.ts │ │ │ │ ├── page-map/ │ │ │ │ │ ├── find-meta-and-page-file-paths.ts │ │ │ │ │ ├── get.ts │ │ │ │ │ ├── index-page.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── merge-meta-with-page-map.ts │ │ │ │ │ ├── normalize.ts │ │ │ │ │ ├── placeholder.ts │ │ │ │ │ ├── to-ast.ts │ │ │ │ │ ├── to-js.ts │ │ │ │ │ └── to-page-map.ts │ │ │ │ ├── recma-plugins/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── recma-rewrite.ts │ │ │ │ ├── rehype-plugins/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── rehype-better-react-mathjax.ts │ │ │ │ │ ├── rehype-extract-toc-content.ts │ │ │ │ │ ├── rehype-twoslash-popup.ts │ │ │ │ │ └── rehype.ts │ │ │ │ ├── remark-plugins/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── remark-assign-frontmatter.ts │ │ │ │ │ ├── remark-custom-heading-id.ts │ │ │ │ │ ├── remark-export-only-metadata.ts │ │ │ │ │ ├── remark-export-source-code.ts │ │ │ │ │ ├── remark-headings.ts │ │ │ │ │ ├── remark-link-rewrite.ts │ │ │ │ │ ├── remark-mdx-disable-explicit-jsx.ts │ │ │ │ │ ├── remark-mdx-frontmatter.ts │ │ │ │ │ ├── remark-mdx-title.ts │ │ │ │ │ ├── remark-remove-imports.ts │ │ │ │ │ └── remark-static-image.ts │ │ │ │ ├── schemas.ts │ │ │ │ ├── tsdoc/ │ │ │ │ │ ├── base.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── tsdoc.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ └── zod-to-ts.ts │ │ │ │ ├── twoslash.ts │ │ │ │ └── utils.ts │ │ │ ├── types.generated.ts │ │ │ └── types.ts │ │ ├── styles/ │ │ │ ├── cards.css │ │ │ ├── code-block.css │ │ │ ├── default.css │ │ │ ├── react-medium-image-zoom.css │ │ │ ├── scrollbar.css │ │ │ ├── steps.css │ │ │ └── subheading-anchor.css │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.ts │ ├── nextra-theme-blog/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── __test__/ │ │ │ └── is-valid-date.test.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── cusdis.tsx │ │ │ │ ├── go-back.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── layout.tsx │ │ │ │ ├── meta.tsx │ │ │ │ ├── navbar-link.tsx │ │ │ │ ├── navbar.tsx │ │ │ │ ├── post-card.tsx │ │ │ │ └── theme-switch.tsx │ │ │ ├── env.d.ts │ │ │ ├── index.ts │ │ │ ├── is-valid-date.ts │ │ │ ├── mdx-components.tsx │ │ │ ├── style.css │ │ │ └── types.ts │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── nextra-theme-docs/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── css/ │ │ │ ├── hamburger.css │ │ │ └── typesetting-article.css │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── setup-files.ts │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ ├── git-url-parse.test.ts │ │ │ │ ├── layout-props.test-d.ts │ │ │ │ └── mdx-components.test-d.ts │ │ │ ├── components/ │ │ │ │ ├── 404/ │ │ │ │ │ ├── index.client.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── back-to-top.tsx │ │ │ │ ├── breadcrumb.tsx │ │ │ │ ├── copy-page.tsx │ │ │ │ ├── footer/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── switchers.ts │ │ │ │ ├── index.ts │ │ │ │ ├── last-updated.tsx │ │ │ │ ├── locale-switch.tsx │ │ │ │ ├── navbar/ │ │ │ │ │ ├── index.client.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── pagination.tsx │ │ │ │ ├── sidebar.tsx │ │ │ │ ├── theme-switch.tsx │ │ │ │ └── toc.tsx │ │ │ ├── index.ts │ │ │ ├── layout.tsx │ │ │ ├── mdx-components/ │ │ │ │ ├── heading-anchor.client.tsx │ │ │ │ ├── heading.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── link.tsx │ │ │ │ └── wrapper.client.tsx │ │ │ ├── schemas.tsx │ │ │ ├── stores/ │ │ │ │ ├── active-anchor.ts │ │ │ │ ├── config.tsx │ │ │ │ ├── focused-route.ts │ │ │ │ ├── index.ts │ │ │ │ ├── menu.ts │ │ │ │ ├── theme-config.ts │ │ │ │ └── toc.ts │ │ │ ├── style.css │ │ │ ├── types.generated.ts │ │ │ └── utils/ │ │ │ ├── extract-only-strings-from-react-node.ts │ │ │ ├── get-git-issue-url.ts │ │ │ ├── git-url-parse.ts │ │ │ └── index.ts │ │ ├── tailwind.config.ts │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── prettier-config/ │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ └── src/ │ │ └── index.js │ └── tsdoc/ │ ├── README.md │ ├── package.json │ ├── src/ │ │ ├── __tests__/ │ │ │ ├── base.test.ts │ │ │ ├── fixtures/ │ │ │ │ └── flattened.ts │ │ │ ├── snapshots/ │ │ │ │ ├── flattened.json │ │ │ │ ├── get-smooth-step-path.json │ │ │ │ ├── get-viewport-for-bounds.json │ │ │ │ ├── head-props.ts │ │ │ │ ├── head.json │ │ │ │ ├── layout-props.json │ │ │ │ ├── layout-props.ts │ │ │ │ ├── navbar.json │ │ │ │ ├── nextra-config.json │ │ │ │ ├── react-flow-instance.json │ │ │ │ ├── search.json │ │ │ │ ├── use-config.json │ │ │ │ ├── use-edges-state.json │ │ │ │ └── use-theme-config.json │ │ │ └── zod-to-ts.test.ts │ │ ├── env.d.ts │ │ └── index.ts │ ├── tsconfig.json │ ├── tsup.config.ts │ └── vitest.config.ts ├── patches/ │ ├── @changesets__assemble-release-plan.patch │ ├── esbuild-plugin-svgr.patch │ ├── eslint-plugin-tailwindcss.patch │ ├── next.patch │ └── tsup.patch ├── pnpm-workspace.yaml ├── prettier.config.mjs ├── renovate.json5 └── turbo.jsonc
SYMBOL INDEX (373 symbols across 137 files)
FILE: docs/app/_components/i18n-demo.tsx
constant LANGUAGES (line 9) | const LANGUAGES = [
FILE: docs/app/_meta.global.tsx
constant FILE_CONVENTIONS (line 22) | const FILE_CONVENTIONS: MetaRecord = {
constant GUIDE (line 58) | const GUIDE: MetaRecord = {
constant ADVANCED (line 86) | const ADVANCED: MetaRecord = {
constant BLOG_THEME (line 96) | const BLOG_THEME: MetaRecord = {
FILE: docs/app/api/[name]/page.tsx
type AllApiReference (line 9) | type AllApiReference = ApiReference & { filePath?: string }
constant API_REFERENCE (line 11) | const API_REFERENCE: (
function getReference (line 76) | async function getReference(props: PageProps) {
function generateMetadata (line 110) | async function generateMetadata(props: PageProps) {
type PageProps (line 115) | type PageProps = Readonly<{
FILE: docs/app/docs/built-ins/[name]/page.tsx
type ComponentApiReference (line 9) | type ComponentApiReference = ApiReference & { groupKeys?: string }
constant API_REFERENCE (line 11) | const API_REFERENCE: (
function getReference (line 105) | async function getReference(props: PageProps) {
function generateMetadata (line 164) | async function generateMetadata(props: PageProps) {
type PageProps (line 169) | type PageProps = Readonly<{
FILE: docs/app/og/route.tsx
function GET (line 12) | async function GET(req: Request): Promise<Response> {
FILE: docs/components/_slider.tsx
function hexToRgb (line 35) | function hexToRgb(hex: `#${string}`): string {
FILE: docs/components/content-and-app-file-tree.tsx
function mapChildren (line 8) | function mapChildren(children) {
FILE: docs/components/generate-api-reference.ts
type ApiReference (line 37) | interface ApiReference {
type Options (line 44) | interface Options {
function generateApiReference (line 51) | async function generateApiReference(
FILE: docs/components/get-page-map.ts
type PageMapVisitor (line 6) | type PageMapVisitor = (item: PageMapItem) => PageMapItem
function visitPageMap (line 16) | function visitPageMap(
function createMetaItem (line 32) | function createMetaItem(pageMap: typeof apiPageMap): MetaJsonFile {
FILE: docs/components/inkeep-chat-button.tsx
method isDarkMode (line 20) | isDarkMode(attrs) {
FILE: docs/components/playground-demo.tsx
constant DEFAULT_MDX (line 11) | const DEFAULT_MDX = `Playground component lets you write Nextra-compatib...
FILE: docs/components/shadow.jsx
class Shadow (line 7) | class Shadow extends Component {
method componentDidMount (line 8) | componentDidMount() {
method render (line 17) | render() {
FILE: docs/mdx-components.tsx
type TSDocProps (line 8) | type TSDocProps = ComponentProps<typeof TSDoc>
type GenerateDefinitionArgs (line 9) | type GenerateDefinitionArgs = Parameters<typeof generateDefinition>[0]
type APIDocsProps (line 11) | interface APIDocsProps
method APIDocs (line 27) | async APIDocs({
FILE: docs/next.config.ts
function isExportNode (line 4) | function isExportNode(node, varName: string) {
constant DEFAULT_PROPERTY_PROPS (line 16) | const DEFAULT_PROPERTY_PROPS = {
function createAstObject (line 25) | function createAstObject(obj) {
type NextraParams (line 37) | type NextraParams = Parameters<typeof nextra>[0]
type MdxOptions (line 38) | type MdxOptions = NonNullable<NextraParams['mdxOptions']>
type RehypePlugin (line 39) | type RehypePlugin = NonNullable<MdxOptions['rehypePlugins']>[0]
method webpack (line 125) | webpack(config) {
FILE: examples/blog/app/layout.jsx
function RootLayout (line 10) | async function RootLayout({ children }) {
FILE: examples/blog/app/posts/(with-comments)/layout.jsx
function CommentsLayout (line 3) | function CommentsLayout({ children }) {
FILE: examples/blog/app/posts/get-posts.js
function getPosts (line 4) | async function getPosts() {
function getTags (line 14) | async function getTags() {
FILE: examples/blog/app/posts/page.jsx
function PostsPage (line 9) | async function PostsPage() {
FILE: examples/blog/app/rss.xml/route.js
constant CONFIG (line 3) | const CONFIG = {
function GET (line 10) | async function GET() {
FILE: examples/blog/app/tags/[tag]/page.jsx
function generateMetadata (line 4) | async function generateMetadata(props) {
function generateStaticParams (line 11) | async function generateStaticParams() {
function TagPage (line 16) | async function TagPage(props) {
FILE: examples/blog/mdx-components.jsx
function useMDXComponents (line 24) | function useMDXComponents(components) {
FILE: examples/custom-theme/mdx-components.jsx
method wrapper (line 5) | wrapper({ children, toc }) {
FILE: examples/docs/src/app/blog/page.jsx
function BlogPage (line 1) | function BlogPage() {
FILE: examples/docs/src/app/docs/[[...mdxPath]]/page.jsx
function generateMetadata (line 6) | async function generateMetadata(props) {
function Page (line 14) | async function Page(props) {
FILE: examples/docs/src/app/layout.jsx
function RootLayout (line 27) | async function RootLayout({ children }) {
FILE: examples/docs/src/app/page.jsx
function IndexPage (line 1) | function IndexPage() {
FILE: examples/docs/src/app/showcase/(overview)/page.jsx
function Page (line 1) | function Page() {
FILE: examples/swr-site/app/[lang]/[[...mdxPath]]/page.tsx
function generateMetadata (line 7) | async function generateMetadata(props: PageProps) {
type PageProps (line 13) | type PageProps = Readonly<{
FILE: examples/swr-site/app/[lang]/graphql-eslint/[[...slug]]/page.tsx
type PageProps (line 51) | type PageProps = Readonly<{
function Page (line 57) | async function Page(props: PageProps) {
function generateStaticParams (line 79) | function generateStaticParams() {
FILE: examples/swr-site/app/[lang]/layout.tsx
type LayoutProps (line 43) | type LayoutProps = Readonly<{
FILE: examples/swr-site/app/[lang]/remote/graphql-yoga/[[...slug]]/page.tsx
type PageProps (line 70) | type PageProps = Readonly<{
function Page (line 76) | async function Page(props: PageProps) {
function generateStaticParams (line 98) | function generateStaticParams() {
FILE: examples/swr-site/app/_components/example-dynamic-markdown-import.tsx
function ExampleDynamicMarkdownImport (line 6) | function ExampleDynamicMarkdownImport() {
FILE: examples/swr-site/app/_dictionaries/get-dictionary.ts
function getDictionary (line 12) | async function getDictionary(locale: string): Promise<Dictionary> {
function getDirection (line 19) | function getDirection(locale: string): 'ltr' | 'rtl' {
FILE: examples/swr-site/app/_dictionaries/i18n-config.ts
type Locale (line 8) | type Locale = (typeof i18n)['locales'][number]
type Dictionary (line 10) | type Dictionary = typeof EnglishLocale
type Dictionaries (line 12) | type Dictionaries = Record<
FILE: examples/swr-site/app/manifest.ts
function manifest (line 3) | function manifest(): MetadataRoute.Manifest {
FILE: examples/swr-site/next.config.ts
method webpack (line 28) | webpack(config) {
FILE: packages/esbuild-react-compiler-plugin/src/index.ts
constant DEFAULT_REACT_COMPILER_CONFIG (line 7) | const DEFAULT_REACT_COMPILER_CONFIG: Partial<ReactCompilerConfig> = {
method sources (line 8) | sources(filename: string) {
method logEvent (line 14) | logEvent(filename, result) {
method setup (line 49) | setup(build) {
FILE: packages/eslint-config/src/index.ts
constant REACT_COMPILER_RESTRICT (line 32) | const REACT_COMPILER_RESTRICT = {
FILE: packages/nextra-theme-blog/src/components/navbar.tsx
type NavbarProps (line 6) | type NavbarProps = {
FILE: packages/nextra-theme-blog/src/components/post-card.tsx
type PostCardProps (line 5) | type PostCardProps = {
FILE: packages/nextra-theme-blog/src/components/theme-switch.tsx
function ThemeSwitch (line 8) | function ThemeSwitch() {
FILE: packages/nextra-theme-blog/src/env.d.ts
type Window (line 1) | interface Window {
FILE: packages/nextra-theme-blog/src/is-valid-date.ts
constant DATE_RE (line 3) | const DATE_RE = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2})?(:\d{2}\.\d{3}Z)?$/
constant DATE_RE_WITH_SLASH (line 4) | const DATE_RE_WITH_SLASH = /^\d{4}\/\d{1,2}\/\d{1,2}( \d{1,2}:\d{1,2})?$/
FILE: packages/nextra-theme-blog/src/mdx-components.tsx
constant CALLOUT_TYPE (line 44) | const CALLOUT_TYPE = Object.freeze({
type BlogMDXComponents (line 55) | type BlogMDXComponents = MDXComponents & {
constant DEFAULT_COMPONENTS (line 59) | const DEFAULT_COMPONENTS = getNextraMDXComponents({
method wrapper (line 85) | wrapper({ children, metadata }) {
FILE: packages/nextra-theme-blog/src/types.ts
type BlogMetadata (line 4) | type BlogMetadata = {
FILE: packages/nextra-theme-blog/tsup.config.ts
method onSuccess (line 15) | async onSuccess() {
FILE: packages/nextra-theme-docs/src/__tests__/layout-props.test-d.ts
type Expected (line 8) | type Expected = z.input<typeof LayoutPropsSchema>
type Actual (line 9) | type Actual = LayoutProps
FILE: packages/nextra-theme-docs/src/components/404/index.tsx
type NotFoundPageProps (line 6) | type NotFoundPageProps = {
FILE: packages/nextra-theme-docs/src/components/back-to-top.tsx
constant SCROLL_TO_OPTIONS (line 6) | const SCROLL_TO_OPTIONS = { top: 0, behavior: 'smooth' } as const
FILE: packages/nextra-theme-docs/src/components/copy-page.tsx
function handleCopy (line 36) | function handleCopy() {
FILE: packages/nextra-theme-docs/src/components/locale-switch.tsx
constant ONE_YEAR (line 11) | const ONE_YEAR = 365 * 24 * 60 * 60 * 1000
type LocaleSwitchProps (line 13) | interface LocaleSwitchProps {
FILE: packages/nextra-theme-docs/src/components/navbar/index.tsx
type NavbarProps (line 10) | interface NavbarProps {
FILE: packages/nextra-theme-docs/src/components/sidebar.tsx
type FolderProps (line 61) | type FolderProps = {
function updateTreeState (line 121) | function updateTreeState() {
function updateAndPruneTreeState (line 127) | function updateAndPruneTreeState() {
function getMenuChildren (line 187) | function getMenuChildren(menu: MenuItem) {
type MenuProps (line 264) | interface MenuProps {
FILE: packages/nextra-theme-docs/src/components/theme-switch.tsx
type ThemeSwitchProps (line 11) | type ThemeSwitchProps = {
FILE: packages/nextra-theme-docs/src/components/toc.tsx
type TOCProps (line 12) | type TOCProps = {
FILE: packages/nextra-theme-docs/src/layout.tsx
type ThemeConfigProps (line 11) | type ThemeConfigProps = z.infer<typeof LayoutPropsSchema>
FILE: packages/nextra-theme-docs/src/mdx-components/index.tsx
constant CALLOUT_TYPE (line 37) | const CALLOUT_TYPE = Object.freeze({
constant DEFAULT_COMPONENTS (line 45) | const DEFAULT_COMPONENTS = getNextraMDXComponents({
method wrapper (line 88) | wrapper({ toc, children, metadata, bottomContent, sourceCode, ...props }) {
FILE: packages/nextra-theme-docs/src/stores/config.tsx
type NormalizePagesResult (line 9) | type NormalizePagesResult = ReturnType<typeof normalizePages>
function useConfig (line 22) | function useConfig(): {
FILE: packages/nextra-theme-docs/src/types.generated.ts
type LayoutProps (line 1) | interface LayoutProps {
FILE: packages/nextra-theme-docs/src/utils/extract-only-strings-from-react-node.ts
function extractStringsFromReactNode (line 3) | function extractStringsFromReactNode(node: ReactNode): string {
FILE: packages/nextra-theme-docs/src/utils/get-git-issue-url.ts
function getGitIssueUrl (line 5) | function getGitIssueUrl({
FILE: packages/nextra-theme-docs/src/utils/git-url-parse.ts
function gitUrlParse (line 3) | function gitUrlParse(url: string) {
FILE: packages/nextra-theme-docs/tsup.config.ts
method onSuccess (line 17) | async onSuccess() {
FILE: packages/nextra/src/client/__tests__/use-fs-route.test.ts
function mockAndRenderHook (line 10) | function mockAndRenderHook(pathname: string) {
FILE: packages/nextra/src/client/components/banner/index.tsx
constant BANNER_CLASS_NAME (line 7) | const BANNER_CLASS_NAME = 'nextra-banner'
type BannerProps (line 9) | type BannerProps = HTMLAttributes<HTMLDivElement> & {
FILE: packages/nextra/src/client/components/button.tsx
type ButtonProps (line 9) | type ButtonProps = HeadlessButtonProps & {
FILE: packages/nextra/src/client/components/callout.tsx
type CalloutType (line 19) | type CalloutType = keyof typeof TypeToEmoji
type CalloutProps (line 49) | type CalloutProps = HTMLAttributes<HTMLDivElement> & {
FILE: packages/nextra/src/client/components/file-tree/file.tsx
type FileProps (line 5) | type FileProps = {
FILE: packages/nextra/src/client/components/file-tree/folder.tsx
type FolderProps (line 10) | type FolderProps = FileProps & {
FILE: packages/nextra/src/client/components/head.tsx
function convertColor (line 14) | function convertColor(v: z.infer<typeof darkLightSchema>) {
function hexToRgb (line 18) | function hexToRgb(hex: string): string {
constant RGB_RE (line 34) | const RGB_RE = /^rgb\((?<rgb>.*?)\)$/
constant HEX_RE (line 35) | const HEX_RE = /^#(?<hex>[0-9a-f]{3,6})$/i
function normalizeColor (line 37) | function normalizeColor(value: string): string {
FILE: packages/nextra/src/client/components/image-zoom.tsx
function getImageSrc (line 8) | function getImageSrc(src: ImageProps['src']): string {
FILE: packages/nextra/src/client/components/playground.tsx
type PlaygroundProps (line 9) | type PlaygroundProps = {
function doCompile (line 83) | async function doCompile() {
function importCompile (line 121) | function importCompile() {
FILE: packages/nextra/src/client/components/popup/index.client.tsx
function usePopup (line 11) | function usePopup(): boolean {
FILE: packages/nextra/src/client/components/search.tsx
function importPagefind (line 27) | async function importPagefind() {
type PagefindResult (line 37) | type PagefindResult = {
type InputProps (line 51) | type InputProps = Omit<
type SearchProps (line 56) | interface SearchProps extends InputProps {
constant INPUTS (line 116) | const INPUTS = new Set(['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA'])
constant DEV_SEARCH_NOTICE (line 118) | const DEV_SEARCH_NOTICE = (
function handleKeyDown (line 212) | function handleKeyDown(event: KeyboardEvent) {
FILE: packages/nextra/src/client/components/select.tsx
type MenuOption (line 15) | interface MenuOption {
type MenuProps (line 20) | interface MenuProps {
FILE: packages/nextra/src/client/components/skip-nav/index.client.tsx
constant DEFAULT_ID (line 35) | const DEFAULT_ID = 'nextra-skip-nav'
constant DEFAULT_LABEL (line 36) | const DEFAULT_LABEL = 'Skip to Content'
FILE: packages/nextra/src/client/components/skip-nav/index.tsx
constant DEFAULT_ID (line 3) | const DEFAULT_ID = 'nextra-skip-nav'
FILE: packages/nextra/src/client/components/tabs/index.client.tsx
type TabItem (line 21) | type TabItem = string | ReactElement
type TabObjectItem (line 23) | type TabObjectItem = {
function isTabObjectItem (line 28) | function isTabObjectItem(item: unknown): item is TabObjectItem {
function fn (line 89) | function fn(event: StorageEvent) {
FILE: packages/nextra/src/client/evaluate.ts
type Scope (line 11) | type Scope = Record<string, unknown>
function evaluate (line 13) | function evaluate(
FILE: packages/nextra/src/client/hocs/with-github-alert.tsx
type BlockquoteType (line 6) | type BlockquoteType = FC<ComponentProps<'blockquote'>>
type T (line 7) | type T = (typeof GITHUB_ALERTS)[number]
constant GITHUB_ALERT_RE (line 9) | const GITHUB_ALERT_RE = /^\s*\[!(?<name>.*?)]\s*$/
constant GITHUB_ALERTS (line 11) | const GITHUB_ALERTS = [
constant GITHUB_ALERT_TYPES (line 19) | const GITHUB_ALERT_TYPES = new Set<string>(GITHUB_ALERTS)
function withGitHubAlert (line 21) | function withGitHubAlert(
FILE: packages/nextra/src/client/hocs/with-icons.tsx
function getIcon (line 27) | function getIcon(language: string) {
function withIcons (line 83) | function withIcons(
FILE: packages/nextra/src/client/hooks/use-copy.ts
function useCopy (line 5) | function useCopy({
FILE: packages/nextra/src/client/hooks/use-fs-route.ts
function useFSRoute (line 7) | function useFSRoute() {
FILE: packages/nextra/src/client/hooks/use-hash.ts
function useHash (line 8) | function useHash() {
FILE: packages/nextra/src/client/hooks/use-mounted.ts
function useMounted (line 8) | function useMounted(): boolean {
FILE: packages/nextra/src/client/mdx-components.ts
type StringComponent (line 9) | type StringComponent = Exclude<keyof JSX.IntrinsicElements, 'img' | 'a'>
type Component (line 14) | type Component<Props> = FC<Props> | StringComponent
type NestedMDXComponents (line 16) | interface NestedMDXComponents {
type MDXComponents (line 25) | type MDXComponents = NestedMDXComponents & {
type DefaultMdxComponents (line 34) | type DefaultMdxComponents = {
constant DEFAULT_COMPONENTS (line 48) | const DEFAULT_COMPONENTS = {
type UseMDXComponents (line 57) | type UseMDXComponents<
FILE: packages/nextra/src/client/mdx-components/anchor.tsx
type NextLinkProps (line 7) | type NextLinkProps = ComponentPropsWithoutRef<typeof Link>
type Props (line 9) | type Props = Omit<NextLinkProps, 'href'> & {
FILE: packages/nextra/src/client/mdx-components/details.tsx
function findSummary (line 85) | function findSummary(
FILE: packages/nextra/src/client/mdx-components/pre/index.tsx
type PreProps (line 14) | type PreProps = HTMLAttributes<HTMLPreElement> & {
FILE: packages/nextra/src/client/mdx-components/pre/toggle-word-wrap-button.tsx
function toggleWordWrap (line 6) | function toggleWordWrap() {
FILE: packages/nextra/src/client/mdx-remote.tsx
type MDXRemoteProps (line 7) | type MDXRemoteProps = Readonly<{
FILE: packages/nextra/src/client/normalize-pages.ts
constant DEFAULT_PAGE_THEME (line 8) | const DEFAULT_PAGE_THEME: PageTheme = {
type PageTheme (line 22) | type PageTheme = NonNullable<z.infer<typeof itemSchema>['theme']>
type Display (line 23) | type Display = z.infer<typeof itemSchema>['display']
type IMenuItem (line 24) | type IMenuItem = z.infer<typeof menuSchema>
type MetaType (line 25) | type MetaType = Record<string, any>
function extendMeta (line 27) | function extendMeta(
type FolderWithoutChildren (line 45) | type FolderWithoutChildren = Omit<Folder, 'children'>
type Item (line 47) | type Item = (MdxFile | FolderWithoutChildren) & {
type PageItem (line 57) | type PageItem = (MdxFile | FolderWithoutChildren) & {
type MenuItem (line 67) | type MenuItem = (MdxFile | FolderWithoutChildren) &
type DocsItem (line 72) | type DocsItem = (MdxFile | FolderWithoutChildren) & {
function findFirstRoute (line 80) | function findFirstRoute(items: DocsItem[]): string | undefined {
type NormalizedResult (line 91) | type NormalizedResult = {
function normalizePages (line 117) | function normalizePages({
FILE: packages/nextra/src/client/pages.ts
function importPage (line 73) | async function importPage(
function generateStaticParamsFor (line 130) | function generateStaticParamsFor(
FILE: packages/nextra/src/client/remove-links.ts
type TOCElement (line 7) | type TOCElement = ReactElement | string
function hasProps (line 9) | function hasProps(node: ReactNode) {
function removeLinks (line 13) | function removeLinks(node: ReactNode): TOCElement[] | string {
FILE: packages/nextra/src/client/setup-page.tsx
type WrapperProps (line 15) | type WrapperProps = ComponentProps<MDXWrapper>
function HOC_MDXWrapper (line 17) | function HOC_MDXWrapper(
FILE: packages/nextra/src/server/__tests__/nextra-config.test-d.ts
type Expected (line 9) | type Expected = { foo: string }
type Actual (line 10) | type Actual = { foo: number }
type Expected (line 15) | type Expected = { foo: { bar: string } }
type Actual (line 16) | type Actual = { foo: { bar: number } }
type Expected (line 21) | type Expected = { foo?: string }
type Actual (line 22) | type Actual = { foo: string }
type Expected (line 27) | type Expected = { foo?: string }
type Actual (line 28) | type Actual = { foo: string | undefined }
type Expected (line 33) | type Expected = z.input<typeof NextraConfigSchema>
type Actual (line 34) | type Actual = NextraConfig
type _Expected (line 38) | type _Expected = z.input<typeof HeadPropsSchema>
type _Actual (line 39) | type _Actual = HeadProps
FILE: packages/nextra/src/server/__tests__/remark-mdx-frontmatter.test.ts
constant YAML_FRONTMATTER (line 5) | const YAML_FRONTMATTER = '---\nfoo: bar\n---'
constant ESM_FRONTMATTER (line 6) | const ESM_FRONTMATTER = "export const metadata = { foo: 'bar' }"
FILE: packages/nextra/src/server/__tests__/test-utils.ts
type IsEqual (line 8) | type IsEqual<A, B> =
function clean (line 17) | async function clean(content: string): Promise<string> {
function getPageMapForFixture (line 29) | async function getPageMapForFixture(dirName: string) {
FILE: packages/nextra/src/server/compile-metadata.ts
function compileMetadata (line 19) | async function compileMetadata(
FILE: packages/nextra/src/server/compile.ts
type Processor (line 38) | type Processor = ReturnType<typeof createProcessor>
type MdxOptions (line 45) | type MdxOptions = NextraConfig['mdxOptions'] &
type CompileMdxOptions (line 48) | type CompileMdxOptions = Pick<
function compileMdx (line 79) | async function compileMdx(
FILE: packages/nextra/src/server/constants.ts
constant MARKDOWN_EXTENSION_RE (line 7) | const MARKDOWN_EXTENSION_RE = /\.mdx?$/
constant CWD (line 9) | const CWD = process.cwd()
constant MARKDOWN_URL_EXTENSION_RE (line 11) | const MARKDOWN_URL_EXTENSION_RE = /\.mdx?(?:(?=[#?])|$)/
constant IS_PRODUCTION (line 13) | const IS_PRODUCTION = process.env.NODE_ENV === 'production'
constant EXTERNAL_URL_RE (line 15) | const EXTERNAL_URL_RE = /^https?:\/\//
constant DEFAULT_PROPERTY_PROPS (line 17) | const DEFAULT_PROPERTY_PROPS = {
constant METADATA_ONLY_RQ (line 25) | const METADATA_ONLY_RQ = '?metadata'
FILE: packages/nextra/src/server/fetch-filepaths-from-github.ts
type Params (line 4) | type Params = {
function fetchFilePathsFromGitHub (line 12) | async function fetchFilePathsFromGitHub({
FILE: packages/nextra/src/server/index.ts
constant MARKDOWN_EXTENSIONS (line 16) | const MARKDOWN_EXTENSIONS = ['md', 'mdx'] as const
constant DEFAULT_EXTENSIONS (line 18) | const DEFAULT_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx'] as const
constant FILENAME (line 20) | const FILENAME = fileURLToPath(import.meta.url)
constant LOADER_PATH (line 22) | const LOADER_PATH = path.join(FILENAME, '..', '..', '..', 'loader.cjs')
constant SEP (line 24) | const SEP = path.sep === '/' ? '/' : '\\\\'
constant GET_PAGE_MAP_PATH (line 26) | const GET_PAGE_MAP_PATH = '/nextra/dist/server/page-map/get.js'
constant PAGE_MAP_PLACEHOLDER_PATH (line 28) | const PAGE_MAP_PLACEHOLDER_PATH = '/nextra/dist/server/page-map/placehol...
constant GET_PAGE_MAP_RE (line 30) | const GET_PAGE_MAP_RE = new RegExp(
constant PAGE_MAP_PLACEHOLDER_RE (line 33) | const PAGE_MAP_PLACEHOLDER_RE = new RegExp(
constant CONTENT_DIR (line 36) | const CONTENT_DIR = getContentDirectory()
function getContentDirectory (line 38) | function getContentDirectory() {
method webpack (line 197) | webpack(config, options) {
FILE: packages/nextra/src/server/loader.ts
constant NOW (line 15) | const NOW = Date.now()
constant APP_DIR (line 16) | const APP_DIR = findPagesDir(CWD).appDir!
constant GIT_ROOT (line 49) | const GIT_ROOT = repository ? path.join(repository.path(), '..') : ''
constant DEFAULT_TRANSFORMERS (line 51) | const DEFAULT_TRANSFORMERS = transformerTwoslash({
function loader (line 56) | async function loader(
function replaceDynamicResourceQuery (line 172) | function replaceDynamicResourceQuery(
function getLastCommitTime (line 194) | async function getLastCommitTime(
FILE: packages/nextra/src/server/locales.ts
constant HAS_LOCALE_RE (line 11) | const HAS_LOCALE_RE = new RegExp(String.raw`^\/(${locales.join('|')})(\/...
constant COOKIE_NAME (line 13) | const COOKIE_NAME = 'NEXT_LOCALE'
function getHeadersLocale (line 15) | function getHeadersLocale(request: NextRequest): string {
function proxy (line 43) | function proxy(request: NextRequest) {
FILE: packages/nextra/src/server/page-map/find-meta-and-page-file-paths.ts
function findMetaAndPageFilePaths (line 5) | async function findMetaAndPageFilePaths({
FILE: packages/nextra/src/server/page-map/get.ts
function importPageMap (line 3) | function importPageMap(lang = ''): Promise<{
function getPageMap (line 39) | async function getPageMap(
function getRouteToFilepath (line 65) | async function getRouteToFilepath(
FILE: packages/nextra/src/server/page-map/index-page.ts
function renderCard (line 4) | function renderCard(item: MdxFile): string {
function createIndexPage (line 11) | async function createIndexPage(pageMap: PageMapItem[]): Promise<string> {
function getIndexPageMap (line 44) | function getIndexPageMap(pageMap: PageMapItem[]) {
FILE: packages/nextra/src/server/page-map/index.ts
function getMetadata (line 9) | function getMetadata(
FILE: packages/nextra/src/server/page-map/merge-meta-with-page-map.ts
function isFolder (line 14) | function isFolder(value: DynamicMetaItem): value is DynamicFolder {
function normalizeMetaRecord (line 24) | function normalizeMetaRecord(
function mergeMetaWithPageMap (line 44) | function mergeMetaWithPageMap<T extends Folder | PageMapItem[] | TItem>(
FILE: packages/nextra/src/server/page-map/normalize.ts
function normalizePageMap (line 12) | function normalizePageMap(pageMap: PageMapItem[] | Folder | TItem): any {
type ParsedFolder (line 21) | type ParsedFolder = Folder & {
function titlize (line 25) | function titlize(item: Folder | MdxFile, meta: MetaRecord): string {
type MetaRecord (line 38) | type MetaRecord = Record<string, Record<string, any>>
function sortFolder (line 40) | function sortFolder(pageMap: PageMapItem[] | Folder | TItem) {
FILE: packages/nextra/src/server/page-map/to-ast.ts
function cleanFilePath (line 7) | function cleanFilePath(filePath: string): string {
function convertPageMapToAst (line 23) | function convertPageMapToAst(
FILE: packages/nextra/src/server/page-map/to-js.ts
constant META_RE (line 7) | const META_RE = /_meta\.[jt]sx?$/
function convertPageMapToJs (line 9) | function convertPageMapToJs({
FILE: packages/nextra/src/server/page-map/to-page-map.ts
type NestedMap (line 5) | interface NestedMap {
type StringMap (line 9) | type StringMap = Record<string, string>
function createNested (line 11) | function createNested(map: NestedMap, path: string): void {
constant APP_DIR_SUFFIX_RE (line 20) | const APP_DIR_SUFFIX_RE = /^(src\/)?app\//
function convertToPageMap (line 22) | function convertToPageMap({
FILE: packages/nextra/src/server/recma-plugins/recma-rewrite.ts
type Mdx (line 10) | enum Mdx {
constant HOC_IMPORT_AST (line 84) | const HOC_IMPORT_AST: ImportDeclaration = {
function createHocCallAst (line 96) | function createHocCallAst(componentName: string): CallExpression {
FILE: packages/nextra/src/server/rehype-plugins/rehype-better-react-mathjax.ts
constant MATHJAX_IMPORTS (line 10) | const MATHJAX_IMPORTS = {
function wrapInMathJaxContext (line 29) | function wrapInMathJaxContext(
function wrapInBraces (line 69) | function wrapInBraces(
FILE: packages/nextra/src/server/rehype-plugins/rehype-extract-toc-content.ts
constant TOC_HEADING_RE (line 10) | const TOC_HEADING_RE = /^h[2-6]$/
function createComputedKey (line 120) | function createComputedKey(
FILE: packages/nextra/src/server/rehype-plugins/rehype-twoslash-popup.ts
constant TWOSLASH_POPUP_IMPORT_AST (line 7) | const TWOSLASH_POPUP_IMPORT_AST = {
FILE: packages/nextra/src/server/rehype-plugins/rehype.ts
type PreElement (line 8) | type PreElement = Element & {
constant CODE_BLOCK_FILENAME_RE (line 14) | const CODE_BLOCK_FILENAME_RE = /filename="([^"]+)"/
constant DEFAULT_REHYPE_PRETTY_CODE_OPTIONS (line 16) | const DEFAULT_REHYPE_PRETTY_CODE_OPTIONS: RehypePrettyCodeOptions = {
method onVisitLine (line 19) | onVisitLine(node) {
method getHighlighter (line 35) | getHighlighter(opts) {
FILE: packages/nextra/src/server/remark-plugins/remark-custom-heading-id.ts
type HProperties (line 5) | type HProperties = {
FILE: packages/nextra/src/server/remark-plugins/remark-link-rewrite.ts
type RemarkLinkRewriteOptions (line 6) | type RemarkLinkRewriteOptions = {
FILE: packages/nextra/src/server/remark-plugins/remark-mdx-frontmatter.ts
function createNode (line 9) | function createNode(data: Record<string, unknown>) {
FILE: packages/nextra/src/server/remark-plugins/remark-mdx-title.ts
function getFrontMatterASTObject (line 10) | function getFrontMatterASTObject(node: MdxjsEsmHast): Property[] {
function isExportNode (line 15) | function isExportNode(
FILE: packages/nextra/src/server/remark-plugins/remark-static-image.ts
constant VALID_BLUR_EXT (line 13) | const VALID_BLUR_EXT = ['.jpeg', '.png', '.webp', '.avif', '.jpg']
constant VARIABLE_PREFIX (line 15) | const VARIABLE_PREFIX = '__img'
FILE: packages/nextra/src/server/schemas.ts
function transformTitle (line 297) | function transformTitle<T>(title: T) {
FILE: packages/nextra/src/server/tsdoc/base.ts
constant DEFAULT_FILENAME (line 32) | const DEFAULT_FILENAME = '$.ts'
function generateDefinition (line 69) | function generateDefinition({
function getCommentAndTags (line 179) | function getCommentAndTags(declaration: ExportedDeclarations): {
function getDocEntry (line 201) | function getDocEntry({
function printType (line 267) | function printType(paramType: Type): string {
function getTypeName (line 283) | function getTypeName({
function prexify (line 356) | function prexify(prefix: string, name: string): string {
function shouldFlattenType (line 360) | function shouldFlattenType(t: Type): boolean {
constant IGNORED_TYPES (line 384) | const IGNORED_TYPES = new Set([
function getTags (line 392) | function getTags(prop: TsSymbol): Tags {
function getFormattedText (line 406) | function getFormattedText(t: Type): string {
function replaceJsDocLinks (line 413) | function replaceJsDocLinks(md: string): string {
FILE: packages/nextra/src/server/tsdoc/tsdoc.tsx
type TSDocProps (line 13) | type TSDocProps = {
function renderMarkdownDefault (line 54) | async function renderMarkdownDefault(description?: string): Promise<Reac...
function FunctionSignature (line 174) | async function FunctionSignature({
function linkify (line 382) | function linkify(
FILE: packages/nextra/src/server/tsdoc/types.ts
type GeneratedType (line 1) | type GeneratedType = {
type Tags (line 6) | type Tags = Record<string, string>
type ReturnField (line 8) | type ReturnField = {
type GeneratedDefinition (line 13) | type GeneratedDefinition = {
type GeneratedFunction (line 32) | type GeneratedFunction = {
type TypeField (line 41) | type TypeField = {
type BaseArgs (line 54) | type BaseArgs = {
FILE: packages/nextra/src/server/tsdoc/zod-to-ts.ts
function generateTsFromZod (line 3) | function generateTsFromZod(schema: z.ZodType, indent = 2): string {
function generateTsFromZodType (line 30) | function generateTsFromZodType(schema: z.ZodType, indent: number): string {
function getDefaultValue (line 87) | function getDefaultValue(schema: z.ZodType): unknown {
function getDocComment (line 99) | function getDocComment(schema: z.ZodType, indent: number): string {
FILE: packages/nextra/src/server/twoslash.ts
function renderMarkdown (line 15) | function renderMarkdown(
function renderMarkdownInline (line 46) | function renderMarkdownInline(
function twoslashRenderer (line 65) | function twoslashRenderer(options?: RendererRichOptions) {
FILE: packages/nextra/src/server/utils.ts
function pageTitleFromFilename (line 16) | function pageTitleFromFilename(fileName: string) {
function createAstExportConst (line 22) | function createAstExportConst(
function createAstObject (line 43) | function createAstObject(
FILE: packages/nextra/src/types.generated.ts
type NextraConfig (line 1) | interface NextraConfig {
type HeadProps (line 138) | interface HeadProps {
FILE: packages/nextra/src/types.ts
type NextraConfigFromZod (line 15) | type NextraConfigFromZod = z.infer<typeof NextraConfigSchema>
type LoaderOptions (line 17) | interface LoaderOptions extends NextraConfigFromZod {
type TPageItem (line 24) | type TPageItem = { name: string; route: string; __pagePath: string }
type TMetaItem (line 25) | type TMetaItem = { __metaPath: string }
type TFolder (line 27) | interface TFolder<T = TItem> {
type TItem (line 33) | type TItem = TPageItem | TMetaItem | TFolder
type Folder (line 35) | interface Folder<FileType = PageMapItem> {
type Import (line 41) | type Import = {
type MetaJsonFile (line 46) | type MetaJsonFile = {
type DynamicFolder (line 52) | type DynamicFolder = {
type DynamicMetaItem (line 57) | type DynamicMetaItem = Meta | DynamicFolder
type DynamicMeta (line 59) | type DynamicMeta = Record<string, DynamicMetaItem>
type FrontMatter (line 61) | type FrontMatter = Record<string, any>
type Meta (line 62) | type Meta = string | Record<string, any>
type MdxFile (line 64) | type MdxFile<FrontMatterType = FrontMatter> = {
type PageMapItem (line 70) | type PageMapItem = Folder | MdxFile | MetaJsonFile
type Page (line 73) | type Page = (MdxFile | Folder<Page>) & {
type Heading (line 77) | type Heading = {
type $NextraMetadata (line 83) | type $NextraMetadata = Omit<Metadata, 'title'> & {
type ReadingTime (line 90) | type ReadingTime = {
type MathJaxOptions (line 97) | type MathJaxOptions = z.infer<typeof MathJaxOptionsSchema>
type MDXWrapper (line 99) | type MDXWrapper = FC<
type MetaRecord (line 106) | type MetaRecord = Record<string, z.infer<typeof metaSchema>>
type SeparatorItem (line 108) | type SeparatorItem = z.infer<typeof separatorItemSchema>
type MenuItem (line 109) | type MenuItem = z.infer<typeof menuSchema>
type PagefindSearchOptions (line 115) | type PagefindSearchOptions = {
type NextraMetadata (line 134) | type NextraMetadata = Metadata & {
type EvaluateResult (line 139) | type EvaluateResult = {
FILE: packages/nextra/tsup.config.ts
constant SEP (line 10) | const SEP = path.sep === '/' ? '/' : '\\\\'
method onSuccess (line 21) | async onSuccess() {
method renderChunk (line 46) | renderChunk(code) {
method renderChunk (line 61) | renderChunk(code) {
FILE: packages/tsdoc/src/__tests__/fixtures/flattened.ts
type EmptyInterface (line 4) | interface EmptyInterface {}
class Class (line 6) | class Class {
type $ (line 10) | type $ = {
FILE: packages/tsdoc/src/__tests__/snapshots/head-props.ts
type $$ (line 1) | interface $$ {
FILE: packages/tsdoc/src/__tests__/snapshots/layout-props.ts
type $ (line 1) | interface $ {
Condensed preview — 652 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,764K chars).
[
{
"path": ".changeset/config.json",
"chars": 587,
"preview": "{\n \"$schema\": \"https://unpkg.com/@changesets/config@2.0.1/schema.json\",\n \"changelog\": \"@changesets/cli/changelog\",\n \""
},
{
"path": ".editorconfig",
"chars": 41,
"preview": "[*]\nindent_style = space\nindent_size = 2\n"
},
{
"path": ".github/CODE_OF_CONDUCT.md",
"chars": 5210,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 830,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n---\n\n**Describe the b"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 603,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n---\n\n**Is "
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 789,
"preview": "<!--\nThank you for contributing to this project! You must fill out the information below before we can\nreview this pull "
},
{
"path": ".github/workflows/lint.yml",
"chars": 923,
"preview": "name: Lint\n\non:\n pull_request:\n branches: [main, v4-v2]\n\njobs:\n lint:\n runs-on: ubuntu-latest\n\n steps:\n "
},
{
"path": ".github/workflows/release.yml",
"chars": 1315,
"preview": "name: Release\n\non:\n push:\n branches: [main, v4-v2]\n\njobs:\n release:\n if: github.repository == 'shuding/nextra'\n\n"
},
{
"path": ".github/workflows/test.yml",
"chars": 993,
"preview": "name: Test\n\non:\n pull_request:\n branches: [main, v4-v2]\n\njobs:\n test:\n name: Test (${{matrix.os}})\n runs-on: "
},
{
"path": ".gitignore",
"chars": 217,
"preview": ".DS_Store\n.next/\n.tsup/\nnode_modules/\n*.log\ndist/\n.turbo/\nout/\n\n.vercel/\n.idea/\n.eslintcache\n.env\n\ntsup.config.bundled*\n"
},
{
"path": ".node-version",
"chars": 3,
"preview": "22\n"
},
{
"path": ".npmrc",
"chars": 80,
"preview": "strict-peer-dependencies=false\nshell-emulator=true\nenable-pre-post-scripts=true\n"
},
{
"path": ".prettierignore",
"chars": 365,
"preview": "pnpm-lock.yaml\n.changeset/*.md\nCHANGELOG.md\ngenerated-page-map.ts\npackages/tsdoc/src/__tests__/snapshots\n\nexamples/swr-s"
},
{
"path": "LICENSE",
"chars": 1065,
"preview": "MIT License\n\nCopyright (c) 2020 Shu Ding\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
},
{
"path": "README.md",
"chars": 1592,
"preview": "# Nextra\n\nSimple, powerful and flexible site generation framework with everything you love\nfrom Next.js.\n\n## Documentati"
},
{
"path": "docs/app/_components/features/index.tsx",
"chars": 1386,
"preview": "import { ArrowRightIcon } from '@components/icons'\nimport cn from 'clsx'\nimport Link from 'next/link'\nimport type { Comp"
},
{
"path": "docs/app/_components/features/style.module.css",
"chars": 2708,
"preview": ".feature {\n position: relative;\n padding: 1.5rem 1.75rem;\n color: #000;\n background-color: white;\n overflow: hidden"
},
{
"path": "docs/app/_components/features/themes-animation.tsx",
"chars": 18320,
"preview": "import type { FC } from 'react'\n\nexport const ThemesAnimation: FC = props => {\n return (\n <svg\n xmlns=\"http://w"
},
{
"path": "docs/app/_components/framer-motion.ts",
"chars": 124,
"preview": "'use client'\n\nimport { motion } from 'framer-motion'\n\nexport const MotionDiv = motion.div\nexport const MotionH3 = motion"
},
{
"path": "docs/app/_components/i18n-demo.tsx",
"chars": 1499,
"preview": "'use client'\n\nimport { ArrowRightIcon } from '@components/icons'\nimport cn from 'clsx'\nimport type { FC } from 'react'\ni"
},
{
"path": "docs/app/_components/overview-page.tsx",
"chars": 1459,
"preview": "import { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'\nimport type { PageMapItem } from 'nex"
},
{
"path": "docs/app/_meta.global.tsx",
"chars": 4691,
"preview": "import type { MetaRecord } from 'nextra'\nimport { LinkArrowIcon } from 'nextra/icons'\nimport type { FC, ReactNode } from"
},
{
"path": "docs/app/about/page.mdx",
"chars": 2815,
"preview": "---\nsidebarTitle: About\ndescription:\n Learn about Nextra's history, team, and contributors, and explore how\n open-sour"
},
{
"path": "docs/app/api/[name]/page.tsx",
"chars": 3920,
"preview": "import path from 'node:path'\nimport { generateApiReference } from '@components/generate-api-reference'\nimport type { Api"
},
{
"path": "docs/app/api/page.mdx",
"chars": 498,
"preview": "import { Callout, Cards } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\nimport { createIndexPag"
},
{
"path": "docs/app/blog/page.mdx",
"chars": 2187,
"preview": "---\nasIndexPage: true\ndescription:\n Stay updated with the latest news and updates from the Nextra team, including\n new"
},
{
"path": "docs/app/docs/advanced/customize-the-cascade-layers/page.mdx",
"chars": 1304,
"preview": "---\nsidebarTitle: Customize Cascade Layers\n---\n\nimport { Steps } from 'nextra/components'\n\n# Customize the Cascade Layer"
},
{
"path": "docs/app/docs/advanced/latex/page.mdx",
"chars": 6871,
"preview": "---\nicon: FormulaIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport {\n Callout,\n MathJax,\n MathJaxContext,\n"
},
{
"path": "docs/app/docs/advanced/mermaid/page.mdx",
"chars": 1024,
"preview": "---\nicon: DiagramIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport { Mermaid } from 'nextra/components'\nimpor"
},
{
"path": "docs/app/docs/advanced/npm2yarn/page.mdx",
"chars": 846,
"preview": "---\nicon: TerminalIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport { Tabs } from 'nextra/components'\nimport "
},
{
"path": "docs/app/docs/advanced/page.mdx",
"chars": 453,
"preview": "---\nasIndexPage: true\n---\n\nimport {\n CloudIcon,\n DiagramIcon,\n FormulaIcon,\n TableIcon,\n TailwindIcon\n} from '@comp"
},
{
"path": "docs/app/docs/advanced/remote/page.mdx",
"chars": 1448,
"preview": "---\nicon: CloudIcon\n---\n\nimport fs from 'node:fs/promises'\nimport { compileMdx } from 'nextra/compile'\nimport { Steps } "
},
{
"path": "docs/app/docs/advanced/table/page.mdx",
"chars": 1871,
"preview": "---\nicon: TableIcon\n---\n\n# Rendering Tables\n\nThis guide covers different ways to render tables in MDX, including GFM syn"
},
{
"path": "docs/app/docs/advanced/tailwind-css/page.mdx",
"chars": 960,
"preview": "---\nicon: TailwindIcon\n---\n\nimport { Steps } from 'nextra/components'\n\n# Tailwind CSS\n\nTailwind CSS is a CSS framework t"
},
{
"path": "docs/app/docs/advanced/twoslash/page.mdx",
"chars": 1343,
"preview": "# Twoslash Support\n\nTwoslash provides an inline type hove inside the code block.\n\n## Basic usage\n\nYou can enable twoslas"
},
{
"path": "docs/app/docs/advanced/typescript/page.mdx",
"chars": 1389,
"preview": "---\nicon: TypeScriptIcon\n---\n\nimport { Steps } from 'nextra/components'\n\n# TypeScript\n\nNextra is built with TypeScript a"
},
{
"path": "docs/app/docs/blog-theme/get-posts-and-tags/page.mdx",
"chars": 304,
"preview": "---\nicon: FilesIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Get Posts and Their Tags\n\nThe followin"
},
{
"path": "docs/app/docs/blog-theme/page.mdx",
"chars": 409,
"preview": "---\nasIndexPage: true\nsidebarTitle: Blog Theme\n---\n\nimport {\n ChevronRightIcon,\n FilesIcon,\n RSSIcon,\n TagsIcon\n} fr"
},
{
"path": "docs/app/docs/blog-theme/posts/page.mdx",
"chars": 262,
"preview": "---\nicon: FileIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Posts Page\n\nThe following code snippet "
},
{
"path": "docs/app/docs/blog-theme/rss/page.mdx",
"chars": 263,
"preview": "---\nicon: RSSIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Generate RSS feed\n\nThe following code sn"
},
{
"path": "docs/app/docs/blog-theme/start/page.mdx",
"chars": 1963,
"preview": "---\nicon: ChevronRightIcon\n---\n\nimport InstallNextraTheme from '@components/install-nextra-theme.mdx'\nimport ReadyToGo f"
},
{
"path": "docs/app/docs/blog-theme/tags/page.mdx",
"chars": 270,
"preview": "---\nicon: TagsIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Tags Page\n\nThe following code snippet d"
},
{
"path": "docs/app/docs/built-ins/[name]/page.tsx",
"chars": 5511,
"preview": "import path from 'node:path'\nimport { generateApiReference } from '@components/generate-api-reference'\nimport type { Api"
},
{
"path": "docs/app/docs/built-ins/page.mdx",
"chars": 1129,
"preview": "---\nasIndexPage: true\nsidebarTitle: Built-In Components\n---\n\nimport {\n CardsIcon,\n FolderTreeIcon,\n IdCardIcon,\n One"
},
{
"path": "docs/app/docs/custom-theme/old.mdx",
"chars": 2369,
"preview": "### Render metadata for the active page\n\n> [!WARNING]\n>\n> Docs from Nextra 3\n\nOther than `children`, some other useful p"
},
{
"path": "docs/app/docs/custom-theme/page.mdx",
"chars": 1930,
"preview": "import { ExampleCode } from 'components/example-code'\nimport { Steps } from 'nextra/components'\nimport OldDocs from './o"
},
{
"path": "docs/app/docs/docs-theme/api/page.mdx",
"chars": 597,
"preview": "# API\n\n## `useThemeConfig` hook\n\nThe `useThemeConfig` hook returns values of your\n[theme configuration](/docs/docs-theme"
},
{
"path": "docs/app/docs/docs-theme/built-ins/footer/page.mdx",
"chars": 918,
"preview": "---\nsidebarTitle: Footer\n---\n\nimport { ToggleVisibilitySection } from 'components/toggle-visibility-section'\n\n# Footer C"
},
{
"path": "docs/app/docs/docs-theme/built-ins/layout/old.mdx",
"chars": 194,
"preview": "## MDX Components [!TODO]\n\nProvide custom [MDX components](https://mdxjs.com/table-of-components) to render\nthe content."
},
{
"path": "docs/app/docs/docs-theme/built-ins/layout/page.mdx",
"chars": 6260,
"preview": "---\nsidebarTitle: Layout\n---\n\nimport { ToggleVisibilitySection } from 'components/toggle-visibility-section'\n\nexport fun"
},
{
"path": "docs/app/docs/docs-theme/built-ins/navbar/page.mdx",
"chars": 3413,
"preview": "---\nsidebarTitle: Navbar\n---\n\nimport { ToggleVisibilitySection } from 'components/toggle-visibility-section'\nimport { ge"
},
{
"path": "docs/app/docs/docs-theme/built-ins/not-found/page.mdx",
"chars": 488,
"preview": "---\nsidebarTitle: NotFoundPage\n---\n\n# NotFoundPage Component\n\nOptions to configure report of broken link on not found pa"
},
{
"path": "docs/app/docs/docs-theme/built-ins/page.mdx",
"chars": 201,
"preview": "---\nasIndexPage: true\nsidebarTitle: Built-In Components\nicon: BoxIcon\n---\n\nimport { OverviewPage } from '../../../_compo"
},
{
"path": "docs/app/docs/docs-theme/page.mdx",
"chars": 297,
"preview": "---\nasIndexPage: true\nsidebarTitle: Docs Theme\n---\n\n# Nextra Docs Theme\n\nimport { BoxIcon, ChevronRightIcon } from '@com"
},
{
"path": "docs/app/docs/docs-theme/start/page.mdx",
"chars": 2789,
"preview": "---\nsidebarTitle: Get Started\nicon: ChevronRightIcon\n---\n\nimport InstallNextraTheme from '@components/install-nextra-the"
},
{
"path": "docs/app/docs/file-conventions/content-directory/page.mdx",
"chars": 3590,
"preview": "---\nicon: FolderIcon\nsidebarTitle: content\ndescription:\n The `content` directory in Nextra allows you to organize your "
},
{
"path": "docs/app/docs/file-conventions/mdx-components-file/page.mdx",
"chars": 2056,
"preview": "---\nicon: MdxIcon\nsidebarTitle: mdx-components.js\ndescription:\n The `mdx-components` file in Nextra is essential for cu"
},
{
"path": "docs/app/docs/file-conventions/meta-file/page.mdx",
"chars": 16606,
"preview": "---\nicon: FileIcon\nsidebarTitle: _meta.js\ndescription:\n The `_meta` file in Nextra allows you to customize page sidebar"
},
{
"path": "docs/app/docs/file-conventions/page-file/page.mdx",
"chars": 1215,
"preview": "---\nicon: FileIcon\nsidebarTitle: page.mdx\ndescription:\n The `page.mdx` file in Nextra is a special Next.js App Router c"
},
{
"path": "docs/app/docs/file-conventions/page.mdx",
"chars": 530,
"preview": "---\nasIndexPage: true\ndescription:\n Nextra's File Conventions guide details the structure and organization of\n files a"
},
{
"path": "docs/app/docs/file-conventions/src-directory/page.mdx",
"chars": 1774,
"preview": "---\nicon: FolderIcon\nsidebarTitle: src\ndescription:\n The `src` directory in Nextra allows you to organize your applicat"
},
{
"path": "docs/app/docs/guide/custom-css/page.mdx",
"chars": 967,
"preview": "---\nsidebarTitle: Custom CSS\nicon: BrushIcon\n---\n\n# Custom CSS Support\n\nNextra is 100% compatible with the\n[built-in CSS"
},
{
"path": "docs/app/docs/guide/github-alert-syntax/page.mdx",
"chars": 2409,
"preview": "---\nicon: InformationCircleIcon\n---\n\n# GitHub Alert Syntax\n\n`nextra-theme-docs` and `nextra-theme-blog` support replacin"
},
{
"path": "docs/app/docs/guide/i18n/page.mdx",
"chars": 2273,
"preview": "---\nicon: GlobeIcon\n---\n\nimport { ExampleCode } from '@components/example-code'\nimport { Steps } from 'nextra/components"
},
{
"path": "docs/app/docs/guide/image/page.mdx",
"chars": 2122,
"preview": "---\nicon: PictureIcon\n---\n\n# Next.js Image\n\nThe standard way to use\n[Next.js Image](https://nextjs.org/docs/app/getting-"
},
{
"path": "docs/app/docs/guide/link/page.mdx",
"chars": 736,
"preview": "---\nicon: LinkIcon\n---\n\n# Next.js Link\n\nAll relative Markdown links are automatically converted into\n[Next.js links](htt"
},
{
"path": "docs/app/docs/guide/markdown/_counter.tsx",
"chars": 321,
"preview": "'use client'\n\nimport type { FC, ReactNode } from 'react'\nimport { useState } from 'react'\n\nexport const Counter: FC<{ ch"
},
{
"path": "docs/app/docs/guide/markdown/page.mdx",
"chars": 2297,
"preview": "---\nicon: MarkdownIcon\n---\n\nimport { Shadow } from '@components/shadow'\nimport { Counter } from './_counter'\n\n# Markdown"
},
{
"path": "docs/app/docs/guide/page.mdx",
"chars": 588,
"preview": "---\nasIndexPage: true\n---\n\nimport {\n BrushIcon,\n GlobeIcon,\n LightningIcon,\n PictureIcon,\n StarsIcon\n} from '@compo"
},
{
"path": "docs/app/docs/guide/search/ai/page.mdx",
"chars": 2967,
"preview": "import { Steps } from 'nextra/components'\n\n# Ask AI\n\nEnhance your Nextra documentation site with AI-powered chat assista"
},
{
"path": "docs/app/docs/guide/search/page.mdx",
"chars": 2125,
"preview": "import { Steps, Tabs } from 'nextra/components'\n\n# Search Engine\n\nNextra includes a full-page search feature that makes "
},
{
"path": "docs/app/docs/guide/ssg/page.mdx",
"chars": 2054,
"preview": "---\nicon: LightningIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport { Callout } from 'nextra/components'\nimp"
},
{
"path": "docs/app/docs/guide/static-exports/page.mdx",
"chars": 1375,
"preview": "import { Steps } from 'nextra/components'\n\n# Static Exports\n\nExport your pages statically, and deploy with [Nginx](https"
},
{
"path": "docs/app/docs/guide/syntax-highlighting/_dynamic-code.tsx",
"chars": 1193,
"preview": "'use client'\n\nimport { Button } from 'nextra/components'\nimport type { FC, ReactNode } from 'react'\nimport { useEffect, "
},
{
"path": "docs/app/docs/guide/syntax-highlighting/page.mdx",
"chars": 7309,
"preview": "---\nicon: StarsIcon\n---\n\nimport { OptionTable } from 'components/_table'\nimport { compileMdx } from 'nextra/compile'\nimp"
},
{
"path": "docs/app/docs/guide/turbopack/page.mdx",
"chars": 1429,
"preview": "# Usage with Turbopack\n\nTo use [Turbopack](https://nextjs.org/docs/architecture/turbopack), simple\nappend the `--turbopa"
},
{
"path": "docs/app/docs/page.mdx",
"chars": 2361,
"preview": "---\ndescription:\n Nextra is a framework built on top of Next.js that enables the creation of\n content-focused websites"
},
{
"path": "docs/app/env.d.ts",
"chars": 378,
"preview": "declare module '*.svg?svgr' {\n import type { FC, SVGProps } from 'react'\n const ReactComponent: FC<SVGProps<SVGElement"
},
{
"path": "docs/app/globals.css",
"chars": 927,
"preview": "@import 'nextra-theme-docs/style.css';\n@import 'tailwindcss';\n/* Whitelist Tailwind CSS classes from <Bleed> TSDoc examp"
},
{
"path": "docs/app/layout.tsx",
"chars": 4209,
"preview": "import { getEnhancedPageMap } from '@components/get-page-map'\nimport { NextraLogo, VercelLogo } from '@components/icons'"
},
{
"path": "docs/app/not-found.ts",
"chars": 60,
"preview": "export { NotFoundPage as default } from 'nextra-theme-docs'\n"
},
{
"path": "docs/app/og/route.tsx",
"chars": 1907,
"preview": "/* eslint react/no-unknown-property: ['error', { ignore: ['tw'] }] */\nimport { NextraLogo } from '@components/icons'\nimp"
},
{
"path": "docs/app/page.css",
"chars": 3922,
"preview": ".content-container {\n max-width: var(--nextra-content-width);\n padding-left: max(env(safe-area-inset-left), 1.5rem);\n "
},
{
"path": "docs/app/page.module.css",
"chars": 1651,
"preview": ".file {\n display: inline-block;\n font-size: 0.9em;\n padding: 1px 6px;\n border-radius: 0.375rem;\n border: 1px solid "
},
{
"path": "docs/app/page.tsx",
"chars": 12370,
"preview": "import { ArrowRightIcon } from '@components/icons'\nimport type { Metadata } from 'next'\nimport Image from 'next/image'\ni"
},
{
"path": "docs/app/showcase/page.mdx",
"chars": 5148,
"preview": "---\ndescription:\n Explore projects powered by Nextra, showcasing a diverse range of websites and\n applications built w"
},
{
"path": "docs/app/sponsors/page.mdx",
"chars": 1428,
"preview": "---\ndescription:\n Support Nextra by exploring its sponsors. Learn how they contribute to the\n development and success "
},
{
"path": "docs/components/_slider.tsx",
"chars": 1758,
"preview": "'use client'\n\nimport type { ComponentProps, FC } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\n\n"
},
{
"path": "docs/components/_table/index.tsx",
"chars": 1446,
"preview": "import type { FC } from 'react'\nimport styles from './style.module.css'\n\nexport const OptionTable: FC<{ options: [string"
},
{
"path": "docs/components/_table/style.module.css",
"chars": 225,
"preview": ".container {\n mask-image: linear-gradient(\n to right,\n transparent 0.8em,\n white 1.5em,\n white calc(100% - "
},
{
"path": "docs/components/content-and-app-file-tree.tsx",
"chars": 2365,
"preview": "import path from 'node:path'\nimport { FileTree } from 'nextra/components'\nimport type { FC, ReactNode } from 'react'\nimp"
},
{
"path": "docs/components/example-code.tsx",
"chars": 709,
"preview": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { compileMdx } from 'nextra/compile'\nimport type {"
},
{
"path": "docs/components/example-tsdoc.mdx",
"chars": 475,
"preview": "```ts\ntype Example = {\n /**\n * **Foo** description.\n * @default \"dimaMachina\"\n * @remarks `\"not dimaMachina\"`\n "
},
{
"path": "docs/components/generate-api-reference.ts",
"chars": 2133,
"preview": "import { BoxIcon, CardsIcon, OneIcon, WarningIcon } from '@components/icons'\nimport { useMDXComponents as getMDXComponen"
},
{
"path": "docs/components/get-page-map.ts",
"chars": 1926,
"preview": "import type { MetaJsonFile, PageMapItem } from 'nextra'\nimport { getPageMap } from 'nextra/page-map'\nimport { pageMap as"
},
{
"path": "docs/components/icons/index.ts",
"chars": 1748,
"preview": "export { default as FilesIcon } from './files.svg?svgr'\nexport { default as TailwindIcon } from './tailwind.svg?svgr'\nex"
},
{
"path": "docs/components/inkeep-chat-button.tsx",
"chars": 990,
"preview": "'use client'\n\nimport { InkeepChatButton } from '@inkeep/cxkit-react'\nimport type { FC } from 'react'\n\nexport const ChatB"
},
{
"path": "docs/components/install-nextra-theme.mdx",
"chars": 1684,
"preview": "Add the following scripts to your `package.json`:\n\n```json filename=\"package.json\"\n\"scripts\": {\n \"dev\": \"next\",\n \"buil"
},
{
"path": "docs/components/playground-demo.tsx",
"chars": 2529,
"preview": "'use client'\n\n// NOTE: We have intentionally omitted a local mdx-components file because it\n// includes the server-only "
},
{
"path": "docs/components/ready-to-go.mdx",
"chars": 377,
"preview": "### Render MDX files\n\nThere are two ways to render MDX files using file-based routing, add your MDX\nfiles via [`page` fi"
},
{
"path": "docs/components/shadow.jsx",
"chars": 624,
"preview": "'use client'\n\n// https://gist.github.com/janily/04d7fb0861e053d4679b38743ffc05a7\nimport { Component } from 'react'\nimpor"
},
{
"path": "docs/components/toggle-visibility-section.tsx",
"chars": 671,
"preview": "import { compileMdx } from 'nextra/compile'\nimport { MDXRemote } from 'nextra/mdx-remote'\nimport type { FC } from 'react"
},
{
"path": "docs/components/video.tsx",
"chars": 343,
"preview": "import type { FC } from 'react'\n\nexport const Video: FC<{ src: string }> = ({ src }) => {\n return (\n <video\n mu"
},
{
"path": "docs/mdx-components.tsx",
"chars": 4983,
"preview": "import { getEnhancedPageMap } from '@components/get-page-map'\nimport type { Folder } from 'nextra'\nimport { useMDXCompon"
},
{
"path": "docs/next-sitemap.config.js",
"chars": 198,
"preview": "/** @type {import('next-sitemap').IConfig} */\nexport default {\n siteUrl: 'https://nextra.site',\n changefreq: 'weekly',"
},
{
"path": "docs/next.config.ts",
"chars": 4037,
"preview": "import nextra from 'nextra'\n\n// @ts-expect-error -- fixme\nfunction isExportNode(node, varName: string) {\n if (node.type"
},
{
"path": "docs/package.json",
"chars": 841,
"preview": "{\n \"name\": \"docs\",\n \"author\": \"Shu Ding\",\n \"license\": \"MIT\",\n \"private\": true,\n \"scripts\": {\n \"build\": \"next bui"
},
{
"path": "docs/postcss.config.mjs",
"chars": 229,
"preview": "// If you want to use other PostCSS plugins, see the following:\n// https://tailwindcss.com/docs/using-with-preprocessors"
},
{
"path": "docs/tsconfig.json",
"chars": 1107,
"preview": "{\n \"compilerOptions\": {\n \"baseUrl\": \".\",\n \"target\": \"es2022\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \""
},
{
"path": "docs/vercel.json",
"chars": 21,
"preview": "{\n \"public\": true\n}\n"
},
{
"path": "examples/blog/app/_meta.global.js",
"chars": 153,
"preview": "export default {\n index: {\n type: 'page'\n },\n posts: {\n type: 'page',\n items: {\n draft: {\n displ"
},
{
"path": "examples/blog/app/layout.jsx",
"chars": 1439,
"preview": "import { Footer, Layout, Navbar, ThemeSwitch } from 'nextra-theme-blog'\nimport { Banner, Head, Search } from 'nextra/com"
},
{
"path": "examples/blog/app/page.mdx",
"chars": 188,
"preview": "---\ntitle: About\n---\n\nHey there!\n\n\n\nThis Markdown image is automatically converted into a"
},
{
"path": "examples/blog/app/posts/(with-comments)/aaron-swartz-a-programmable-web/page.mdx",
"chars": 5191,
"preview": "---\ntitle: Notes on A Programmable Web by Aaron Swartz\ndate: 2016-05-21\ndescription:\n At the time when I was getting in"
},
{
"path": "examples/blog/app/posts/(with-comments)/code-blocks/page.mdx",
"chars": 1112,
"preview": "---\ntitle: Code blocks\ndate: 2022-07-29\ndescription: En example of using code blocks in your blog.\ntags:\n [\n web dev"
},
{
"path": "examples/blog/app/posts/(with-comments)/draft/page.mdx",
"chars": 367,
"preview": "---\ntitle: Draft\ndate: 2023-06-28\ndescription: An example of a draft post.\ntags: [web development]\nauthor: Ada Lovelace\n"
},
{
"path": "examples/blog/app/posts/(with-comments)/layout.jsx",
"chars": 224,
"preview": "import { Comments } from 'nextra-theme-blog'\n\nexport default function CommentsLayout({ children }) {\n return (\n <>\n "
},
{
"path": "examples/blog/app/posts/(with-comments)/lists/page.mdx",
"chars": 297,
"preview": "---\ntitle: Lists\ndate: 2024-07-11\ndescription: Example of ordered/unordered nested lists.\ntags: [web development]\nauthor"
},
{
"path": "examples/blog/app/posts/(with-comments)/nextra-components/page.mdx",
"chars": 3359,
"preview": "---\ntitle: Nextra Components\ndate: 2023-05-15\ndescription: En example of using the Callout component in your blog.\ntags:"
},
{
"path": "examples/blog/app/posts/(with-comments)/table/page.mdx",
"chars": 553,
"preview": "---\ntitle: Table\ndate: 2022-08-28\ndescription: En example of using table.\ntags: [web development]\nauthor: Dimitri POSTOL"
},
{
"path": "examples/blog/app/posts/get-posts.js",
"chars": 534,
"preview": "import { normalizePages } from 'nextra/normalize-pages'\nimport { getPageMap } from 'nextra/page-map'\n\nexport async funct"
},
{
"path": "examples/blog/app/posts/page.jsx",
"chars": 894,
"preview": "import Link from 'next/link'\nimport { PostCard } from 'nextra-theme-blog'\nimport { getPosts, getTags } from './get-posts"
},
{
"path": "examples/blog/app/rss.xml/route.js",
"chars": 956,
"preview": "import { getPosts } from '../posts/get-posts.js'\n\nconst CONFIG = {\n title: 'My Blog',\n siteUrl: 'https://your-domain.c"
},
{
"path": "examples/blog/app/tags/[tag]/page.jsx",
"chars": 843,
"preview": "import { PostCard } from 'nextra-theme-blog'\nimport { getPosts, getTags } from '../../posts/get-posts'\n\nexport async fun"
},
{
"path": "examples/blog/mdx-components.jsx",
"chars": 669,
"preview": "import { useMDXComponents as getBlogMDXComponents } from 'nextra-theme-blog'\n\nconst blogComponents = getBlogMDXComponent"
},
{
"path": "examples/blog/next.config.js",
"chars": 187,
"preview": "import nextra from 'nextra'\n\nconst withNextra = nextra({\n defaultShowCopyCode: true,\n readingTime: true\n})\n\nexport def"
},
{
"path": "examples/blog/package.json",
"chars": 483,
"preview": "{\n \"name\": \"example-blog\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"private\": true,\n \"scripts\": {\n \"build\": \"next"
},
{
"path": "examples/custom-theme/app/_components/footer.tsx",
"chars": 213,
"preview": "import type { FC } from 'react'\n\nexport const Footer: FC = () => {\n return (\n <footer style={{ background: 'lightsal"
},
{
"path": "examples/custom-theme/app/_components/navbar.tsx",
"chars": 957,
"preview": "'use client'\n\nimport { usePathname } from 'next/navigation'\nimport type { PageMapItem } from 'nextra'\nimport { Anchor } "
},
{
"path": "examples/custom-theme/app/_components/nextra-theme.tsx",
"chars": 779,
"preview": "import type { PageMapItem } from 'nextra'\nimport { version } from 'nextra/package.json'\nimport type { FC, ReactNode } fr"
},
{
"path": "examples/custom-theme/app/_components/sidebar.tsx",
"chars": 1533,
"preview": "'use client'\n\nimport { usePathname } from 'next/navigation'\nimport type { PageMapItem } from 'nextra'\nimport { Anchor } "
},
{
"path": "examples/custom-theme/app/_components/toc.tsx",
"chars": 366,
"preview": "import type { Heading } from 'nextra'\nimport type { FC } from 'react'\n\nexport const TOC: FC<{ toc: Heading[] }> = ({ toc"
},
{
"path": "examples/custom-theme/app/_meta.global.ts",
"chars": 241,
"preview": "export default {\n index: {\n type: 'page'\n },\n docs: {\n title: 'Documentation',\n type: 'page',\n items: {\n "
},
{
"path": "examples/custom-theme/app/docs/nested-level/bar/page.mdx",
"chars": 14,
"preview": "# Nexted Page\n"
},
{
"path": "examples/custom-theme/app/docs/one-level/page.mdx",
"chars": 17,
"preview": "# One level page\n"
},
{
"path": "examples/custom-theme/app/docs/page.mdx",
"chars": 18,
"preview": "# Getting Started\n"
},
{
"path": "examples/custom-theme/app/layout.tsx",
"chars": 667,
"preview": "import type { Metadata } from 'next'\nimport { Head } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-ma"
},
{
"path": "examples/custom-theme/app/page.mdx",
"chars": 52,
"preview": "# Home\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n"
},
{
"path": "examples/custom-theme/mdx-components.jsx",
"chars": 435,
"preview": "import { useMDXComponents as getNextraComponents } from 'nextra/mdx-components'\nimport { TOC } from './app/_components/t"
},
{
"path": "examples/custom-theme/next.config.ts",
"chars": 115,
"preview": "import nextra from 'nextra'\n\nconst withNextra = nextra({})\n\nexport default withNextra({\n reactStrictMode: true\n})\n"
},
{
"path": "examples/custom-theme/package.json",
"chars": 510,
"preview": "{\n \"name\": \"example-custom-theme\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"private\": true,\n \"scripts\": {\n \"build"
},
{
"path": "examples/custom-theme/public/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "examples/custom-theme/tsconfig.json",
"chars": 637,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n "
},
{
"path": "examples/docs/mdx-components.js",
"chars": 214,
"preview": "import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'\n\nconst docsComponents = getDocsMDXComponent"
},
{
"path": "examples/docs/next.config.mjs",
"chars": 200,
"preview": "import nextra from 'nextra'\n\nconst withNextra = nextra({\n latex: true,\n search: {\n codeblocks: false\n },\n content"
},
{
"path": "examples/docs/package.json",
"chars": 473,
"preview": "{\n \"name\": \"example-docs\",\n \"license\": \"MIT\",\n \"private\": true,\n \"scripts\": {\n \"build\": \"next build --webpack\",\n "
},
{
"path": "examples/docs/src/app/_ignored/_meta.js",
"chars": 107,
"preview": "// This file will be NOT treated as `_meta` file, since directory starts with underscore\nexport default {}\n"
},
{
"path": "examples/docs/src/app/_ignored/page.mdx",
"chars": 78,
"preview": "This file will be NOT treated as page, since directory starts with underscore\n"
},
{
"path": "examples/docs/src/app/_meta.js",
"chars": 167,
"preview": "export default {\n index: {\n display: 'hidden'\n },\n docs: {\n type: 'page',\n title: 'Documentation'\n },\n blo"
},
{
"path": "examples/docs/src/app/blog/page.jsx",
"chars": 222,
"preview": "export default function BlogPage() {\n return (\n <h1\n style={{\n textAlign: 'center',\n fontSize: 64"
},
{
"path": "examples/docs/src/app/docs/[[...mdxPath]]/page.jsx",
"chars": 767,
"preview": "import { generateStaticParamsFor, importPage } from 'nextra/pages'\nimport { useMDXComponents as getMDXComponents } from "
},
{
"path": "examples/docs/src/app/layout.jsx",
"chars": 1604,
"preview": "/* eslint-env node */\nimport { Footer, Layout, Navbar } from 'nextra-theme-docs'\nimport { Banner, Head } from 'nextra/co"
},
{
"path": "examples/docs/src/app/page.jsx",
"chars": 224,
"preview": "export default function IndexPage() {\n return (\n <h1\n style={{\n textAlign: 'center',\n fontSize: 6"
},
{
"path": "examples/docs/src/app/showcase/(overview)/page.jsx",
"chars": 217,
"preview": "export default function Page() {\n return (\n <h1\n style={{\n textAlign: 'center',\n fontSize: 64,\n "
},
{
"path": "examples/docs/src/content/_meta.js",
"chars": 142,
"preview": "export default {\n index: '',\n 'get-started': '',\n features: '',\n themes: '',\n advanced: {\n theme: {\n copyPa"
},
{
"path": "examples/docs/src/content/advanced/code-highlighting.mdx",
"chars": 1358,
"preview": "# Code Highlighting\n\nNextra uses [Shiki](https://shiki.style) and\n[Rehype Pretty Code](https://github.com/FormidableLabs"
},
{
"path": "examples/docs/src/content/features/_meta.js",
"chars": 92,
"preview": "export default {\n mdx: '',\n ssg: '',\n i18n: '',\n image: '',\n themes: '',\n latex: ''\n}\n"
},
{
"path": "examples/docs/src/content/features/i18n.mdx",
"chars": 1084,
"preview": "# Next.js I18n\n\n> [!NOTE]\n>\n> This feature is only available in the docs theme.\n\nNextra supports\n[Next.js Internationali"
},
{
"path": "examples/docs/src/content/features/image.mdx",
"chars": 847,
"preview": "# Next.js Image\n\nYou can use [Next.js Image](https://nextjs.org/docs/app/getting-started/images)\ndirectly in MDX.\n\nIf th"
},
{
"path": "examples/docs/src/content/features/latex.mdx",
"chars": 867,
"preview": "{/* <link rel=\"stylesheet\"> is unsupported in Metadata API https://nextjs.org/docs/app/api-reference/functions/generate-"
},
{
"path": "examples/docs/src/content/features/mdx.mdx",
"chars": 3400,
"preview": "import { compileMdx } from 'nextra/compile'\nimport { Callout } from 'nextra/components'\nimport { MDXRemote } from 'nextr"
},
{
"path": "examples/docs/src/content/features/ssg.mdx",
"chars": 1625,
"preview": "# Next.js Static Rendering\n\n[Static Rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-co"
},
{
"path": "examples/docs/src/content/features/themes.mdx",
"chars": 591,
"preview": "# Themes\n\nNextra itself is basically a plugin that normalizes your Markdown routes in\nNext.js into structural data, and "
},
{
"path": "examples/docs/src/content/get-started.mdx",
"chars": 2983,
"preview": "import { Steps } from 'nextra/components'\n\n# Get Started\n\n## Quick start with Vercel\n\nYou can start by creating your own"
},
{
"path": "examples/docs/src/content/index.mdx",
"chars": 520,
"preview": "import { Bleed } from 'nextra/components'\n\n# Introduction\n\n**Nextra** is a [Next.js](https://nextjs.org) based static si"
},
{
"path": "examples/docs/src/content/mermaid.mdx",
"chars": 295,
"preview": "# Mermaid\n\n```mermaid\ngraph TD;\n subgraph AA [Consumers]\n A[Mobile app];\n B[Web app];\n C[Node.js client];\n en"
},
{
"path": "examples/docs/src/content/page.mdx",
"chars": 72,
"preview": "# Just Page\n\n{/* this file should not be treated as App Router page */}\n"
},
{
"path": "examples/docs/src/content/themes/_meta.js",
"chars": 62,
"preview": "export default {\n docs: 'Docs Theme',\n blog: 'Blog Theme'\n}\n"
},
{
"path": "examples/docs/src/content/themes/blog/_meta.js",
"chars": 31,
"preview": "export default {\n index: ''\n}\n"
},
{
"path": "examples/docs/src/content/themes/blog/index.mdx",
"chars": 1904,
"preview": "---\nsidebarTitle: Installation\n---\n\n# Get Started\n\nimport { Steps } from 'nextra/components'\n\n## Configurations\n\nSimilar"
},
{
"path": "examples/docs/src/content/themes/docs/_meta.js",
"chars": 80,
"preview": "export default {\n index: '',\n configuration: '',\n callout: '',\n bleed: ''\n}\n"
},
{
"path": "examples/docs/src/content/themes/docs/bleed.mdx",
"chars": 1776,
"preview": "---\nsidebarTitle: Bleed\n---\n\n# Bleed Component\n\nA built-in component provided by `nextra-theme-docs`.\n\n## Example\n\nWhen "
},
{
"path": "examples/docs/src/content/themes/docs/callout.mdx",
"chars": 1209,
"preview": "---\nsidebarTitle: Callout\n---\n\n# Callout Component\n\nA built-in component provided by `nextra/components`.\n\n## Example\n\ni"
},
{
"path": "examples/docs/src/content/themes/docs/configuration.mdx",
"chars": 9063,
"preview": "# Configuration\n\nTo configure the theme, edit or create the `theme.config.js` file in the root\ndirectory. The file looks"
},
{
"path": "examples/docs/src/content/themes/docs/index.mdx",
"chars": 1751,
"preview": "---\nsidebarTitle: Installation\n---\n\n# Docs Theme\n\nimport { Steps } from 'nextra/components'\n\n> [!NOTE]\n>\n> This website "
},
{
"path": "examples/docs/src/content/themes/docs/tabs.mdx",
"chars": 1532,
"preview": "---\nsidebarTitle: Tabs\n---\n\n# Tabs Component\n\nA built-in component provided by `nextra-theme-docs`.\n\n## Example\n\nimport "
},
{
"path": "examples/swr-site/README.md",
"chars": 27,
"preview": "# SWR i18n Example Website\n"
},
{
"path": "examples/swr-site/app/[lang]/[[...mdxPath]]/page.tsx",
"chars": 957,
"preview": "import { generateStaticParamsFor, importPage } from 'nextra/pages'\nimport type { FC } from 'react'\nimport { useMDXCompon"
},
{
"path": "examples/swr-site/app/[lang]/graphql-eslint/[[...slug]]/page.tsx",
"chars": 2133,
"preview": "import { notFound } from 'next/navigation'\nimport { compileMdx } from 'nextra/compile'\nimport { Callout, Tabs } from 'ne"
},
{
"path": "examples/swr-site/app/[lang]/layout.tsx",
"chars": 4168,
"preview": "/* eslint-env node */\nimport { SwrIcon, VercelIcon } from '@app/_icons'\nimport type { Metadata } from 'next'\nimport {\n "
},
{
"path": "examples/swr-site/app/[lang]/not-found.ts",
"chars": 60,
"preview": "export { NotFoundPage as default } from 'nextra-theme-docs'\n"
},
{
"path": "examples/swr-site/app/[lang]/remote/graphql-yoga/[[...slug]]/page.tsx",
"chars": 2778,
"preview": "import { notFound } from 'next/navigation'\nimport { useMDXComponents as getMDXComponents } from 'nextra-theme-docs'\nimpo"
},
{
"path": "examples/swr-site/app/[lang]/styles.css",
"chars": 469,
"preview": "@import 'tailwindcss';\n@import 'nextra-theme-docs/style.css';\n@import '../_components/features.css';\n\n@theme {\n}\n\nbody {"
},
{
"path": "examples/swr-site/app/_components/authors.tsx",
"chars": 1151,
"preview": "import { getDictionary } from '@app/_dictionaries/get-dictionary'\nimport type { Locale } from '@app/_dictionaries/i18n-c"
},
{
"path": "examples/swr-site/app/_components/blog.tsx",
"chars": 1055,
"preview": "import type { MdxFile } from 'nextra'\nimport { Link } from 'nextra-theme-docs'\nimport { getPageMap } from 'nextra/page-m"
},
{
"path": "examples/swr-site/app/_components/example-dynamic-markdown-import.tsx",
"chars": 564,
"preview": "'use client'\n\nimport dynamic from 'next/dynamic'\nimport { useState } from 'react'\n\nexport function ExampleDynamicMarkdow"
},
{
"path": "examples/swr-site/app/_components/external.mdx",
"chars": 133,
"preview": "import { Callout } from 'nextra/components'\n\n<Callout type=\"info\" emoji=\"💣\">\n This `<Callout>` comes from `external.mdx"
},
{
"path": "examples/swr-site/app/_components/features.css",
"chars": 605,
"preview": ".features {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr 1fr;\n gap: 1rem 2rem;\n margin: 2.5rem 0 2rem;\n}\n.fea"
},
{
"path": "examples/swr-site/app/_components/features.tsx",
"chars": 1620,
"preview": "import type { FC } from 'react'\nimport { getDictionary } from '../_dictionaries/get-dictionary'\nimport type { Locale } f"
},
{
"path": "examples/swr-site/app/_components/video.tsx",
"chars": 1612,
"preview": "'use client'\n\nimport type { FC, ReactNode } from 'react'\nimport { useCallback, useEffect, useRef } from 'react'\nimport {"
},
{
"path": "examples/swr-site/app/_dictionaries/en.ts",
"chars": 638,
"preview": "export default {\n dark: 'Dark',\n light: 'Light',\n system: 'System',\n backToTop: 'Scroll to top',\n lastUpdated: 'Las"
},
{
"path": "examples/swr-site/app/_dictionaries/es.ts",
"chars": 759,
"preview": "import type { Dictionary } from './i18n-config'\n\nexport default {\n dark: 'Oscuro',\n light: 'Luz',\n system: 'Sistema',"
},
{
"path": "examples/swr-site/app/_dictionaries/get-dictionary.ts",
"chars": 658,
"preview": "import 'server-only'\nimport type { Dictionaries, Dictionary } from './i18n-config'\n\n// We enumerate all dictionaries her"
},
{
"path": "examples/swr-site/app/_dictionaries/i18n-config.ts",
"chars": 316,
"preview": "import type EnglishLocale from './en'\n\nexport const i18n = {\n defaultLocale: 'en',\n locales: ['en', 'es', 'ru']\n} as c"
},
{
"path": "examples/swr-site/app/_dictionaries/ru.ts",
"chars": 729,
"preview": "import type { Dictionary } from './i18n-config'\n\nexport default {\n dark: 'Темный',\n light: 'Светлый',\n system: 'Систе"
},
{
"path": "examples/swr-site/app/_icons/index.ts",
"chars": 854,
"preview": "export { default as FeatherIcon } from './feather.svg?svgr'\nexport { default as LightningIcon } from './lightning.svg?sv"
},
{
"path": "examples/swr-site/app/env.d.ts",
"chars": 378,
"preview": "declare module '*.mdx' {\n import type { FC } from 'react'\n import type { MDXComponents } from 'nextra/mdx-components'\n"
},
{
"path": "examples/swr-site/app/manifest.ts",
"chars": 487,
"preview": "import type { MetadataRoute } from 'next'\n\nexport default function manifest(): MetadataRoute.Manifest {\n return {\n n"
},
{
"path": "examples/swr-site/content/en/_meta.ts",
"chars": 783,
"preview": "export default {\n index: {\n type: 'page',\n display: 'hidden',\n theme: {\n typesetting: 'article',\n to"
},
{
"path": "examples/swr-site/content/en/about/_meta.ts",
"chars": 92,
"preview": "export default {\n team: '👥 Team',\n acknowledgement: '🧩 Acknowledgement',\n 'a-page': ''\n}\n"
}
]
// ... and 452 more files (download for full content)
About this extraction
This page contains the full source code of the shuding/nextra GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 652 files (1.6 MB), approximately 471.3k tokens, and a symbol index with 373 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.