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 ================================================ ## Why: Closes: ## What's being changed (if available, include any code snippets, screenshots, or gifs): ## 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
Inkeep - AI Agents that get real work done xyflow preview
================================================ 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 > = ({ large, centered, children, lightOnly, className, href, index, ...props }) => { return ( {children} {href && ( )} ) } export const Features: FC<{ children: ReactNode }> = ({ children }) => { return
{children}
} ================================================ 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 ( ) } ================================================ 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 (
{LANGUAGES.map(({ lang }) => ( setActive(lang)} className={cn(styles.file, active === lang && styles.active)} > /{lang}/hello.mdx ))}
{LANGUAGES.map(({ lang, name }) => (
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}
))}
) } ================================================ 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 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

{pageItem.title}

} return ( {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 } /> ) })} ) }) } ================================================ 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}  ) } 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: page.jsx }, _3: { href: 'https://nextjs.org/docs/app/api-reference/file-conventions/layout', title: layout.jsx }, _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: app }, _7: { href: 'https://nextjs.org/docs/app/building-your-application/optimizing/static-assets?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar', title: public } } const GUIDE: MetaRecord = { markdown: '', 'syntax-highlighting': '', link: '', image: '', ssg: '', i18n: '', 'custom-css': '', 'static-exports': '', search: { items: { index: '', ai: { title: Ask AI } }, 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: <>/posts Page, // prettier-ignore tags: <>/tags/:id Page, // prettier-ignore rss: <>/rss.xml 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 => } }) } # 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. | ![Nextra icon](../icon.svg) | | Logo | Full Nextra logo | ![Nextra logo](/logo.svg) | | Social Card | The Nextra social card | ![Nextra card](/opengraph-image.jpeg) | ## 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 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 = async props => { const { default: MDXContent, toc, metadata, sourceCode } = await getReference(props) return ( ) } 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 This API reference is automatically generated from the catch-all route file `/api/[name]/page.tsx` using the new [Nextra `` component](/docs/built-ins/tsdoc). ================================================ 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 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 => (

{page.title}

{page.description}{' '} {page.date && Read more}

{page.date ? ( ) : ( Coming soon! )}
)) } ================================================ 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: ## 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 } ``` ================================================ 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' {/* is unsupported in Metadata API https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata */} # 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 ### 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 This is applicable only to KaTeX as the math renderer. 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' ``` Add `{:jsx}` inside `` element in your root `layout` file since `{: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 `{:jsx}` directly in your MDX file: ````mdx filename="katex.mdx" # My page with single usage of KaTeX ```math \int_2^3x^3\,\mathrm{d}x ``` ```` ## 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:
The **Pythagorean equation** is $a=\sqrt{b^2 + c^2}$ and the quadratic formula: ```math x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} ```
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 `{: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 ``` 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 ( ) } ================================================ 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 `` component. ## Example 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 } ================================================ 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 [`` and `` 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 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 } ================================================ 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 ================================================ 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 } # 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. ## Create `[[...slug]]/page.tsx` file Create `[[...slug]]/page.tsx` file in `app/` directory with the following content: ## 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] ``` ================================================ 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 `{:js}`, `{:js}`, `{:js}`, `{:js}`, `
{:js}` and `{: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 `` 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 `
`, ``, ``, ``, `` and `
`, and `` 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. ## 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 } ``` ================================================ 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 = { title: 'Delete inactive users'.toUpperCase() // ^? } todo.title = 'Hello' Number.parseInt('123', 10) // ^| // Just comments, so Popup will be // not behind the viewport of `` // element due his `position: absolute` style // ``` ```` Renders: {/* prettier-ignore */} ```ts twoslash // @errors: 2540 interface Todo { title: string } const todo: Readonly = { 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: ` Custom log message - `@error: ` Custom error message - `@warn: ` Custom warn message - `@annotate: ` 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: ### 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. ## 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. ================================================ 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 ================================================ 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. ================================================ 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. ================================================ 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 ### 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. {/* ### 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:

MIT 2023 © Nextra.

, head: ({ title, meta }) => ( <> {meta.description && ( )} {meta.tag && } {meta.author && } ), readMore: 'Read More →', postFooter: null, darkMode: false, navs: [ { url: 'https://github.com/shuding/nextra', name: 'Nextra' } ] } ``` */}
## Layout Props ================================================ 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. ================================================ 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' }, { name: 'Head', packageName: 'nextra/components', isFlattened: true }, { name: 'Search', packageName: 'nextra/components', isFlattened: false, groupKeys: "Omit" }, { type: 'separator', title: 'Content Components', name: '_2' }, { name: 'Bleed', packageName: 'nextra/components', groupKeys: 'HTMLAttributes' }, { name: 'Callout', packageName: 'nextra/components', groupKeys: 'HTMLAttributes' }, { // TODO: add // name: 'Cards', packageName: 'nextra/components', groupKeys: 'HTMLAttributes' }, { // TODO: add // // name: 'FileTree', packageName: 'nextra/components', groupKeys: 'HTMLAttributes' }, { name: 'Steps', packageName: 'nextra/components', groupKeys: 'HTMLAttributes' }, { // TODO: add // // // name: 'Table', packageName: 'nextra/components', groupKeys: 'HTMLAttributes' }, { 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' ? ( {o.name} ) : ( 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 & { '...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 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: ` // **Tip for TypeScript users:**
// You can retrieve the props type for the \`<${name}>\` component using \`React.ComponentProps\`. //
` }) 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 = async props => { const { default: MDXContent, toc, metadata, sourceCode } = await getReference(props) return ( ) } 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 This API reference is automatically generated from the catch-all route file `/docs/built-ins/[name]/page.tsx` using the new [Nextra `` component](/docs/built-ins/tsdoc). 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 */} 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 `` - 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} {children} ) } function MyWrapper({ children, toc }) { return ( <>

My Theme

Table of Contents:
    {toc.map(heading => (
  • {heading.value}
  • ))}
{children}
) } ``` ### 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 (

My Theme

{pageMap.map(item => { if ('route' in item && !('children' in item)) { return ( {item.route} ) } })}
{children}
) } ``` 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 ### Create a root layout ### Create [`mdx-components` file](/docs/file-conventions/mdx-components-file) ### 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: ### Create navbar and footer ### Create sidebar ### Add first MDX page After creating the theme, you can simply add a MDX file as `app/page.mdx` and see the result: ![Custom theme](/assets/docs/custom-theme.png)
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' && }
================================================ 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' ``` ## `useConfig` hook ```js import { useConfig } from 'nextra-theme-docs' ``` The `useConfig` hook returns data from your current page context. ================================================ 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 ## 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 ( {children}
MIT {new Date().getFullYear()} ©{' '} Nextra .
{children}
) } ``` ================================================ 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 ( , ${props.map(prop => JSON.stringify(prop)).join('|')}> export default $`} /> ) } # Layout Component The theme is configured with the `` 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 ( {children} ) } ``` Detailed information for each option is listed below. ## Props ## Page Map ## Banner ## Navbar ## Footer ## 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). ### 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" {children} ``` Then Nextra will automatically generate the correct file path for all pages. ## Dark Mode and Themes Customize the theme behavior of the website. import Old from './old.mdx' {process.env.NODE_ENV !== 'production' && } ## Edit Link Show an "Edit this page" link on the page that points to the file URL on GitHub (or other places). > [!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. > [!TIP] > > To disable it, you can set `feedback.content` to `null`. ## I18n ## Last Updated Date Show the last updated date of a page. It's useful for showing the freshness of the content. ## Navigation Show previous and next page links on the bottom of the content. It's useful for navigating between pages. ![Navigation](/assets/docs/navigation.png) ```jsx filename="app/layout.jsx" {children} ``` The above is also equivalent to `navigation: true{:js}`. ## Sidebar ### 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: (
{children}
) }, frameworks: 'JS Frameworks & Libs', about: 'About' } ``` ![Customized Sidebar](/assets/docs/sidebar-customized.png) ### 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 You are able to customize the option names for localization or other purposes: ```jsx filename="app/layout.jsx" {children} ``` ## Table of Contents (TOC) Show a table of contents on the right side of the page. It's useful for navigating between headings. ### 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. ================================================ 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 ### Logo The logo of the website rendered on the navbar.
<>![Customized Logo](/assets/docs/logo.png) {/* prettier-ignore */}
[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-yrlccm?file=theme.config.jsx)
```jsx filename="app/layout.jsx" My Cool Project } /> ``` ### 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: ![Project link](/assets/docs/project-link.png) ```jsx filename="app/layout.jsx" } /> ``` ### 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" } /> ``` ### 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. ================================================ 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 ## Example ```jsx filename="app/not-found.jsx" import { NotFoundPage } from 'nextra-theme-docs' export default function NotFound() { return (

The page is not found

) } ``` ================================================ 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 ================================================ 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' ================================================ 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 ### 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. ```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 = Nextra 4.0 is released 🎉 const navbar = ( Nextra} // ... Your additional navbar options /> ) const footer =
MIT {new Date().getFullYear()} © Nextra.
export default async function RootLayout({ children }) { return ( {/* Your additional tags should be passed as `children` of `` element */} {children} ) } ```
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 } # `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 ### 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: you should get the following structure: > [!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 `` 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). ================================================ 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 (
{children}
) } # `_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:
<>![Example of Nextra Theme Docs](/assets/routing@1x.png) {/* prettier-ignore */}
Example: [Nextra Docs Theme](/docs/docs-theme) has sidebar and navbar generated automatically from Markdown files.
{/* 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):**
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):**
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: > [!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 **/ 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: 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: ( Contact Us ), 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 {children} } ``` ### Pages In `_meta` file you can define how the pages are shown in the sidebar, e.g. for the following file structure: ```js filename="_meta.js" copy=false export default { index: 'My Homepage', contact: 'Contact Us', about: 'About Us' } ``` > [!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: ```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' } } ``` And it will look like this:
> [!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. ##### 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 `
  • ` and ``. 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:
    ```js filename="_meta.js" {4} export default { about: { theme: { typesetting: 'article' } } } ```
    [Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-hg77h3?file=pages%2F_meta.js,pages%2Findex.mdx)
    ### 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.
    The nested `_meta` file contains the meta information for pages in the same folder:
    ```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' } ```
    > [!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. ```mdx filename="content/fruits/index.mdx or app/fruits/page.mdx" copy=false {4} --- title: All Fruits sidebarTitle: 🍒 Fruits asIndexPage: true --- ``` ### 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:
    <>![Navbar menu](/assets/docs/menu.png) {/* prettier-ignore */}
    [Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-2qopvp?file=pages%2F_meta.js)
    ```ts type MenuItemSchema = | TitleSchema | { title: TitleSchema } | (LinkSchema & { type?: 'page' | 'doc' }) | SeparatorSchema type MenuSchema = { type: 'menu' title?: TitleSchema items: Record } ``` ```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:
    ```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' } ```
    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: > [!TIP] > > By default, the `.js`, `.jsx`, or `.tsx` file extensions can be used for > `page`.
    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 ================================================ 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 = ( <> ) export const folders = ( <> ) **Without `src` directory** {folders} {nextConfigPackageJson} **With `src` directory** {folders} {nextConfigPackageJson} ================================================ 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 `` 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 `` component: import { Steps } from 'nextra/components' ### Create a `
    ` component To create a `
    ` component, start by importing `withGitHubAlert` from `nextra/components`. You should then create the `
    ` 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 `
    ` 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 }, MyBlockquoteComponent) ``` ### Provide `
    ` to `useMDXComponents` To make the `
    ` component available, you should integrate it into the `useMDXComponents` function: ```jsx filename="mdx-components.jsx" export function useMDXComponents(components) { return { blockquote: Blockquote, ...components } } ``` ================================================ 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. ## 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`: > [!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). ================================================ 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' Hello ``` ## 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" ![Hello](/demo.png) ``` This loads the `demo.png` file inside the `public` folder, and automatically wraps it with Next.js ``. > [!TIP] > > You can also use `![](../public/demo.png)` 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: ![Nextra](/opengraph-image.jpeg) ## 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 => } } ``` ### 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 `` component: ```mdx import { ImageZoom } from 'nextra/components' ``` When zoom is **enabled globally**, and you want to disable zoom for a specific image, you can simply use the `` component: ```mdx import { Image } from 'nextra/components' ``` ================================================ 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 here 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 ( ) } ================================================ 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 ( ) } **Clicks**: ``` Generates:

    Hello MDX

    **Clicks**:
    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. ================================================ 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 ### 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 ( ) } ``` ### 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> = async ({ children }) => { const pageMap = await getPageMap() return ( {children} ) } export default RootLayout ``` > [!IMPORTANT] > > The chat button will appear on all pages of your documentation site. ## 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. ### 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`: ```json filename="package.json" "scripts": { "postbuild": "pagefind --site .next/server/app --output-path public/_pagefind" } ``` ```json filename="package.json" "scripts": { "postbuild": "pagefind --site .next/server/app --output-path out/_pagefind" } ``` ### 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. ## 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. 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 {stars} } {/* 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() } Nextra has stars on GitHub! Last repository update _{await getUpdatedAt()}_. ` 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 } ================================================ 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 ### 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). ================================================ 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(null!) const tokenRef = useRef(undefined) // Find the corresponding token from the DOM useEffect(() => { tokenRef.current = [ ...ref.current.querySelectorAll('code > span > span') ].find(el => el.textContent === '1') }, []) return ( <>
    {children}
    ) } ================================================ 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 } ``` ```` Result: ```js copy=false {1,4-5} import { useState } from 'react' function Counter() { const [count, setCount] = useState(0) return } ``` ### 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 } ``` ```` ```js copy=false /useState/ import { useState } from 'react' function Counter() { const [count, setCount] = useState(0) return } ``` 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 } ``` ```` Renders: ```js copy=false showLineNumbers import { useState } from 'react' function Counter() { const [count, setCount] = useState(0) return } ``` ### 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: export async function ANSI() { const rawAnsi = `\`\`\`ansi  ✓ src/index.test.ts (1)  Test Files  1 passed (1)  Tests  1 passed (1)  Start at  23:32:41  Duration  11ms  PASS  Waiting for file changes... press h to show help, press q to quit \`\`\`` const rawJs = await compileMdx(`~~~md filename="Markdown" ${rawAnsi} ~~~ Renders: ${rawAnsi} `) return } ## 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' ```js copy=false filename="dynamic-code.js" function hello() { const x = 2 + 3 console.log(1) } ``` 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). ## 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: <>![Documentation theme screenshot](/assets/docs-theme.png) <>![Blog theme screenshot](/assets/blog-theme.png) 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).
    {/* prettier-ignore */} Can I use Nextra with Next.js `pages` router? Nextra 4 only works with the `app` router. Only Nextra 1/2/3 supports the `pages` router.
    Can I use X with Nextra? 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)
    {/* prettier-ignore */} How can I add a live coding component in Nextra? 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.
    ================================================ FILE: docs/app/env.d.ts ================================================ declare module '*.svg?svgr' { import type { FC, SVGProps } from 'react' const ReactComponent: FC> 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 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 = ( 🎉 Nextra 4.0 has been released.{' '} Read blogpost ) const navbar = ( } projectLink="https://github.com/shuding/nextra" /> ) const footer = (
    Powered by

    © {new Date().getFullYear()} The Nextra Project.

    ) const RootLayout: FC> = async ({ children }) => { const pageMap = await getEnhancedPageMap() return ( Sponsored by: {[ { 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 => ( ))} ) }} > {children} ) } 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 { try { const { searchParams } = new URL(req.url) // ?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>![Hero](/hero.png)</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> <>[![React Flow preview](./_logos/react-flow.jpg)](https://reactflow.dev)</> <>[![Svelte Flow preview](./_logos/svelte-flow.jpg)](https://svelteflow.dev)</> <>[![Speakeasy preview](./_logos/speakeasy.png)](https://speakeasy.com/docs)</> <>[![The Graph preview](./_logos/thegraph.jpeg)](https://thegraph.com/docs/en)</> <>[![GraphQL preview](./_logos/graphql.png)](https://graphql.org)</> <>[![GraphQL Hive preview](./_logos/graphql-hive.png)](https://the-guild.dev/graphql/hive)</> <>[![SWR preview](./_logos/swr.png)](https://swr.vercel.app)</> <>[![COBE preview](./_logos/cobe.png)](https://cobe.vercel.app)</> <>[![JavaScript Patterns preview](./_logos/javascript-patterns.jpg)](https://javascriptpatterns.vercel.app)</> <>[![CodeSandbox preview](./_logos/codesandbox.jpg)](https://codesandbox.io/docs/learn/introduction/overview)</> <>[![DocsGPT preview](./_logos/docsgpt.png)](https://docs.docsgpt.co.uk)</> <>[![CloudQuery preview](./_logos/cloudquery.svg)](https://cloudquery.io)</> <>[![Edge Runtime preview](./_logos/edge-runtime.jpeg)](https://edge-runtime.vercel.app)</> <>[![Sound.xyz preview](./_logos/sound.xyz.png)](https://docs.sound.xyz)</> <>[![Panda preview](./_logos/panda.png)](https://panda-css.com)</> <>[![Kuma UI preview](./_logos/kuma-ui.png)](https://kuma-ui.com)</> <>[![Langfuse Open Source LLM Engineering Platform](./_logos/langfuse.png)](https://langfuse.com)</> <>[![The Guild Blog preview](./_logos/the-guild.png)](https://the-guild.dev)</> <>[![GraphQL Yoga preview](./_logos/graphql-yoga.png)](https://the-guild.dev/graphql/yoga-server)</> <>[![GraphQL Envelop preview](./_logos/graphql-envelop.png)](https://the-guild.dev/graphql/envelop)</> <>[![GraphQL Inspector preview](./_logos/graphql-inspector.png)](https://the-guild.dev/graphql/inspector)</> <>[![GraphQL Code Generator preview](./_logos/graphql-codegen.png)](https://the-guild.dev/graphql/codegen)</> <>[![GraphQL Mesh preview](./_logos/graphql-mesh.png)](https://the-guild.dev/graphql/mesh)</> <>[![GraphQL Tools preview](./_logos/graphql-tools.png)](https://the-guild.dev/graphql/tools)</> <>[![GraphQL Modules preview](./_logos/graphql-modules.png)](https://the-guild.dev/graphql/modules)</> <>[![GraphQL ESLint preview](./_logos/graphql-eslint.png)](https://the-guild.dev/graphql/eslint)</> <>[![GraphQL Config preview](./_logos/graphql-config.png)](https://the-guild.dev/graphql/config)</> <>[![GraphQL Scalars preview](./_logos/graphql-scalars.png)](https://the-guild.dev/graphql/scalars)</> <>[![GraphQL Shield preview](./_logos/graphql-shield.png)](https://the-guild.dev/graphql/shield)</> <>[![GraphQL SOFA preview](./_logos/graphql-sofa.png)](https://the-guild.dev/graphql/sofa-api)</> <>[![Apollo Angular preview](./_logos/apollo-angular.png)](https://the-guild.dev/graphql/apollo-angular)</> <>[![GraphQL SSE preview](./_logos/graphql-sse.png)](https://the-guild.dev/graphql/sse)</> <>[![GraphQL WS preview](./_logos/graphql-ws.png)](https://the-guild.dev/graphql/ws)</> <>[![feTS preview](./_logos/fets.png)](https://the-guild.dev/openapi/fets)</> <>[![JavaScript Code Challenges preview](./_logos/jscodechallenges.png)](https://jscodechallenges.vercel.app)</> <>[![React Cosmos preview](./_logos/react-cosmos.png)](https://reactcosmos.org)</> <>[![Typia preview](./_logos/typia.png)](https://typia.io)</> <>[![Nestia preview](./_logos/nestia.png)](https://nestia.io)</> <>[![Safe preview](./_logos/safe-core.png)](https://docs.safe.global)</> <>[![Auth.js preview](./_logos/authjs.png)](https://authjs.dev)</> <>[![imgix preview](./_logos/imgix.png)](https://docs.imgix.com)</> <>[![AnythingLLM preview](./_logos/anythingllm.png)](https://anythingllm.com)</> <>[![Redbrick preview](./_logos/redbrick.jpg)](https://wiki.redbrick.land)</> <>[![Makeform preview](./_logos/makeform.png)](https://www.makeform.ai/help)</> <>[![EmbedPDF preview](./_logos/embedpdf.png)](https://www.embedpdf.com)</> <>[![Reactylon preview](./_logos/reactylon.png)](https://www.reactylon.com/docs)</> </Cards> export default function MdxLayout(props) { return cloneElement(props.children, { components: { img: props => ( <Image {...props} className="[aspect-ratio:12/6.3] object-cover" /> ), a({ children, href }) { const { alt } = children.props return ( <Cards.Card href={href} title={alt.replace(/ preview$/i, '')} target="_blank" rel="noreferrer" arrow className="!no-underline" > {children} </Cards.Card> ) }, p(props) { return ( <p {...props} className="mt-4 mb-16 text-center text-lg text-gray-600 dark:text-gray-400" /> ) } } }) } ================================================ FILE: docs/app/sponsors/page.mdx ================================================ --- description: Support Nextra by exploring its sponsors. Learn how they contribute to the development and success of the Nextra framework --- import { Button, Cards, Image } from 'nextra/components' import { cloneElement } from 'react' # Sponsors <div className="mb-12 text-center"> <Button className="mt-3 inline-block !px-6 hover:!no-underline" variant="outline" href="https://github.com/sponsors/dimaMachina" as="a" target="_blank" rel="noreferrer" > {'Become a Sponsor'} </Button> </div> {/* prettier-ignore */} <Cards num={3}> <>[![Inkeep - AI Agents that get real work done](../showcase/_logos/inkeep.png)](https://inkeep.com)</> <>[![xyflow preview](../showcase/_logos/xyflow.png)](https://xyflow.com)</> </Cards> export default function MdxLayout(props) { return cloneElement(props.children, { components: { img: props => ( <Image {...props} className="[aspect-ratio:12/6.3] object-cover" /> ), a({ children, href }) { const { alt } = children.props return ( <Cards.Card href={`${href}?utm_source=nextra.site&utm_campaign=nextra&utm_content=logolink`} title={alt.replace(/ preview$/i, '')} target="_blank" rel="noreferrer" arrow className="!no-underline" > {children} </Cards.Card> ) } } }) } ================================================ FILE: docs/components/_slider.tsx ================================================ 'use client' import type { ComponentProps, FC } from 'react' import { useCallback, useEffect, useState } from 'react' export const Slider: FC<{ cssVar: string max: number }> = ({ cssVar, max }) => { const handleChange: NonNullable<ComponentProps<'input'>['onChange']> = useCallback( e => { const value = `${e.target.value}${max === 360 ? 'deg' : '%'}` e.target.nextSibling!.textContent = value document.documentElement.style.setProperty(cssVar, value) }, [cssVar, max] ) return ( <div className="flex h-6 items-center gap-2"> <input type="range" className="w-28" onChange={handleChange} step="1" min="0" max={max} /> <label className="w-14 text-sm text-gray-600 dark:text-gray-400" /> </div> ) } function hexToRgb(hex: `#${string}`): string { const bigint = Number.parseInt(hex.slice(1), 16) const r = (bigint >> 16) & 255 const g = (bigint >> 8) & 255 const b = bigint & 255 return `${r},${g},${b}` } export const BackgroundColor: FC = () => { const [value, setValue] = useState('') useEffect(() => { const color = getComputedStyle(document.body).getPropertyValue( '--nextra-bg' ) setValue(color) }, []) return ( <div className="flex h-6 items-center gap-2"> <input type="color" value={value} onChange={e => { const { value } = e.target e.target.nextSibling!.textContent = value document.documentElement.style.setProperty( '--nextra-bg', hexToRgb(value as `#${string}`) ) }} /> <label className="w-20 text-sm text-gray-600 dark:text-gray-400" /> </div> ) } ================================================ FILE: docs/components/_table/index.tsx ================================================ import type { FC } from 'react' import styles from './style.module.css' export const OptionTable: FC<{ options: [string, string, any] }> = ({ options }) => { return ( <div className={ '-mx-6 mt-6 mb-4 overflow-x-auto overscroll-x-contain px-6 pb-4 ' + styles.container } > <table className="w-full border-collapse text-sm"> <thead> <tr className="border-b py-4 text-start dark:border-neutral-700"> <th className="py-2 font-semibold">Option</th> <th className="py-2 pl-6 font-semibold">Type</th> <th className="px-6 py-2 font-semibold">Description</th> </tr> </thead> <tbody className="align-baseline text-gray-900 dark:text-gray-100"> {options.map(([option, type, description]) => ( <tr key={option} className="border-b border-gray-100 dark:border-neutral-700/50" > <td className="py-2 font-mono text-xs leading-6 font-semibold whitespace-pre text-violet-600 dark:text-violet-500"> {option} </td> <td className="py-2 pl-6 font-mono text-xs leading-6 font-semibold whitespace-pre text-slate-500 dark:text-slate-400"> {type} </td> <td className="py-2 pl-6">{description}</td> </tr> ))} </tbody> </table> </div> ) } ================================================ FILE: docs/components/_table/style.module.css ================================================ .container { mask-image: linear-gradient( to right, transparent 0.8em, white 1.5em, white calc(100% - 1.5em), transparent calc(100% - 0.8em) ); } .container::-webkit-scrollbar { appearance: none; } ================================================ FILE: docs/components/content-and-app-file-tree.tsx ================================================ import path from 'node:path' import { FileTree } from 'nextra/components' import type { FC, ReactNode } from 'react' import { Children } from 'react' import { useMDXComponents } from '../mdx-components' // @ts-expect-error -- fixme function mapChildren(children) { return Children.map(children, child => { const { name, ext } = path.parse(child.props.name) if (name === '_meta') { return child } if (ext === '.md' || ext === '.mdx') { const file = <FileTree.File {...child.props} name={`page${ext}`} /> if (name === 'index') { return file } return <FileTree.Folder name={name}>{file}</FileTree.Folder> } if (!ext) { return ( <FileTree.Folder {...child.props}> {mapChildren(child.props.children)} </FileTree.Folder> ) } return child // @ts-expect-error -- fixme }).sort((a, b) => { const aName = a.props.name const bName = b.props.name const isAFolder = a.props.children const isBFolder = b.props.children if (isAFolder && !isBFolder) return -1 if (isBFolder && !isAFolder) return 1 return aName.localeCompare(bName) }) } export const ContentAndAppFileTee: FC<{ children: ReactNode className: string }> = ({ children, className }) => { const { a: Link, code: Code } = useMDXComponents() const layout = <FileTree.File name="layout.jsx" /> return ( <> <FileTree className={className}> <b> Using{' '} <Link href="/docs/file-conventions/content-directory"> <Code>content</Code> directory </Link> </b> <FileTree.Folder name="app" defaultOpen> <FileTree.Folder name="[[...mdxPath]]"> <FileTree.File name="page.jsx" /> </FileTree.Folder> {layout} </FileTree.Folder> <FileTree.Folder name="content" defaultOpen> {children} </FileTree.Folder> </FileTree>{' '} <FileTree className={className}> <b> Using{' '} <Link href="/docs/file-conventions/page-file"> <Code>page.mdx</Code> files </Link> </b> <FileTree.Folder name="app" defaultOpen> {/* @ts-expect-error -- fixme */} {mapChildren([layout, ...children])} </FileTree.Folder> </FileTree> </> ) } ================================================ FILE: docs/components/example-code.tsx ================================================ import fs from 'node:fs/promises' import path from 'node:path' import { compileMdx } from 'nextra/compile' import type { FC } from 'react' import { MDXRemote } from '../../packages/nextra/dist/client/mdx-remote' export const ExampleCode: FC<{ filePath: string metadata: string example: string }> = async ({ filePath, metadata, example }) => { const pageContent = await fs.readFile( `../examples/${example}/${filePath}`, 'utf8' ) const ext = path.extname(filePath).slice(1) const rawJs = await compileMdx( `~~~${ext} filename="${filePath}" showLineNumbers ${metadata} ${pageContent.trim()} ~~~`, { defaultShowCopyCode: true } ) return <MDXRemote compiledSource={rawJs} /> } ================================================ FILE: docs/components/example-tsdoc.mdx ================================================ ```ts type Example = { /** * **Foo** description. * @default "dimaMachina" * @remarks `"not dimaMachina"` */ foo: string } ``` In this example, while the actual type of the property `foo` is `string`, the displayed type will be `"not dimaMachina"` as per the `@remarks` tag. <APIDocs code={` type Example = { /** * **Foo** description. * @default "dimaMachina" * @remarks \`"not dimaMachina"\` */ foo: string } export default Example`} /> ================================================ FILE: docs/components/generate-api-reference.ts ================================================ import { BoxIcon, CardsIcon, OneIcon, WarningIcon } from '@components/icons' import { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file' import { compileMdx } from 'nextra/compile' import { Bleed, Callout, Cards, FileTree, Steps, Table, Tabs } from 'nextra/components' import { evaluate } from 'nextra/evaluate' import type { generateDefinition } from 'nextra/tsdoc' import { BackgroundColor, Slider } from './_slider' import ExampleTSDoc from './example-tsdoc.mdx' import { PlaygroundDemo } from './playground-demo' const { wrapper: _Wrapper, ...components } = getMDXComponents({ Callout, Steps, Bleed, PlaygroundDemo, ExampleTSDoc, Tabs, FileTree, Table, Cards, BoxIcon, CardsIcon, OneIcon, WarningIcon, BackgroundColor, Slider }) export interface ApiReference { name: string isFlattened?: boolean code?: string packageName?: string } interface Options { title: string subtitle: string definition: ReturnType<typeof generateDefinition> bottomMdxContent?: string } export async function generateApiReference( apiRef: ApiReference, { title, subtitle, definition, bottomMdxContent }: Options ) { const { description, tags = {} } = definition const result = [ description && // og:description `export const metadata = { description: ${JSON.stringify(description.split('\n', 1)[0])} }`, // Title `# \`${apiRef.name}\` ${title}`, // Page description description, apiRef.packageName && `Exported from \`${apiRef.packageName}\`.`, // Signature `## ${subtitle}`, '<APIDocs definition={definition} />', // Warnings tags.throws && `> [!WARNING] > > Throws an ${tags.throws.replaceAll('{', '`').replaceAll('}', '`')}`, // Tips tags.see && `<Callout> **See** ${tags.see} </Callout>`, // Examples tags.example && `## Example ${tags.example}`, // Usage tags.usage && `## Usage ${tags.usage}`, bottomMdxContent ].filter(Boolean) const rawJs = await compileMdx(result.join('\n\n')) return evaluate(rawJs, components, { definition }) } ================================================ FILE: docs/components/get-page-map.ts ================================================ import type { MetaJsonFile, PageMapItem } from 'nextra' import { getPageMap } from 'nextra/page-map' import { pageMap as apiPageMap } from '../app/api/[name]/page' import { pageMap as builtInsPageMap } from '../app/docs/built-ins/[name]/page' type PageMapVisitor = (item: PageMapItem) => PageMapItem function visitPageMap( pageMap: PageMapItem, visitor: PageMapVisitor ): PageMapItem function visitPageMap( pageMap: PageMapItem[], visitor: PageMapVisitor ): PageMapItem[] function visitPageMap( pageMap: PageMapItem[] | PageMapItem, visitor: PageMapVisitor ): PageMapItem[] | PageMapItem { if (Array.isArray(pageMap)) { return pageMap.map(item => visitPageMap(item, visitor)) } if ('children' in pageMap) { return visitor({ ...pageMap, children: visitPageMap(pageMap.children, visitor) }) } return visitor(pageMap) } function createMetaItem(pageMap: typeof apiPageMap): MetaJsonFile { return { data: Object.fromEntries( pageMap.map(o => { if ('type' in o && o.type === 'separator') { return [o.name, { type: 'separator', title: o.title }] } return [o.name, ''] }) ) } } export const getEnhancedPageMap: typeof getPageMap = async (...args) => { const rootPageMap = await getPageMap(...args) const modifiedPageMap = visitPageMap(rootPageMap, item => { if ('route' in item) { if (item.route === '/api') { return { ...item, children: [ createMetaItem(apiPageMap), { route: '/api', name: 'index', title: 'Overview' }, ...apiPageMap ] } } if (item.route === '/docs/built-ins') { return { ...item, children: [createMetaItem(builtInsPageMap), ...builtInsPageMap] } } } return item }) return modifiedPageMap } ================================================ FILE: docs/components/icons/index.ts ================================================ export { default as FilesIcon } from './files.svg?svgr' export { default as TailwindIcon } from './tailwind.svg?svgr' export { default as LightningIcon } from './lightning.svg?svgr' export { default as GlobeIcon } from './globe.svg?svgr' export { default as PictureIcon } from './picture.svg?svgr' export { default as CodeIcon } from './code.svg?svgr' export { default as BrushIcon } from './brush.svg?svgr' export { default as DropperIcon } from './dropper.svg?svgr' export { default as StarsIcon } from './stars.svg?svgr' export { default as FormulaIcon } from './formula.svg?svgr' export { default as WarningIcon } from './warning.svg?svgr' export { default as ChevronRightIcon } from './chevron-right.svg?svgr' export { default as BoxIcon } from './box.svg?svgr' export { default as GearIcon } from './gear.svg?svgr' export { default as RowsIcon } from './rows.svg?svgr' export { default as CardsIcon } from './cards.svg?svgr' export { default as OneIcon } from './one.svg?svgr' export { default as CloudIcon } from './cloud.svg?svgr' export { default as TableIcon } from './table.svg?svgr' export { default as FileIcon } from './file.svg?svgr' export { default as NewsletterIcon } from './newsletter.svg?svgr' export { default as ArrowRightIcon } from './arrow-right.svg?svgr' export { default as SwitchIcon } from './switch.svg?svgr' export { default as DiagramIcon } from './diagram.svg?svgr' export { default as FolderTreeIcon } from './folder-tree.svg?svgr' export { default as IdCardIcon } from './id-card.svg?svgr' export { default as VercelLogo } from './vercel.svg?svgr' export { default as NextraLogo } from './nextra.svg?svgr' export { default as TagsIcon } from './tags.svg?svgr' export { default as RSSIcon } from './rss.svg?svgr' ================================================ FILE: docs/components/inkeep-chat-button.tsx ================================================ 'use client' import { InkeepChatButton } from '@inkeep/cxkit-react' import type { FC } from 'react' export const ChatButton: FC = () => { return ( <InkeepChatButton aiChatSettings={{ aiAssistantAvatar: '/icon.svg', aiAssistantName: 'Inkeep' }} baseSettings={{ apiKey: process.env.NEXT_PUBLIC_INKEEP_API_KEY!, primaryBrandColor: '#238aff', colorMode: { sync: { target: 'html', attributes: ['class'], isDarkMode(attrs) { return attrs.class === 'dark' } } }, theme: { styles: [ { key: 'custom-theme', type: 'style', // Fix icon on light theme value: ` [data-theme=light] .ikp-chat-button__avatar-content { filter: invert(1); } ` } ] } }} /> ) } ================================================ FILE: docs/components/install-nextra-theme.mdx ================================================ Add the following scripts to your `package.json`: ```json filename="package.json" "scripts": { "dev": "next", "build": "next build", "start": "next start" }, ``` > [!TIP] > > You can enable Turbopack in development by appending the `--turbopack` flag to > the `dev` command: > > ```diff filename="package.json" > - "dev": "next", > + "dev": "next --turbopack", > ``` You can start the server in development mode with the following command according to your package manager: ```sh npm2yarn npm run dev ``` or in production mode: ```sh npm2yarn npm run build npm run start ``` > [!NOTE] > > If you're not familiar with Next.js, note that development mode is > significantly slower since Next.js compiles every page you navigate to. ### Add Next.js config Create a `next.config.mjs` file in your project's root directory with the following content: ```js filename="next.config.mjs" import nextra from 'nextra' // Set up Nextra with its configuration const withNextra = nextra({ // ... Add Nextra-specific options here }) // Export the final Next.js config with Nextra included export default withNextra({ // ... Add regular Next.js options here }) ``` With this configuration, Nextra will handle Markdown files in your Next.js project. For more Nextra configuration options, check out the [Guide](/docs/guide). ### Add [`mdx-components` file](/docs/file-conventions/mdx-components-file) ### Setup search To set up search, follow the instructions on the [Search Engine](/docs/guide/search#setup) page. ### Create the root layout Next, create the root layout of your application inside the `app` folder. This layout will be used to configure your Nextra Theme: ================================================ FILE: docs/components/playground-demo.tsx ================================================ 'use client' // NOTE: We have intentionally omitted a local mdx-components file because it // includes the server-only `<TSDoc>` component import { useMDXComponents } from 'nextra-theme-docs' import { Code, Mermaid, Playground, Pre, Tabs } from 'nextra/components' import { MdxIcon } from 'nextra/icons' import type { ComponentProps, FC } from 'react' import { useCallback, useEffect, useRef, useState } from 'react' const DEFAULT_MDX = `Playground component lets you write Nextra-compatible MDX that renders only on the client. It's modeled after the functionality found in [MDX Playground](https://mdxjs.com/playground). In some instances where remote loading MDX is not an option, this may work as a great alternative. Here's an example of a code block. \`\`\`ts console.log("Hello world, this is a playground component!"); \`\`\` ## Caveats Due to the purely client-side nature of this component, features "Table of Contents" and "Front matter" will not work. ## Mermaid Example \`\`\`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 \`\`\`` export const PlaygroundDemo: FC = () => { const [rawMdx, setRawMdx] = useState(DEFAULT_MDX) const handleInput: NonNullable<ComponentProps<'span'>['onInput']> = useCallback(e => { setRawMdx(e.currentTarget.textContent) }, []) const spanRef = useRef<HTMLSpanElement>(null!) const initialRender = useRef(false) useEffect(() => { if (!initialRender.current) { initialRender.current = true spanRef.current.textContent = rawMdx } }, []) // eslint-disable-line react-hooks/exhaustive-deps -- only on mount return ( <div className="mt-6 grid grid-cols-1 gap-2 lg:grid-cols-2"> <Pre data-filename="MDX" icon={<MdxIcon height="1em" className="shrink-0" />} > <Code> <span ref={spanRef} contentEditable suppressContentEditableWarning className="outline-none" onInput={handleInput} /> </Code> </Pre> <div> <Playground fallback={ <div className="flex h-full items-center justify-center text-4xl"> Loading playground... </div> } source={rawMdx} components={useMDXComponents({ Mermaid, $Tabs: Tabs })} /> </div> </div> ) } ================================================ FILE: docs/components/ready-to-go.mdx ================================================ ### Render MDX files There are two ways to render MDX files using file-based routing, add your MDX files via [`page` files](/docs/file-conventions/page-file) or [`content` directory](/docs/file-conventions/content-directory) convention. ### Run the project Run the `dev` command specified in `package.json` to start developing the project! 🎉 ```sh npm2yarn npm run dev ``` ================================================ FILE: docs/components/shadow.jsx ================================================ 'use client' // https://gist.github.com/janily/04d7fb0861e053d4679b38743ffc05a7 import { Component } from 'react' import { createPortal } from 'react-dom' export class Shadow extends Component { componentDidMount() { if (this.shadowAttached) { return } this.shadowAttached = true this.shadowRoot = this.node.attachShadow({ mode: this.props.mode }) this.forceUpdate() } render() { const { children, ...props } = this.props return ( <div {...props} ref={node => (this.node = node)}> {this.shadowRoot && createPortal(children, this.shadowRoot)} </div> ) } } ================================================ FILE: docs/components/toggle-visibility-section.tsx ================================================ import { compileMdx } from 'nextra/compile' import { MDXRemote } from 'nextra/mdx-remote' import type { FC } from 'react' export const ToggleVisibilitySection: FC<{ element: string property: string }> = async ({ element, property }) => { const rawJs = await compileMdx(`### Toggle Visibility [#toggle-visibility-for-${property}] You can toggle visibility of the ${element} on the specific pages by setting \`theme.${property}\` property in the \`_meta.js\` file: ~~~js filename="_meta.js" export default { 'my-page': { theme: { ${property}: false // Hide ${property} on this page } } } ~~~`) return <MDXRemote compiledSource={rawJs} /> } ================================================ FILE: docs/components/video.tsx ================================================ import type { FC } from 'react' export const Video: FC<{ src: string }> = ({ src }) => { return ( <video muted autoPlay playsInline loop controls className="x:focus-visible:nextra-focus mt-6 rounded-xl border dark:border-zinc-800" > <source src={src} type="video/mp4" /> </video> ) } ================================================ FILE: docs/mdx-components.tsx ================================================ import { getEnhancedPageMap } from '@components/get-page-map' import type { Folder } from 'nextra' import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs' import type { UseMDXComponents } from 'nextra/mdx-components' import { generateDefinition, TSDoc } from 'nextra/tsdoc' import type { ComponentProps } from 'react' type TSDocProps = ComponentProps<typeof TSDoc> type GenerateDefinitionArgs = Parameters<typeof generateDefinition>[0] interface APIDocsProps extends Partial<TSDocProps>, Pick<GenerateDefinitionArgs, 'code' | 'flattened'> { componentName?: string groupKeys?: string packageName?: string } const { img: Image, ...docsComponents } = getDocsMDXComponents({ // @ts-expect-error -- FIXME figure: props => <figure className="mt-[1.25em]" {...props} />, // @ts-expect-error -- FIXME figcaption: props => ( <figcaption className="mt-2 text-center text-sm" {...props} /> ), async APIDocs({ componentName, groupKeys, packageName = 'nextra/components', code: $code, flattened, definition: $definition, ...props }: APIDocsProps) { if (Object.keys(props).length) { throw new Error(`Unexpected props: ${Object.keys(props)}`) } let code: string if (componentName) { const result = groupKeys ? `Omit<MyProps, keyof ${groupKeys}> & { '...props': ${groupKeys} }>` : 'MyProps' code = ` import type { ComponentProps } from 'react' import type { ${componentName.split('.')[0]} } from '${packageName}' type MyProps = ComponentProps<typeof ${componentName}> type $ = ${result} export default $` } else { code = $code } const definition = $definition ?? generateDefinition( // @ts-expect-error -- exist { code, flattened } ) // TODO pass `'/api'` as first argument const pageMap = await getEnhancedPageMap() const apiPageMap = pageMap.find( (o): o is Folder => 'name' in o && o.name === 'api' )!.children return ( <TSDoc definition={definition} typeLinkMap={{ ...Object.fromEntries( apiPageMap .filter(o => 'route' in o && o.name !== 'index') // @ts-expect-error -- fixme .map(o => [o.title, o.route]) ), NextConfig: 'https://nextjs.org/docs/pages/api-reference/config/next-config-js', RehypePrettyCodeOptions: 'https://rehype-pretty.pages.dev/#options', PluggableList: 'https://github.com/unifiedjs/unified#pluggablelist', GitHubIcon: 'https://github.com/shuding/nextra/blob/main/packages/nextra/src/client/icons/github.svg', DiscordIcon: 'https://github.com/shuding/nextra/blob/main/packages/nextra/src/client/icons/discord.svg', PagefindSearchOptions: 'https://github.com/CloudCannon/pagefind/blob/248f81d172316a642a83527fa92180abbb7f9c49/pagefind_web_js/types/index.d.ts#L72-L82', ReactNode: 'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/51fcf2a1c5da6da885c1f8c11224917bbc011493/types/react/index.d.ts#L426-L439', ReactElement: 'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d44fce6cd8765acbdb0256195e5f16f67471430d/types/react/index.d.ts#L315-L322', TabItem: 'https://github.com/shuding/nextra/blob/fb376a635de7fa287d5ffec9dbb5f40f1cfdb0f6/packages/nextra/src/client/components/tabs/index.client.tsx#L21', TabObjectItem: 'https://github.com/shuding/nextra/blob/fb376a635de7fa287d5ffec9dbb5f40f1cfdb0f6/packages/nextra/src/client/components/tabs/index.client.tsx#L23', PageMapItem: 'https://github.com/shuding/nextra/blob/fb376a635de7fa287d5ffec9dbb5f40f1cfdb0f6/packages/nextra/src/types.ts#L66', // ThemeProviderProps: // 'https://github.com/pacocoursey/next-themes/blob/c89d0191ce0f19215d7ddfa9eb28e1e4f94d37e5/next-themes/src/types.ts#L34-L57', LastUpdated: 'https://github.com/shuding/nextra/blob/main/packages/nextra-theme-docs/src/components/last-updated.tsx', MDXRemote: 'https://github.com/shuding/nextra/blob/main/packages/nextra/src/client/mdx-remote.tsx', MDXComponents: 'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/4c3811099cbe9ee60151c11a679b780d0ba785bf/types/mdx/types.d.ts#L65', ComboboxInputProps: 'https://github.com/tailwindlabs/headlessui/blob/0933dd5e5f563675c8a36e4520905bf9b58df00e/packages/%40headlessui-react/src/components/combobox/combobox.tsx#L506' }} /> ) } }) export const useMDXComponents: UseMDXComponents<typeof docsComponents> = <T,>( components?: T ) => ({ ...docsComponents, // @ts-expect-error -- FIXME img: props => ( <Image {...props} className="nextra-border rounded-xl border drop-shadow-sm" /> ), ...components }) ================================================ FILE: docs/next-sitemap.config.js ================================================ /** @type {import('next-sitemap').IConfig} */ export default { siteUrl: 'https://nextra.site', changefreq: 'weekly', priority: '0.5', generateIndexSitemap: false, exclude: ['/icon.svg'] } ================================================ FILE: docs/next.config.ts ================================================ import nextra from 'nextra' // @ts-expect-error -- fixme function isExportNode(node, varName: string) { if (node.type !== 'mdxjsEsm') return false const [n] = node.data.estree.body if (n.type !== 'ExportNamedDeclaration') return false const name = n.declaration?.declarations?.[0].id.name if (!name) return false return name === varName } const DEFAULT_PROPERTY_PROPS = { type: 'Property', kind: 'init', method: false, shorthand: false, computed: false } // @ts-expect-error -- fixme export function createAstObject(obj) { return { type: 'ObjectExpression', properties: Object.entries(obj).map(([key, value]) => ({ ...DEFAULT_PROPERTY_PROPS, key: { type: 'Identifier', name: key }, value: value && typeof value === 'object' ? value : { type: 'Literal', value } })) } } type NextraParams = Parameters<typeof nextra>[0] type MdxOptions = NonNullable<NextraParams['mdxOptions']> type RehypePlugin = NonNullable<MdxOptions['rehypePlugins']>[0] // eslint-disable-next-line unicorn/consistent-function-scoping const rehypeOpenGraphImage: RehypePlugin = () => (ast: any) => { // @ts-expect-error -- fixme const frontMatterNode = ast.children.find(node => isExportNode(node, 'metadata') ) if (!frontMatterNode) { return } const { properties } = frontMatterNode.data.estree.body[0].declaration.declarations[0].init // @ts-expect-error -- fixme const title = properties.find(o => o.key.value === 'title')?.value.value if (!title) { return } const [prop] = createAstObject({ openGraph: createAstObject({ images: `https://nextra.site/og?title=${title}` }) }).properties properties.push(prop) } const withNextra = nextra({ latex: true, defaultShowCopyCode: true, mdxOptions: { rehypePlugins: [ // Provide only on `build` since turbopack on `dev` supports only serializable values process.env.NODE_ENV === 'production' && rehypeOpenGraphImage ].filter(v => !!v) }, whiteListTagsStyling: ['figure', 'figcaption'] }) const nextConfig = withNextra({ reactStrictMode: true, env: { NEXT_PUBLIC_INKEEP_API_KEY: 'dee399c7f7ac40b9de0d0b85ca32959953b9ff7c9fc8d96c' }, redirects: () => [ { source: '/docs/guide/:slug(typescript|latex|tailwind-css|mermaid)', destination: '/docs/advanced/:slug', permanent: true }, { source: '/docs/docs-theme/built-ins/:slug(callout|steps|tabs|bleed)', destination: '/docs/built-ins/:slug', permanent: true }, { source: '/docs/docs-theme/api/use-config', destination: '/docs/docs-theme/api', permanent: true }, { source: '/docs/guide/advanced/:slug', destination: '/docs/advanced/:slug', permanent: true }, { source: '/docs/docs-theme/theme-configuration', destination: '/docs/docs-theme/built-ins/layout', permanent: true }, { source: '/docs/docs-theme/page-configuration', destination: '/docs/file-conventions/meta-file', permanent: true }, { source: '/docs/guide/organize-files', destination: '/docs/file-conventions', permanent: true }, { source: '/docs/advanced/playground', destination: '/docs/built-ins/playground', permanent: true } ], webpack(config) { // rule.exclude doesn't work starting from Next.js 15 const { test: _test, ...imageLoaderOptions } = config.module.rules.find( // @ts-expect-error -- fixme rule => rule.test?.test?.('.svg') ) config.module.rules.push({ test: /\.svg$/, oneOf: [ { resourceQuery: /svgr/, use: ['@svgr/webpack'] }, imageLoaderOptions ] }) return config }, turbopack: { rules: { './components/icons/*.svg': { loaders: ['@svgr/webpack'], as: '*.js' } } }, experimental: { optimizePackageImports: ['@components/icons'] } }) export default nextConfig ================================================ FILE: docs/package.json ================================================ { "name": "docs", "author": "Shu Ding", "license": "MIT", "private": true, "scripts": { "build": "next build --webpack", "dev": "next", "postbuild": "next-sitemap && pagefind --site .next/server/app --output-path public/_pagefind", "start": "next start" }, "dependencies": { "@inkeep/cxkit-react": "^0.5.98", "clsx": "^2.1.0", "framer-motion": "^12.0.0", "next": "^16.0.7", "nextra": "workspace:*", "nextra-theme-docs": "workspace:*", "react": "19.1.0", "react-dom": "19.1.0" }, "devDependencies": { "@svgr/webpack": "^8.0.1", "@tailwindcss/postcss": "4.1.10", "@types/node": "^22.0.0", "@types/react": "^19.1.8", "next-sitemap": "^4.2.3", "pagefind": "^1.3.0", "tailwindcss": "4.1.10" }, "browserslist": [ ">= .25%", "not dead" ] } ================================================ FILE: docs/postcss.config.mjs ================================================ // If you want to use other PostCSS plugins, see the following: // https://tailwindcss.com/docs/using-with-preprocessors /** @type {import('postcss').Postcss} */ export default { plugins: { '@tailwindcss/postcss': {} } } ================================================ FILE: docs/tsconfig.json ================================================ { "compilerOptions": { "baseUrl": ".", "target": "es2022", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "exactOptionalPropertyTypes": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "incremental": true, "esModuleInterop": true, "isolatedModules": true, "moduleResolution": "bundler", "jsx": "react-jsx", "module": "esnext", "resolveJsonModule": true, "paths": { "@components/*": ["components/*"], // These work at runtime due to Next.js internal resolution or custom config, // but we include them here so TypeScript doesn't complain. "private-next-root-dir/*": ["./*"], "next-mdx-import-source-file": ["./mdx-components.tsx"] }, "plugins": [ { "name": "next" } ], "strictNullChecks": true, "noUncheckedIndexedAccess": true }, "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts" ], "exclude": ["node_modules", ".next"] } ================================================ FILE: docs/vercel.json ================================================ { "public": true } ================================================ FILE: examples/blog/app/_meta.global.js ================================================ export default { index: { type: 'page' }, posts: { type: 'page', items: { draft: { display: 'hidden' } } } } ================================================ FILE: examples/blog/app/layout.jsx ================================================ import { Footer, Layout, Navbar, ThemeSwitch } from 'nextra-theme-blog' import { Banner, Head, Search } from 'nextra/components' import { getPageMap } from 'nextra/page-map' import 'nextra-theme-blog/style.css' export const metadata = { title: 'Blog Example' } export default async function RootLayout({ children }) { const banner = ( <Banner storageKey="4.0-release"> 🎉 Nextra 4.0 is released.{' '} <a href="#" style={{ textDecoration: 'underline', textUnderlinePosition: 'from-font' }} > Read more → </a> </Banner> ) return ( <html lang="en" suppressHydrationWarning> <Head backgroundColor={{ dark: '#0f172a', light: '#fefce8' }} /> <body> <Layout banner={banner}> <Navbar pageMap={await getPageMap()}> <Search /> <ThemeSwitch /> </Navbar> {children} <Footer> <abbr title="This site and all its content are licensed under a Creative Commons Attribution-NonCommercial 4.0 International License." style={{ cursor: 'help' }} > CC BY-NC 4.0 </abbr>{' '} {new Date().getFullYear()} © Dimitri POSTOLOV. <a href="/feed.xml" style={{ float: 'right' }}> RSS </a> </Footer> </Layout> </body> </html> ) } ================================================ FILE: examples/blog/app/page.mdx ================================================ --- title: About --- Hey there! ![Mountain](../public/img.jpeg) This Markdown image is automatically converted into a [Next.js Image](https://nextjs.org/docs/api-reference/next/image). ================================================ FILE: examples/blog/app/posts/(with-comments)/aaron-swartz-a-programmable-web/page.mdx ================================================ --- title: Notes on A Programmable Web by Aaron Swartz date: 2016-05-21 description: At the time when I was getting into web development, I had the chance to read one of the most inspiring book about the web, Aaron Swartz's A Programmable Web. And it completely changed my mind. tags: [web development] author: Shu --- At the time when I was getting into web development, I had the chance to read one of the most inspiring book about the web, Aaron Swartz's A Programmable Web. And it completely changed my mind. **Updated in 2017**: [@tommyjtl](https://github.com/tommyjtl), [@zimine](https://github.com/zimine) and I are currently helping translate this post into Simplified Chinese. Any [contributions](https://github.com/tommyjtl/the-programmable-web/tree/translation) are welcomed :) --- > Sure, it sounds a little bit crazy. But it paid off the last time they made > that gamble: we ended up with a little thing called the World Wide Web. Let's > see if they can do it again. — Aaron Read Aaron's original post: [Building Programmable Web Sites by Aaron Swartz, 2009](http://www.cs.rpi.edu/~hendler/ProgrammableWebSwartz2009.html). ## Quotes About WWW 1. "(the Internet) It should be kept open. It should be kept free." – Steve Jobs 2. "The third reason it's very exciting is that Microsoft doesn't own it and I don't think they can. It's the one thing in the industry that Microsoft can probably never own. I think one of the things that's essential is that the government continue to fund the Internet as a public trust, as a public facility and remove any of these ridiculous notions of privatizing it that have been brought up. I don't think they're going to fly, thankfully." – Steve Jobs 3. Jacques Mattheij wrote an article, about the web in 2050, which feels like the *New Speak* in George Orwell's _1984_. ## Quotes from Aaron's Post About API > APIs only let you look at the data in a **particular way**, typically the way > that the hosting site looks at it About API, II (Q: differences between data, protocol, API?) > pass the noun to the verb: /share?v=1234 pass the verb to the noun: > /v/1234?m=share Then he describes the interesting hybrid that the Web adopted, which he terms "Representational State Transfer" or REST. About "standard" vs "design" > And instead of spending time building things, they've convinced people > interested in these ideas that the first thing we need to do is write > standards. (**To engineers, this is absurd from the start -- standards are > things you write after you've got something working, not before!**) Fortunately for us, the Web was designed with this future in mind. The protocols that underpin it are not designed simply to provide pages for human consumption, but also to easily accommodate the menagerie of spiders, bots, and scripts that explore its fertile soil. ...for applications. Then we'll look into what it means for your application to be not just another tool for people and software to use, but **part of the ecology** -- a section of the programmable web. This means exposing your data to be queried and copied and integrated, even without explicit permission, into the larger software ecosystem, while protecting users' freedom. The more likely option is, of course, to break away from the Web altogether, and force people to download special software to use your application. ... If that's a choice you want to make, you probably shouldn't be reading this book. This is one of the secrets of success on the Web: the more you send people away, the more they come back About URL and URI > Moreover, URLs do not just exist as isolated entities URLs shouldn't change (and if they do change, the old ones should redirect to the new ones) so they should only contain information about the page that never changes. This leads to some obvious requirements. First, URLs shouldn't include technical details of the software you used to build your website, since that could change at any moment About TBL > And even then, they're far more limited than the wide-reaching interactivity > that Berners-Lee imagined. Instead, they used the clone created by a team at the University of Illinois Urbana-Champaign (UIUC), which never supported editing because programmer Marc Andreesen was too dumb to figure out how to do page editing with inline pictures, something Tim Berners-Lee's version had no problem with. (related: http://www.aaronsw.com/weblog/mylifewithtim) ## External links 1. [Steve Jobs interview: One-on-one in 1995](http://computerworld.com/article/2498543/it-management/steve-jobs-interview--one-on-one-in-1995.html?page=8) 2. [Solid: Re-decentralizing the web](https://solid.mit.edu) 3. [Aaron's public links & notes tagged with "web" on Pinboard](https://pinboard.in/u:aaronsw/t:web) 4. ["URLs shouldn't include technical details": 天猫首页](https://zhihu.com/question/54777923/answer/141058259) 5. [Semantic Web – W3C](https://w3.org/standards/semanticweb) 6. [Tim Berners-Lee: The next web](https://ted.com/talks/tim_berners_lee_on_the_next_web) 7. [The Web in 2050 · Jacques Mattheij](https://jacquesmattheij.com/the-web-in-2050): "reboot the web" ================================================ FILE: examples/blog/app/posts/(with-comments)/code-blocks/page.mdx ================================================ --- title: Code blocks date: 2022-07-29 description: En example of using code blocks in your blog. tags: [ web development, JavaScript, GraphQL, C++, Java, React, Next.js, The Guild, MacBook Pro ] author: Dimitri POSTOLOV --- ## Test `filename`, line highlighting and empty lines ```js filename="test.js" {1} console.log('hello world') console.log('goodbye world') ``` ## Test `showLineNumbers` and word highlighting ```scala showLineNumbers {2-4} /println/ object Hello { def main(args: Array[String]) = { println("hello, world") } } object Hello { def main(args: Array[String]) = { println("hello, world") } } ``` ## Test highlighting inline code `import React from 'react'{:js}` ## Test without specified language ```text /hello/ hello world ``` ## Test with code block default language ``` const links = [ { href: '/settings', label: 'Settings' }, { href: '/support', label: 'Support' }, { href: '/license', label: 'License' }, ] ``` ## Test link in code Link to [`google`](https://google.com) Link to [GitHub](https://github.com) ================================================ FILE: examples/blog/app/posts/(with-comments)/draft/page.mdx ================================================ --- title: Draft date: 2023-06-28 description: An example of a draft post. tags: [web development] author: Ada Lovelace --- Because this post has `display: 'hidden'` defined in `_meta.global.js`, it won't show up in the [list of posts](/posts) or [list of posts by tag](/tags/web%20development) but can be access directly by its url at [/posts/draft](/posts/draft). ================================================ FILE: examples/blog/app/posts/(with-comments)/layout.jsx ================================================ import { Comments } from 'nextra-theme-blog' export default function CommentsLayout({ children }) { return ( <> {children} <Comments lang="en" appId="a2d11511-7012-4254-9483-cb49c8f4dfe8" /> </> ) } ================================================ FILE: examples/blog/app/posts/(with-comments)/lists/page.mdx ================================================ --- title: Lists date: 2024-07-11 description: Example of ordered/unordered nested lists. tags: [web development] author: Dimitri POSTOLOV --- - **foo** - bar - **baz** - qux - **qwe** 1. he 1. **be** 1. wo 1. **be** da - da - ba ================================================ FILE: examples/blog/app/posts/(with-comments)/nextra-components/page.mdx ================================================ --- title: Nextra Components date: 2023-05-15 description: En example of using the Callout component in your blog. tags: [web development] author: Tristan Dubbeld --- import { Bleed, Callout, Cards, FileTree, Steps, Tabs } from 'nextra/components' import { CopyIcon, GitHubIcon, MenuIcon } from 'nextra/icons' ## `<Callout>` ### Default <Callout>This is a default callout.</Callout> ### Error <Callout type="error">This is an error callout.</Callout> ### Info <Callout type="info">This is an info callout. [^2]</Callout> ### Warning <Callout type="warning">This is a warning callout.</Callout> ### With custom emoji [^1] <Callout emoji="🚀">This is a callout with a custom emoji.</Callout> ## `<Steps>` <Steps> ### Step 1 Content for step 1. ### Step 2 Contents for step 2. </Steps> <Steps> ## Test Run pnpm test <Steps> ### nextra:test ### nextra-theme-docs:test <Steps> #### more #### more more #### more more more </Steps> ### nextra-theme-blog:test </Steps> ## Lint </Steps> ## `<Tabs>` {/* prettier-ignore */} <Tabs items={['pnpm', 'npm', 'yarn']}> <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab> <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab> <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab> </Tabs> ## `<FileTree>` <FileTree> <FileTree.Folder name="pages" defaultOpen> <FileTree.Folder name="fruits" defaultOpen> <FileTree.File name="_meta.js" /> <FileTree.File name="apple.mdx" /> <FileTree.File name="banana.mdx" /> </FileTree.Folder> <FileTree.File name="_meta.js" /> <FileTree.File name="about.mdx" /> <FileTree.File name="contact.mdx" /> <FileTree.File name="index.mdx" /> </FileTree.Folder> </FileTree> <FileTree> <FileTree.Folder name="users-service" defaultOpen> <FileTree.File name="schema.graphql" /> </FileTree.Folder> <FileTree.Folder name="posts-service" defaultOpen> <FileTree.File name="schema.graphql" /> </FileTree.Folder> </FileTree> ## `<Cards>` <Cards num={2}> <Cards.Card arrow title="Documentation theme" href="/docs/docs-theme/start"> <>![Documentation theme](https://nextra.site/assets/docs-theme.png)</> </Cards.Card> <Cards.Card arrow title="Blog theme" href="/docs/blog-theme/start"> <>![Blog theme](https://nextra.site/assets/blog-theme.png)</> </Cards.Card> </Cards> <Cards> <Cards.Card icon={<CopyIcon />} title="Callout" href="/foo" /> <Cards.Card icon={<GitHubIcon />} title="Tabs" href="/bar" /> <Cards.Card icon={<MenuIcon />} title="Steps" href="/baz" /> </Cards> ## `<details>` and `<summary>` <details> <summary>Summary</summary> Details <details> <summary>Summary 2</summary> Details 2 </details> </details> ## `<Bleed>` <Bleed>![Mountain](/img.jpeg)</Bleed> ## GitHub Alert Syntax > [!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. [^1]: With custom emoji [^2]: This is an info callout. ================================================ FILE: examples/blog/app/posts/(with-comments)/table/page.mdx ================================================ --- title: Table date: 2022-08-28 description: En example of using table. tags: [web development] author: Dimitri POSTOLOV --- ## Test table | Left | Center | Right | Right | Right | Right | Right | Right | Right | Right | | ---- | :----: | ----: | ----: | ----: | ----: | ----: | ----: | ----: | ----: | | ss2 | 333 | 3232 | 3232 | 3232 | 3232 | 3232 | 3232 | 3232 | 3232 | | | 222 | 3232 | 3232 | 3232 | 3232 | 3232 | 3232 | 3232 | 3232 | | | 23 | | | | | | | | | ================================================ FILE: examples/blog/app/posts/get-posts.js ================================================ import { normalizePages } from 'nextra/normalize-pages' import { getPageMap } from 'nextra/page-map' export async function getPosts() { const { directories } = normalizePages({ list: await getPageMap('/posts'), route: '/posts' }) return directories .filter(post => post.name !== 'index') .sort((a, b) => new Date(b.frontMatter.date) - new Date(a.frontMatter.date)) } export async function getTags() { const posts = await getPosts() const tags = posts.flatMap(post => post.frontMatter.tags) return tags } ================================================ FILE: examples/blog/app/posts/page.jsx ================================================ import Link from 'next/link' import { PostCard } from 'nextra-theme-blog' import { getPosts, getTags } from './get-posts' export const metadata = { title: 'Posts' } export default async function PostsPage() { const tags = await getTags() const posts = await getPosts() const allTags = Object.create(null) for (const tag of tags) { allTags[tag] ??= 0 allTags[tag] += 1 } return ( <div data-pagefind-ignore="all"> <h1>{metadata.title}</h1> <div className="not-prose" style={{ display: 'flex', flexWrap: 'wrap', gap: '.5rem' }} > {Object.entries(allTags).map(([tag, count]) => ( <Link key={tag} href={`/tags/${tag}`} className="nextra-tag"> {tag} ({count}) </Link> ))} </div> {posts.map(post => ( <PostCard key={post.route} post={post} /> ))} </div> ) } ================================================ FILE: examples/blog/app/rss.xml/route.js ================================================ import { getPosts } from '../posts/get-posts.js' const CONFIG = { title: 'My Blog', siteUrl: 'https://your-domain.com', description: 'Latest blog posts', lang: 'en-us' } export async function GET() { const allPosts = await getPosts() const posts = allPosts .map( post => ` <item> <title>${post.title} ${post.frontMatter.description} ${CONFIG.siteUrl}${post.route} ${new Date(post.frontMatter.date).toUTCString()} ` ) .join('\n') const xml = ` ${CONFIG.title} ${CONFIG.siteUrl} ${CONFIG.description} ${CONFIG.lang} ${posts} ` return new Response(xml, { headers: { 'Content-Type': 'application/rss+xml' } }) } ================================================ FILE: examples/blog/app/tags/[tag]/page.jsx ================================================ import { PostCard } from 'nextra-theme-blog' import { getPosts, getTags } from '../../posts/get-posts' export async function generateMetadata(props) { const params = await props.params return { title: `Posts Tagged with “${decodeURIComponent(params.tag)}”` } } export async function generateStaticParams() { const allTags = await getTags() return [...new Set(allTags)].map(tag => ({ tag })) } export default async function TagPage(props) { const params = await props.params const { title } = await generateMetadata({ params }) const posts = await getPosts() return ( <>

    {title}

    {posts .filter(post => post.frontMatter.tags.includes(decodeURIComponent(params.tag)) ) .map(post => ( ))} ) } ================================================ FILE: examples/blog/mdx-components.jsx ================================================ import { useMDXComponents as getBlogMDXComponents } from 'nextra-theme-blog' const blogComponents = getBlogMDXComponents({ h1: ({ children }) => (

    {children}

    ), DateFormatter: ({ date }) => `Last updated at ${date.toLocaleDateString('en', { day: 'numeric', month: 'long', year: 'numeric' })}` }) export function useMDXComponents(components) { return { ...blogComponents, ...components } } ================================================ FILE: examples/blog/next.config.js ================================================ import nextra from 'nextra' const withNextra = nextra({ defaultShowCopyCode: true, readingTime: true }) export default withNextra({ reactStrictMode: true, cleanDistDir: true }) ================================================ FILE: examples/blog/package.json ================================================ { "name": "example-blog", "type": "module", "license": "MIT", "private": true, "scripts": { "build": "next build", "dev": "next", "postbuild": "pagefind --site .next/server/app --output-path public/_pagefind", "start": "next start" }, "dependencies": { "next": "^16.0.7", "nextra": "workspace:*", "nextra-theme-blog": "workspace:*", "react": "19.1.0", "react-dom": "19.1.0" }, "devDependencies": { "pagefind": "^1.3.0" } } ================================================ FILE: examples/custom-theme/app/_components/footer.tsx ================================================ import type { FC } from 'react' export const Footer: FC = () => { return (
    Powered by Nextra {new Date().getFullYear()}
    ) } ================================================ FILE: examples/custom-theme/app/_components/navbar.tsx ================================================ 'use client' import { usePathname } from 'next/navigation' import type { PageMapItem } from 'nextra' import { Anchor } from 'nextra/components' import { normalizePages } from 'nextra/normalize-pages' import type { FC } from 'react' export const Navbar: FC<{ pageMap: PageMapItem[] }> = ({ pageMap }) => { const pathname = usePathname() const { topLevelNavbarItems } = normalizePages({ list: pageMap, route: pathname }) return (
      {topLevelNavbarItems.map(item => { const route = item.route || ('href' in item ? item.href! : '') return (
    • {item.title}
    • ) })}
    ) } ================================================ FILE: examples/custom-theme/app/_components/nextra-theme.tsx ================================================ import type { PageMapItem } from 'nextra' import { version } from 'nextra/package.json' import type { FC, ReactNode } from 'react' import { Footer } from './footer' import { Navbar } from './navbar' import { Sidebar } from './sidebar' export const NextraTheme: FC<{ children: ReactNode pageMap: PageMapItem[] }> = ({ children, pageMap }) => { return ( <>

    Custom theme demo for Nextra {version}

    {children}
  • `, `
    ` exports (since they should be always used with `` component) ```diff - import { Table, Th, Tr, Td } from 'nextra/components' + import { Table } from 'nextra/components' // ... - + - ` and `
    + -
    + ``` - 283320f: make `compileMdx` from `nextra/compile` return a `string` instead of an `object` - 283320f: remove `BlogMetadata.draft`, support \_meta files for `nextra-theme-blog` - 283320f: remove `export const title` from generated mdx pages - 283320f: The initial version which supports App Router instead of Pages Router, something may be broken, check https://github.com/shuding/nextra/tree/v4-v2/examples for the migration guide - 283320f: migrate search from Flexsearch to Pagefind - 283320f: - add root `_meta.global.{js,jsx,ts,tsx}` file > See > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts) > based on https://nextra.site website - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2 `lang?: string, route?: string = '/'` - remove `createCatchAllMeta` from `nextra/catch-all` - remove `collectCatchAllRoutes` - remove `normalizePageRoute` - add `mergeMetaWithPageMap` to `nextra/page-map` - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime` in remark plugin - refactor recma rewrite plugin and add tests - remove `recmaRewriteJsx` - remove `recmaRewriteFunctionBody` - make `convertPageMapToJs` sync - 283320f: improve performance on projects without Turbopack enabled - 283320f: release Nextra rc.0 - 283320f: - migrate to tailwind css v4.beta2 - refactor builtin CSS classes from `_` prefix to `x:` prefix - remove `color-primary-750` theme color variant - 283320f: replace `export const useTOC = () = [/* your headings */]` by `export const toc = [/* your headings */]` - 283320f: move `` component in `nextra/components` - 283320f: remove `nextra-theme-blog/cusdis` export, export `` component from `nextra-theme-blog` directly (because `peerDependency` of `react-cusdis` was removed) - 283320f: require Next.js minimum v14 - 283320f: - add `nextra/components` to `experimental.optimizePackageImports` to optimize `nextra/components` by default - remove `` from `nextra/components` - rename `` to `MDXRemote` and move to `nextra/mdx-remote` ### Minor Changes - 283320f: add `nextThemes` prop in `` component - 283320f: - use ReactIcon for code blocks with `jsx`, `tsx` language - add JsonIcon for `json` language - parse language from filename if exist when `diff` language is specified - use JavaScript icon for `cjs` and `mjs` - use TypeScript icon for `cts` and `mts` - 283320f: use `next-view-transitions` for transition in `nextra-theme-blog` - 283320f: replace `useContentDir` with `contentDirBasePath` option which configure `content` directory under a catch-all subdirectory - 283320f: move TOC logic from `recma-rewrite-jsx` plugin to `rehype-extract-toc-content` plugin - 283320f: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and also `content` folder files - all add to `pageMap`, but ignore dynamic pages `[[` - e11dbe0: set `content` value for `` based on background value for light and dark themes ### Patch Changes - 283320f: search tweaks - fdd2c6a: fix steps background on dark mode fix headings anchor link color on dark mode - 283320f: setup `@typescript-eslint/no-unnecessary-condition` rule and fix warnings - aca79fa: Don't focus search input on `Ctrl + k` on non Mac devices. Don't focus search input on `⌘ + Shift + k` or `Ctrl + Shift + k`. - 283320f: add helpful error message about not available search on development mode - 283320f: remove `react-cusdis` dependency, use https://cusdis.com/doc#/advanced/sdk directly - 283320f: add `getPageMap` helper function to `nextra/page-map` - 283320f: Fixes when Turbopack is enabled: `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'` - 283320f: add `whiteListTagsStyling` nextra config option - 283320f: fix unable to select text and `::selection` style - 283320f: - allow override/add additional icons for code blocks - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of `mdx-components` file - 283320f: - Use Tailwind CSS CLI because CSS processing by `tsup` produce different, weird and broken result - Patch react-compiler with some fixes which isn't fixed - 283320f: use `Date.now()` for last edit time on development and git last commit time on production - 283320f: move `pagefind` output to `public/_pagefind` directory https://github.com/shuding/nextra/pull/3517 - 283320f: initialize `transformerTwoslash` only 1 time outside of loader - 283320f: fix edit on github and last updated at for catch all routes - 283320f: simplify `generatePageMap` - 283320f: add `banner` prop for `` component - 283320f: sync with nextra 3.1.0 - 283320f: Cache the result of `repository.getFileLatestModifiedDateAsync` because it can slow down Fast Refresh for uncommitted files. - 283320f: reduce bundle size of bundled website by compiling svg icons in separated files - 283320f: enable page reload of catch-all routes `app/[[...slug]].jsx` on content change - 283320f: remove false positive warnings on projects without `content/` directory ``` ⚠ Compiled with warnings ../packages/nextra/dist/client/pages.js Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client' ``` - 283320f: - sync with nextra 3.0.15 - bump to Next 15 - remove importing of `style.css` in themes, you need to import now manually by ```js import 'nextra-theme-docs/style.css' // for docs theme import 'nextra-theme-blog/style.css' // for blog theme ``` - 283320f: add support for turbopack `next dev --turbopack` - 283320f: fix `colorSchema` for HEX format with 4 chars, e.g. `#111` - 283320f: fix external svg icon was added for span in `` - 283320f: make nextThemes optional prop, to avoid ts errors - 283320f: sync with nextra 3.0.10 - 283320f: defer pagefind results update for prioritizing the user input state - 283320f: make Nextra works with `src/app` and `src/content` directories - 283320f: - fix missing tailwind class for `json` icon in code blocks - capitalize folders in sidebar even without index pages - sync with nextra 3.2.4 - 283320f: add ↗ char for external links - 283320f: sync with nextra 3.0.3 - 283320f: fix injecting mdx-components into headings and injecting into toc - 283320f: - add `disabled` prop for `` component when `open` prop was set (to disable click event and remove `cursor: pointer`) - allow `
    ` and `
    ` tags be used with `` - fix Webpack module rebuild for pageMap when new files where added or removed in `app` dir or `content` dir - 283320f: Use `primaryColor` for `::selection` styles - 283320f: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean` - 283320f: support `GitHub Alert Syntax` - 283320f: fix search, didn't work with Next.js' `basePath` set - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [fdd2c6a] - Updated dependencies [283320f] - Updated dependencies [aca79fa] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [e11dbe0] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - Updated dependencies [283320f] - nextra@4.0.0 ## 4.0.0-rc.0 ### Major Changes - 28796b4: release Nextra rc.0 ### Patch Changes - Updated dependencies [28796b4] - nextra@4.0.0-rc.0 ## 4.0.0-app-router.43 ### Patch Changes - 50c2f76: fix `colorSchema` for HEX format with 4 chars, e.g. `#111` - 50c2f76: make nextThemes optional prop, to avoid ts errors - Updated dependencies [50c2f76] - Updated dependencies [50c2f76] - nextra@4.0.0-app-router.43 ## 4.0.0-app-router.42 ### Patch Changes - 242e0d0: search tweaks - 3fc12a0: - Use Tailwind CSS CLI because CSS processing by `tsup` produce different, weird and broken result - Patch react-compiler with some fixes which isn't fixed - Updated dependencies [242e0d0] - Updated dependencies [3fc12a0] - nextra@4.0.0-app-router.42 ## 4.0.0-app-router.41 ### Patch Changes - nextra@4.0.0-app-router.41 ## 4.0.0-app-router.40 ### Patch Changes - Updated dependencies [88135ec] - nextra@4.0.0-app-router.40 ## 4.0.0-app-router.39 ### Patch Changes - Updated dependencies [711dbe7] - nextra@4.0.0-app-router.39 ## 4.0.0-app-router.38 ### Patch Changes - Updated dependencies [42eb445] - nextra@4.0.0-app-router.38 ## 4.0.0-app-router.37 ### Patch Changes - Updated dependencies [ad80ee1] - nextra@4.0.0-app-router.37 ## 4.0.0-app-router.36 ### Patch Changes - Updated dependencies [739e9eb] - Updated dependencies [d805f2a] - Updated dependencies [0ab4ff1] - nextra@4.0.0-app-router.36 ## 4.0.0-app-router.35 ### Patch Changes - Updated dependencies [96fb083] - nextra@4.0.0-app-router.35 ## 4.0.0-app-router.34 ### Patch Changes - nextra@4.0.0-app-router.34 ## 4.0.0-app-router.33 ### Patch Changes - Updated dependencies [dd2e216] - nextra@4.0.0-app-router.33 ## 4.0.0-app-router.32 ### Patch Changes - fbeef15: setup `@typescript-eslint/no-unnecessary-condition` rule and fix warnings - Updated dependencies [fbeef15] - nextra@4.0.0-app-router.32 ## 4.0.0-app-router.31 ### Patch Changes - Updated dependencies [386b620] - nextra@4.0.0-app-router.31 ## 4.0.0-app-router.30 ### Major Changes - 39bacdc: remove `BlogMetadata.draft`, support \_meta files for `nextra-theme-blog` ### Patch Changes - f277a7a: fix search, didn't work with Next.js' `basePath` set - Updated dependencies [f277a7a] - nextra@4.0.0-app-router.30 ## 4.0.0-app-router.29 ### Major Changes - 4bdf82d: - migrate to tailwind css v4.beta2 - refactor builtin CSS classes from `_` prefix to `x:` prefix - remove `color-primary-750` theme color variant ### Patch Changes - Updated dependencies [4bdf82d] - nextra@4.0.0-app-router.29 ## 4.0.0-app-router.28 ### Patch Changes - 846552e: - fix missing tailwind class for `json` icon in code blocks - capitalize folders in sidebar even without index pages - sync with nextra 3.2.4 - Updated dependencies [846552e] - nextra@4.0.0-app-router.28 ## 4.0.0-app-router.27 ### Major Changes - 8a0ae0f: - add root `_meta.global.{js,jsx,ts,tsx}` file > See > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts) > based on https://nextra.site website - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2 `lang?: string, route?: string = '/'` - remove `createCatchAllMeta` from `nextra/catch-all` - remove `collectCatchAllRoutes` - remove `normalizePageRoute` - add `mergeMetaWithPageMap` to `nextra/page-map` - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime` in remark plugin - refactor recma rewrite plugin and add tests - remove `recmaRewriteJsx` - remove `recmaRewriteFunctionBody` - make `convertPageMapToJs` sync ### Patch Changes - 5e06f57: fix injecting mdx-components into headings and injecting into toc - Updated dependencies [8a0ae0f] - Updated dependencies [5e06f57] - nextra@4.0.0-app-router.27 ## 4.0.0-app-router.26 ### Minor Changes - 0076bad: move TOC logic from `recma-rewrite-jsx` plugin to `rehype-extract-toc-content` plugin ### Patch Changes - be82724: Fixes when Turbopack is enabled: `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'` - Updated dependencies [be82724] - Updated dependencies [0076bad] - nextra@4.0.0-app-router.26 ## 4.0.0-app-router.25 ### Major Changes - c095f98: make `compileMdx` from `nextra/compile` return a `string` instead of an `object` - 79bbab7: remove `export const title` from generated mdx pages - 33ee518: replace `export const useTOC = () = [/* your headings */]` by `export const toc = [/* your headings */]` ### Patch Changes - 3edc6d7: use `Date.now()` for last edit time on development and git last commit time on production - fdbae45: initialize `transformerTwoslash` only 1 time outside of loader - Updated dependencies [c095f98] - Updated dependencies [79bbab7] - Updated dependencies [3edc6d7] - Updated dependencies [fdbae45] - Updated dependencies [33ee518] - nextra@4.0.0-app-router.25 ## 4.0.0-app-router.24 ### Patch Changes - e46dbdf: Cache the result of `repository.getFileLatestModifiedDateAsync` because it can slow down Fast Refresh for uncommitted files. - Updated dependencies [e46dbdf] - nextra@4.0.0-app-router.24 ## 4.0.0-app-router.23 ### Patch Changes - b2e44d3: make Nextra works with `src/app` and `src/content` directories - Updated dependencies [b2e44d3] - nextra@4.0.0-app-router.23 ## 4.0.0-app-router.22 ### Patch Changes - 5f79b77: fix unable to select text and `::selection` style - 57fde3f: reduce bundle size of bundled website by compiling svg icons in separated files - Updated dependencies [5f79b77] - Updated dependencies [57fde3f] - nextra@4.0.0-app-router.22 ## 4.0.0-app-router.21 ### Major Changes - 730899e: - add `nextra/components` to `experimental.optimizePackageImports` to optimize `nextra/components` by default - remove `` from `nextra/components` - rename `` to `MDXRemote` and move to `nextra/mdx-remote` ### Patch Changes - 0d74f68: fix external svg icon was added for span in `` - Updated dependencies [4e02ef3] - Updated dependencies [0d74f68] - Updated dependencies [730899e] - nextra@4.0.0-app-router.21 ## 4.0.0-app-router.20 ### Major Changes - 16816f2: remove `
    `, `
    ` exports (since they should be always used with `` component) ```diff - import { Table, Th, Tr, Td } from 'nextra/components' + import { Table } from 'nextra/components' // ... - + -
    + -
    + ``` - 0a63ba3: improve performance on projects without Turbopack enabled ### Patch Changes - 7cc8ca1: simplify `generatePageMap` - 16816f2: remove false positive warnings on projects without `content/` directory ``` ⚠ Compiled with warnings ../packages/nextra/dist/client/pages.js Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client' ``` - Updated dependencies [3d8705c] - Updated dependencies [16816f2] - Updated dependencies [27454c4] - Updated dependencies [7cc8ca1] - Updated dependencies [aa94d91] - Updated dependencies [0a63ba3] - Updated dependencies [71a051b] - Updated dependencies [0a63ba3] - Updated dependencies [16816f2] - Updated dependencies [b873702] - nextra@4.0.0-app-router.20 ## 4.0.0-app-router.19 ### Patch Changes - Updated dependencies [a3627e5] - nextra@4.0.0-app-router.19 ## 4.0.0-app-router.18 ### Minor Changes - 439466a: replace `useContentDir` with `contentDirBasePath` option which configure `content` directory under a catch-all subdirectory - b00a560: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and also `content` folder files - all add to `pageMap`, but ignore dynamic pages `[[` ### Patch Changes - a074a99: add `whiteListTagsStyling` nextra config option - Updated dependencies [a074a99] - Updated dependencies [439466a] - Updated dependencies [b00a560] - nextra@4.0.0-app-router.18 ## 4.0.0-app-router.17 ### Patch Changes - Updated dependencies [33568c1] - nextra@4.0.0-app-router.17 ## 4.0.0-app-router.16 ### Major Changes - 5385fd4: remove `nextra-theme-blog/cusdis` export, export `` component from `nextra-theme-blog` directly (because `peerDependency` of `react-cusdis` was removed) ### Minor Changes - ab21db7: - use ReactIcon for code blocks with `jsx`, `tsx` language - add JsonIcon for `json` language - parse language from filename if exist when `diff` language is specified - use JavaScript icon for `cjs` and `mjs` - use TypeScript icon for `cts` and `mts` ### Patch Changes - 0540e6c: - add `disabled` prop for `` component when `open` prop was set (to disable click event and remove `cursor: pointer`) - allow `
    ` and `
    ` tags be used with `` - fix Webpack module rebuild for pageMap when new files where added or removed in `app` dir or `content` dir - Updated dependencies [ab21db7] - Updated dependencies [0540e6c] - Updated dependencies [5b47509] - nextra@4.0.0-app-router.16 ## 4.0.0-app-router.15 ### Patch Changes - nextra@4.0.0-app-router.15 ## 4.0.0-app-router.14 ### Major Changes - be19dd4: remove `"typesVersions"` field from `package.json`. You need to set `"moduleResolution": "bundler"` in your `tsconfig.json` if you are using TypeScript ### Patch Changes - Updated dependencies [be19dd4] - nextra@4.0.0-app-router.14 ## 4.0.0-app-router.13 ### Major Changes - 54657e2: require Next.js minimum v15 ### Patch Changes - 07213e2: add `banner` prop for `` component - 07213e2: add support for turbopack `next dev --turbopack` - Updated dependencies [3ade013] - Updated dependencies [ddc39cc] - Updated dependencies [07213e2] - Updated dependencies [54657e2] - nextra@4.0.0-app-router.13 ## 4.0.0-app-router.12 ### Patch Changes - b8defc9: sync with nextra 3.1.0 - Updated dependencies [b8defc9] - Updated dependencies [b8defc9] - nextra@4.0.0-app-router.12 ## 4.0.0-app-router.11 ### Patch Changes - be15165: move `pagefind` output to `public/_pagefind` directory https://github.com/shuding/nextra/pull/3517 - Updated dependencies [be15165] - nextra@4.0.0-app-router.11 ## 4.0.0-app-router.10 ### Patch Changes - 8b1a7c9: defer pagefind results update for prioritizing the user input state - Updated dependencies [8b1a7c9] - nextra@4.0.0-app-router.10 ## 4.0.0-app-router.9 ### Patch Changes - 2c8a8ab: - sync with nextra 3.0.15 - bump to Next 15 - remove importing of `style.css` in themes, you need to import now manually by ```js import 'nextra-theme-docs/style.css' // for docs theme import 'nextra-theme-blog/style.css' // for blog theme ``` - Updated dependencies [2c8a8ab] - nextra@4.0.0-app-router.9 ## 4.0.0-app-router.8 ### Patch Changes - 875842b: remove `react-cusdis` dependency, use https://cusdis.com/doc#/advanced/sdk directly - 9832af9: add ↗ char for external links - ec39959: Use `primaryColor` for `::selection` styles - 875842b: support `GitHub Alert Syntax` - Updated dependencies [9832af9] - Updated dependencies [ec39959] - Updated dependencies [875842b] - nextra@4.0.0-app-router.8 ## 4.0.0-app-router.7 ### Patch Changes - 5201e5f: add helpful error message about not available search on development mode - 3ac2c32: add `getPageMap` helper function from `nextra/page-map` - b4ca36d: - allow override/add additional icons for code blocks - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of `mdx-components` file - 4768dee: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean` - Updated dependencies [5201e5f] - Updated dependencies [3ac2c32] - Updated dependencies [b4ca36d] - Updated dependencies [4768dee] - nextra@4.0.0-app-router.7 ## 4.0.0-app-router.6 ### Patch Changes - 2092d5e: enable page reload of catch-all routes `app/[[...slug]].jsx` on content change - a97e5cf: sync with nextra 3.0.10 - Updated dependencies [2092d5e] - Updated dependencies [a97e5cf] - nextra@4.0.0-app-router.6 ## 4.0.0-app-router.5 ### Patch Changes - a15a02d: sync with nextra 3.0.3 - Updated dependencies [659b36e] - Updated dependencies [a15a02d] - nextra@4.0.0-app-router.5 ## 4.0.0-app-router.4 ### Patch Changes - nextra@4.0.0-app-router.4 ## 4.0.0-app-router.3 ### Major Changes - 1e77fab: move ``, `
    `, ``, ``, `SkipNavLink`, `` - 4f0f6b2: Omit `...{:type}` inline code annotations from search index #2922 - 150184b: attach heading anchor `id` attribute to heading (like Pagefind do) and fix heading anchor styles when `theme.typesetting: 'article'` is set - 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to improve type inference. - 9f55bd1: update rehype-pretty-code/shikiji to latest - a90b90f: Switch to the dark theme provided by `@tailwindcss/typography` in theme-blog. - 49a9627: fix theme-blog heading styles in post layout - 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts` - 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `` and svg icons in `` and `` - 237c345: Make React 18 as minimal requirement - a95e745: Fix the line highlighting background-color does not extend to the full width of the code block when a scrollbar appears with line numbers. - Updated dependencies [e7e8e84] - Updated dependencies [7188278] - Updated dependencies [d1e3e9a] - Updated dependencies [73239c4] - Updated dependencies [2b9b95b] - Updated dependencies [023d37b] - Updated dependencies [0fe55db] - Updated dependencies [50a52fd] - Updated dependencies [c2ad837] - Updated dependencies [2a3e3e7] - Updated dependencies [a3b67ae] - Updated dependencies [1a36469] - Updated dependencies [799174f] - Updated dependencies [98f439c] - Updated dependencies [6ec3241] - Updated dependencies [148278c] - Updated dependencies [c7f03e5] - Updated dependencies [3644e1c] - Updated dependencies [919fe97] - Updated dependencies [cb24790] - Updated dependencies [47b125d] - Updated dependencies [982862f] - Updated dependencies [a8c2196] - Updated dependencies [ba30c6c] - Updated dependencies [0b5cc9d] - Updated dependencies [5a63701] - Updated dependencies [60ec68c] - Updated dependencies [d7d8a3e] - Updated dependencies [fe5061b] - Updated dependencies [2872606] - Updated dependencies [a52a869] - Updated dependencies [6ec3241] - Updated dependencies [1a634cd] - Updated dependencies [63ca28b] - Updated dependencies [ad108ff] - Updated dependencies [ad4823d] - Updated dependencies [4f0f6b2] - Updated dependencies [1f3e7cd] - Updated dependencies [ab07609] - Updated dependencies [2f3be33] - Updated dependencies [90c129e] - Updated dependencies [f71e660] - Updated dependencies [150184b] - Updated dependencies [66cce1d] - Updated dependencies [c74ae90] - Updated dependencies [7615b62] - Updated dependencies [6070b02] - Updated dependencies [7bb18e3] - Updated dependencies [b9f88e3] - Updated dependencies [8efbb45] - Updated dependencies [6f4c83a] - Updated dependencies [d8a406b] - Updated dependencies [9f55bd1] - Updated dependencies [4e55c06] - Updated dependencies [128e195] - Updated dependencies [8bce16d] - Updated dependencies [ccaf3d4] - Updated dependencies [3043826] - Updated dependencies [2630461] - Updated dependencies [576cb6f] - Updated dependencies [217f708] - Updated dependencies [57bc0e2] - Updated dependencies [ca51306] - Updated dependencies [f662237] - Updated dependencies [3c6193d] - Updated dependencies [1f3e7cd] - Updated dependencies [198dbcc] - Updated dependencies [363b85f] - Updated dependencies [fef635e] - Updated dependencies [6070b02] - Updated dependencies [237c345] - Updated dependencies [191e6c4] - Updated dependencies [440ff42] - Updated dependencies [7faa096] - Updated dependencies [9099c35] - Updated dependencies [98f439c] - Updated dependencies [a95e745] - Updated dependencies [80e11e0] - Updated dependencies [c7f03e5] - nextra@3.0.0 ## 3.0.0-alpha.42 ### Patch Changes - Updated dependencies [ca51306] - nextra@3.0.0-alpha.42 ## 3.0.0-alpha.41 ### Patch Changes - 237c345: Make React 18 as minimal requirement - Updated dependencies [237c345] - nextra@3.0.0-alpha.41 ## 3.0.0-alpha.40 ### Patch Changes - Updated dependencies [982862f] - nextra@3.0.0-alpha.40 ## 3.0.0-alpha.39 ### Major Changes - ba30c6c: use render props for className with `selected`, `disabled` and `hover` state for `` - 2872606: remove `image` prop from `` component, image will be showed based on truthiness `children` prop now set `icon` as optional prop ### Patch Changes - Updated dependencies [47b125d] - Updated dependencies [ba30c6c] - Updated dependencies [2872606] - nextra@3.0.0-alpha.39 ## 3.0.0-alpha.38 ### Patch Changes - Updated dependencies [ccaf3d4] - nextra@3.0.0-alpha.38 ## 3.0.0-alpha.37 ### Patch Changes - 2a3e3e7: Fix first list item in `` not within permitted parent elements - Updated dependencies [2a3e3e7] - nextra@3.0.0-alpha.37 ## 3.0.0-alpha.36 ### Patch Changes - Updated dependencies [2b9b95b] - nextra@3.0.0-alpha.36 ## 3.0.0-alpha.35 ### Patch Changes - Updated dependencies [f662237] - nextra@3.0.0-alpha.35 ## 3.0.0-alpha.34 ### Patch Changes - 1a634cd: remove explicit `ZodError` assertion - Updated dependencies [1a634cd] - nextra@3.0.0-alpha.34 ## 3.0.0-alpha.33 ### Patch Changes - 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to improve type inference. - Updated dependencies [7bb18e3] - nextra@3.0.0-alpha.33 ## 3.0.0-alpha.32 ### Patch Changes - 73239c4: To ensure consistent horizontal padding, set the default language as plaintext for code blocks. This prevents any loss of formatting for code blocks without a specified language. - 7e57ddb: Avoid skipping the heading level in the posts layout, removes `.post-item` and `.post-item-more` classes - 150184b: attach heading anchor `id` attribute to heading (like Pagefind do) and fix heading anchor styles when `theme.typesetting: 'article'` is set - a90b90f: Switch to the dark theme provided by `@tailwindcss/typography` in theme-blog. - 49a9627: fix theme-blog heading styles in post layout - 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts` - Updated dependencies [73239c4] - Updated dependencies [799174f] - Updated dependencies [150184b] - Updated dependencies [3c6193d] - nextra@3.0.0-alpha.32 ## 3.0.0-alpha.31 ### Patch Changes - Updated dependencies [d1e3e9a] - nextra@3.0.0-alpha.31 ## 3.0.0-alpha.30 ### Patch Changes - Updated dependencies [7615b62] - nextra@3.0.0-alpha.30 ## 3.0.0-alpha.29 ### Patch Changes - Updated dependencies [fef635e] - nextra@3.0.0-alpha.29 ## 3.0.0-alpha.28 ### Patch Changes - a8c2196: use dynamic import for loading `mermaid` - 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `` and svg icons in `` and `` - Updated dependencies [a8c2196] - Updated dependencies [363b85f] - nextra@3.0.0-alpha.28 ## 3.0.0-alpha.27 ### Patch Changes - 4f0f6b27: Omit `...{:type}` inline code annotations from search index #2922 - a95e7454: Fix the line highlighting background-color does not extend to the full width of the code block when a scrollbar appears with line numbers. - Updated dependencies [4f0f6b27] - Updated dependencies [a95e7454] - nextra@3.0.0-alpha.27 ## 3.0.0-alpha.26 ### Patch Changes - nextra@3.0.0-alpha.26 ## 3.0.0-alpha.25 ### Patch Changes - nextra@3.0.0-alpha.25 ## 3.0.0-alpha.24 ### Patch Changes - Updated dependencies [6f4c83a8] - nextra@3.0.0-alpha.24 ## 3.0.0-alpha.23 ### Minor Changes - 6ec3241c: Add Terraform/Move icon https://github.com/shuding/nextra/pull/2811 https://github.com/shuding/nextra/pull/2808 - 6ec3241c: Make the `` component be crawlable and indexable by search engines by default ### Patch Changes - ad108ff7: use `overflow-x-auto` instead `overflow-x-scroll` for `
    ` - Updated dependencies [6ec3241c] - Updated dependencies [6ec3241c] - Updated dependencies [ad108ff7] - Updated dependencies [217f7082] - nextra@3.0.0-alpha.23 ## 3.0.0-alpha.22 ### Patch Changes - Updated dependencies [2630461c] - nextra@3.0.0-alpha.22 ## 3.0.0-alpha.21 ### Patch Changes - nextra@3.0.0-alpha.21 ## 3.0.0-alpha.20 ### Patch Changes - nextra@3.0.0-alpha.20 ## 3.0.0-alpha.19 ### Patch Changes - nextra@3.0.0-alpha.19 ## 3.0.0-alpha.18 ### Patch Changes - Updated dependencies [98f439ca] - Updated dependencies [f71e660e] - Updated dependencies [98f439ca] - nextra@3.0.0-alpha.18 ## 3.0.0-alpha.17 ### Minor Changes - 30438264: add shikiji twoslash Demo feature: https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support ### Patch Changes - 9f55bd1f: update rehype-pretty-code/shikiji to latest - Updated dependencies [9f55bd1f] - Updated dependencies [30438264] - nextra@3.0.0-alpha.17 ## 3.0.0-alpha.16 ### Minor Changes - 5a637010: add icons for following languages: - GraphQL (`graphql`) - C++ (`c++`, `cpp`) - C# (`csharp`, `c#`, `cs`) - Python (`python`, `py`) allow disallow mobile word wrap button in code blocks with `word-wrap=false` meta data setting ### Patch Changes - Updated dependencies [5a637010] - Updated dependencies [90c129e6] - nextra@3.0.0-alpha.16 ## 3.0.0-alpha.15 ### Patch Changes - Updated dependencies [1a364694] - nextra@3.0.0-alpha.15 ## 3.0.0-alpha.14 ### Patch Changes - nextra@3.0.0-alpha.14 ## 3.0.0-alpha.13 ### Patch Changes - Updated dependencies [60ec68c4] - Updated dependencies [c74ae90a] - Updated dependencies [6070b025] - Updated dependencies [8bce16d3] - Updated dependencies [6070b025] - nextra@3.0.0-alpha.13 ## 3.0.0-alpha.12 ### Patch Changes - Updated dependencies [3644e1c2] - Updated dependencies [57bc0e2a] - nextra@3.0.0-alpha.12 ## 3.0.0-alpha.11 ### Major Changes - c2ad837d: update to MDX3 ### Patch Changes - Updated dependencies [c2ad837d] - nextra@3.0.0-alpha.11 ## 3.0.0-alpha.10 ### Patch Changes - Updated dependencies [9099c354] - nextra@3.0.0-alpha.10 ## 3.0.0-alpha.9 ### Patch Changes - Updated dependencies [8efbb45c] - Updated dependencies [80e11e04] - nextra@3.0.0-alpha.9 ## 3.0.0-alpha.8 ### Minor Changes - 440ff42d: add MathJax support ### Patch Changes - Updated dependencies [440ff42d] - nextra@3.0.0-alpha.8 ## 3.0.0-alpha.7 ### Patch Changes - 0b5cc9d5: make nextra compatible with windows - Updated dependencies [0b5cc9d5] - nextra@3.0.0-alpha.7 ## 3.0.0-alpha.6 ### Patch Changes - Updated dependencies [03da778a] - nextra@3.0.0-alpha.6 ## 3.0.0-alpha.5 ### Patch Changes - Updated dependencies [a3b67aea] - nextra@3.0.0-alpha.5 ## 3.0.0-alpha.4 ### Patch Changes - Updated dependencies [7faa0968] - nextra@3.0.0-alpha.4 ## 3.0.0-alpha.3 ### Patch Changes - Updated dependencies [fe5061b7] - nextra@3.0.0-alpha.3 ## 3.0.0-alpha.2 ### Patch Changes - cb247901: fix broken `export default` statement in mdx files - Updated dependencies [cb247901] - nextra@3.0.0-alpha.2 ## 3.0.0-alpha.1 ### Major Changes - 148278ce: rename tailwind prefix `nx-` to `_` to reduce bundle size - d7d8a3eb: new styles for code blocks aka in next.js - 128e195f: fix React warning, remove PageOpts.toc, use `toc` prop from `components.wrapper` - 191e6c41: - use `shikiji` instead of `shiki` - rename `useSSG` to `useData` - c7f03e54: rename `pageOpts.headings` to `toc` ### Patch Changes - Updated dependencies [e7e8e849] - Updated dependencies [71882780] - Updated dependencies [023d37b1] - Updated dependencies [148278ce] - Updated dependencies [c7f03e54] - Updated dependencies [d7d8a3eb] - Updated dependencies [a52a869e] - Updated dependencies [63ca28be] - Updated dependencies [1f3e7cd4] - Updated dependencies [b9f88e34] - Updated dependencies [4e55c064] - Updated dependencies [128e195f] - Updated dependencies [1f3e7cd4] - Updated dependencies [198dbcca] - Updated dependencies [191e6c41] - Updated dependencies [c7f03e54] - nextra@3.0.0-alpha.1 ## 3.0.0-alpha.0 ### Major Changes - 16ab7f78: - remove `legacyBehavior` from `NextLink` - remove `config.cusdis`. Instead, now you need to pass cusdis options as props in `Cusdis` component - 919fe977: set `"peerDependencies.next": ">=13"` ### Patch Changes - Updated dependencies [0fe55db2] - Updated dependencies [50a52fd1] - Updated dependencies [919fe977] - Updated dependencies [ad4823d9] - Updated dependencies [ab07609c] - Updated dependencies [2f3be336] - Updated dependencies [66cce1d1] - Updated dependencies [d8a406b4] - Updated dependencies [576cb6f1] - nextra@3.0.0-alpha.0 ## 2.13.4 ### Patch Changes - nextra@2.13.4 ## 2.13.3 ### Patch Changes - Updated dependencies [93b57052] - nextra@2.13.3 ## 2.13.2 ### Patch Changes - ad7b31b0: downgrade remark-math from `6` to `5.1.1` to fix `TypeError: Cannot read properties of undefined (reading 'mathFlowInside')` error fix support of ```math lang that was overridden by `rehype-pretty-code` - Updated dependencies [ad7b31b0] - nextra@2.13.2 ## 2.13.1 ### Patch Changes - Updated dependencies [ee02a483] - nextra@2.13.1 ## 2.13.0 ### Patch Changes - nextra@2.13.0 ## 2.12.3 ### Patch Changes - Updated dependencies [ffb6d808] - nextra@2.12.3 ## 2.12.2 ### Patch Changes - Updated dependencies [7c8c4989] - nextra@2.12.2 ## 2.12.1 ### Patch Changes - Updated dependencies [52ae8fc5] - nextra@2.12.1 ## 2.12.0 ### Minor Changes - 8962597e: - allow override static image component that was hardcoded to `import Image from 'next/image'` now it's plain `` - support `
    `/`` for `.md` files ### Patch Changes - Updated dependencies [d9820746] - Updated dependencies [fbf003cd] - Updated dependencies [8962597e] - nextra@2.12.0 ## 2.11.1 ### Patch Changes - cf5f91ea: fix footnotes and backlink jump - 4dd720ad: remove `font-weight: 500;` from styles of code blocks since it gives no effect - Updated dependencies [ddddce95] - Updated dependencies [6154e312] - Updated dependencies [46743ba4] - Updated dependencies [4dd720ad] - nextra@2.11.1 ## 2.11.0 ### Minor Changes - 3bb480a4: support draft posts via frontMatter's `draft: true` value ### Patch Changes - 3bb480a4: use github-slugger for custom heading ids to prevent duplicated headings - 3bb480a4: fix code blocks `box-decoration-theme: clone` can create confusing output over line breaks, use `slice` instead - Updated dependencies [3bb480a4] - Updated dependencies [3bb480a4] - Updated dependencies [3bb480a4] - Updated dependencies [3bb480a4] - nextra@2.11.0 ## 2.10.0 ### Minor Changes - e54b008: - add `@theguild/remark-npm2yarn` package that replaces the code block that has `npm2yarn` metadata with `` and `` components from `nextra/components`. - `` now has `selectedKey` prop, the chosen tab is saved in the local storage, which will be chosen in future page renders. More info https://nextra.site/docs/guide/advanced/npm2yarn ### Patch Changes - Updated dependencies [e54b008] - nextra@2.10.0 ## 2.9.0 ### Minor Changes - 16bbb88: Move below packages to nextra package - `` and `` - `` and `` - `` - `` to import them you can use the following in your official `nextra-theme-blog` and `nextra-theme-docs` ```js import { Card, Cards } from 'nextra/components' ``` ```js import { Tab, Tabs } from 'nextra/components' ``` ```js import { Steps } from 'nextra/components' ``` ```js import { FileTree } from 'nextra/components' ``` ### Patch Changes - b1a7eba: `opens in new tab` span element should have `user-select: none` - Updated dependencies [16bbb88] - Updated dependencies [23a25b1] - nextra@2.9.0 ## 2.8.0 ### Patch Changes - bef7324: accessibility issues for text and navbar in light mode - 6c12bf4: fix broken code format while selecting and copying code with `showLineNumbers` option enabled - Updated dependencies [6c12bf4] - nextra@2.8.0 ## 2.7.1 ### Patch Changes - Updated dependencies [0e53ca51] - nextra@2.7.1 ## 2.7.0 ### Minor Changes - 44626e8f: support mermaid diagrams ### Patch Changes - Updated dependencies [44626e8f] - nextra@2.7.0 ## 2.6.2 ### Patch Changes - 9c9625ee: Fix search not working in certain Next.js versions - Updated dependencies [9c9625ee] - nextra@2.6.2 ## 2.6.1 ### Patch Changes - Updated dependencies [1e9ebabc] - nextra@2.6.1 ## 2.6.0 ### Patch Changes - 9d9bc23: accessibility issues for text and navbar in light mode - Updated dependencies [15c4092] - Updated dependencies [1c6256b] - nextra@2.6.0 ## 2.5.2 ### Patch Changes - f85423a: Fix prose styles for small breakpoints - Updated dependencies [a3601e5] - nextra@2.5.2 ## 2.5.1 ### Patch Changes - 8aae0c9: fix: cusdis comments theme doens't change when resolvedTheme changed - Updated dependencies [d408ab0] - nextra@2.5.1 ## 2.5.0 ### Minor Changes - 08d393e: support ANSI highlighting ### Patch Changes - Updated dependencies [08d393e] - nextra@2.5.0 ## 2.4.2 ### Patch Changes - Updated dependencies [16e562d] - nextra@2.4.2 ## 2.4.1 ### Patch Changes - Updated dependencies [a992ce1] - nextra@2.4.1 ## 2.4.0 ### Patch Changes - Updated dependencies [545bd7c] - Updated dependencies [0a50cad] - Updated dependencies [259bfbc] - nextra@2.4.0 ## 2.3.0 ### Minor Changes - 6a79462: add new option `dateFormatter` - 76e8b0f: support custom heading id via `# my very long heading... [#my-custom-heading]` syntax https://github.com/shuding/nextra/pull/1645 ### Patch Changes - Updated dependencies [0dd028a] - Updated dependencies [6ea1caf] - Updated dependencies [76e8b0f] - nextra@2.3.0 ## 2.2.20 ### Patch Changes - Updated dependencies [2e48307] - Updated dependencies [e4c8b6d] - nextra@2.2.20 ## 2.2.19 ### Patch Changes - Updated dependencies [e41cbbc] - Updated dependencies [a1e59b2] - nextra@2.2.19 ## 2.2.18 ### Patch Changes - Updated dependencies [9bd2d59] - Updated dependencies [c2287e1] - Updated dependencies [90cb6b8] - nextra@2.2.18 ## 2.2.17 ### Patch Changes - Updated dependencies [4a66366] - nextra@2.2.17 ## 2.2.16 ### Patch Changes - b94245a: Reverts #1417 "force theme to light if darkMode: false was set" - d495e5f: introduce `_app.mdx` for better performance and smallest `.next/static/chunks` size - Updated dependencies [d495e5f] - nextra@2.2.16 ## 2.2.15 ### Patch Changes - 2e441b7: open http:// links in new window - da585a8: force theme to `light` if `darkMode: false` was set - 3e9e54f: hide unnecessary parts of the pages when being printed - Updated dependencies [d5aa17c] - Updated dependencies [016828e] - Updated dependencies [b3219c3] - nextra@2.2.15 ## 2.2.14 ### Patch Changes - Updated dependencies [bcaba9c] - Updated dependencies [a683c84] - Updated dependencies [a404ef7] - nextra@2.2.14 ## 2.2.13 ### Patch Changes - d1d873f: typed frontmatter -> `useConfig` - 6626356: prefer `import type` - 2234a13: fix raw `__esModule` string ☠️ - Updated dependencies [d1d873f] - Updated dependencies [6626356] - Updated dependencies [2234a13] - nextra@2.2.13 ## 2.2.12 ### Patch Changes - c913ec8: add peer deps - Updated dependencies [619ae3a] - nextra@2.2.12 ## 2.2.11 ## 2.2.10 ## 2.2.9 ## 2.2.8 ## 2.2.7 ## 2.2.6 ## 2.2.5 ### Patch Changes - 163065c: loader refactor, type-safe `__nextra_resolvePageMap`, avoid code interpolation in loader.ts ## 2.2.4 ### Patch Changes - 091b77b: fix missing filename add filename / copy code with "codeHighlight: false" add unit tests for filename and copy code ## 2.2.3 ### Patch Changes - 11b2870: fix copy code button position ## 2.2.2 ### Patch Changes - 3145f53: extend `plugin:react/recommended`, `plugin:react-hooks/recommended` and `plugin:@next/next/recommended` configs - 1834730: fix hydration error produced by cached compiler, fix broken code-blocks styles while setting `nextraConfig.codeHighlight: false` ## 2.2.1 ## 2.2.0 ### Minor Changes - e4b20ca: support `transform` in nextra config ### Patch Changes - af76dbe: fix highlight substring from filename for code blocks ## 2.1.0 ### Minor Changes - e5262d0: improve hmr and internal api for layout (toc and meta files) ### Patch Changes - 09fc32a: allow changing prefix in `` - c86508c: lint fixes for `eslint:recommended` and `plugin:@typescript-eslint/recommended` configs - 329bc8c: fix inline code blocks style regression - d6c871a: simplify the custom theme layout api - 1ff43c1: use OKLCH colors where possible - ef3008d: `•` separator is missing if tags are empty - c86508c: allow override components with new options `components` #1201 - a31678a: improve copy ## 2.0.3 ## 2.0.2 ### Patch Changes - 99ec64e: fix indentation for copy code button - f488e2e: remove @react/skip-nev #1051 fix: staticImage should only set blur placeholder for jpeg,png,webp,avif ## 2.0.1 ### Patch Changes - a9748aa: fix: A11y improvements to the docs theme - 93af338: feat: static tags for blog theme - ac82b1f: make code-blocks buttons focusable if they are visible on page - 0ca195c: inform screen readers of externals links that open in a new tabs ## 2.0.0 ### Patch Changes - 94ef0b3: improve 2.0 docs - 8f55c80: fix(nextra-theme-blog): unneeded spread for `` - 6644bd5: pass unstable_flexsearch - cef5546: allow headings contain links - 2217f9c: fix `Warning: Prop `href` did not match. Server: "#" Client: ...` - fdb2f57: update docs to use next.js 13 - a0398e0: fix: avoid mutating nextConfig - 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible with next 13 - a5cac21: [blog]: add support for `showLineNumbers` prop in code-blocks - fe2b714: upgrade to react 18 - 1ee3c92: reuse table styles from docs in blog - f569d90: missing `nx-` class prefixes in blog fix callout padding in docs - b1d7361: improve docs for 2.0 - 8dab966: fix invisible copy button in code blocks - 0518b1b: improve tags styling - 29dc746: fix blog build error - b7f7cf6: add missing `passHref` for `NextLink` - e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add `NextraConfig.unstable_defaultShowCopyCode` option to show button by default, add `copy` and `copy=false` options for code-blocks - a5cac21: [docs/blog]: extract code styles and import in both themes - 580c433: add nx- to all tailwind classes for style isolation - c3e6227: add `overflow-x-scroll` for tables - 1c3fedb: add missing `nx-` prefixes to table/th/tr elements - 4fd7c53: chore(nextra-theme-blog): refactor `sort-date.ts`. - 78f1519: chore: Add strict-peer-dependencies=false - 4edca5e: chore(nextra-theme-blog): refactor `traverse.ts` - acf3a1f: fix(blog): types is missing in bundle - 3de0f41: chore(blog/docs): use `postcss-import` to import css variables styles - 74a3398: update docs for 2.0 - 3ef42cb: fix(nextra-theme-blog): move css to `className`s, fix duplicate id issue - bd2cefa: Fix css classes with `eslint-plugin-tailwindcss` - ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile) - 009bf6a: Fix release workflow. - 4157b71: fix: make cusdis a component - ff8967c: fix missing `Copy Code` button in code-blocks without language - 723d42a: use `lightningcss` instead `cssnano` - 64ae4b5: add `nextraConfig.unstable_readingTime` option for blog theme - 596ea52: fix(nextra-theme-blog): make nav items center aligned - 7d2d5ee: use resolvedTheme instead renderedTheme + theme check - 256154a: use "next/future/image" if `"experimental.images.allowFutureImage": true` is set in next config - c8605d6: feat: New layout implementation - 4157b71: set lower build target and share code highlight theme through nextra - 94a8587: chore: extract `svg` icons in `/icons` folder, reusing same icons `` / `` in blog from docs - 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well - 256154a: replace images with `` even when url not relative but that starts from `/` (public directory) - e573175: Fix release CI - 48e0ac2: export `useConfig` and `useTheme` - 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader - 71528f1: show copy code button only on hover of container - 03e90d8: refresh build system with tsup and fix nextra type - e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter` - e6771ca: move `withLayout` logic directly in nextra loader - 43409ad: fix: mdx theme is missing - e596d3d: add missing class names to override styles - 07e4732: [nextra-theme-blog]: fix `Application error: a client-side exception has occurred` when invalid date was provided in frontmatter + TESTS ## 2.0.0-beta.45 ## 2.0.0-beta.44 ### Patch Changes - 94ef0b3: improve 2.0 docs - fdb2f57: update docs to use next.js 13 - b1d7361: improve docs for 2.0 - 74a3398: update docs for 2.0 ## 2.0.0-beta.43 ### Patch Changes - 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible with next 13 ## 2.0.0-beta.42 ## 2.0.0-beta.41 ### Patch Changes - bd2cefa: Fix css classes with `eslint-plugin-tailwindcss` ## 2.0.0-beta.40 ### Patch Changes - f569d90: missing `nx-` class prefixes in blog fix callout padding in docs ## 2.0.0-beta.39 ## 2.0.0-beta.38 ## 2.0.0-beta.37 ## 2.0.0-beta.36 ### Patch Changes - 1c3fedb: add missing `nx-` prefixes to table/th/tr elements ## 2.0.0-beta.35 ## 2.0.0-beta.34 ## 2.0.0-beta.33 ### Patch Changes - 580c433: add nx- to all tailwind classes for style isolation ## 2.0.0-beta.32 ### Patch Changes - 723d42a: use `lightningcss` instead `cssnano` ## 2.0.0-beta.31 ### Patch Changes - cef5546: allow headings contain links ## 2.0.0-beta.30 ### Patch Changes - b7f7cf6: add missing `passHref` for `NextLink` - 7d2d5ee: use resolvedTheme instead renderedTheme + theme check ## 2.0.0-beta.29 ## 2.0.0-beta.28 ## 2.0.0-beta.27 ## 2.0.0-beta.26 ## 2.0.0-beta.25 ### Patch Changes - c3e6227: add `overflow-x-scroll` for tables - ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile) - ff8967c: fix missing `Copy Code` button in code-blocks without language - 256154a: use "next/future/image" if `"experimental.images.allowFutureImage": true` is set in next config - 256154a: replace images with `` even when url not relative but that starts from `/` (public directory) ## 2.0.0-beta.24 ## 2.0.0-beta.23 ## 2.0.0-beta.22 ### Patch Changes - 8dab966: fix invisible copy button in code blocks ## 2.0.0-beta.21 ## 2.0.0-beta.20 ### Patch Changes - 1ee3c92: reuse table styles from docs in blog - e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add `NextraConfig.unstable_defaultShowCopyCode` option to show button by default, add `copy` and `copy=false` options for code-blocks - 64ae4b5: add `nextraConfig.unstable_readingTime` option for blog theme - 71528f1: show copy code button only on hover of container - e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter` - e6771ca: move `withLayout` logic directly in nextra loader ## 2.0.0-beta.19 ## 2.0.0-beta.18 ### Patch Changes - 0518b1b: improve tags styling ## 2.0.0-beta.17 ### Patch Changes - 2217f9c: fix `Warning: Prop`href`did not match. Server: "#" Client: ...` ## 2.0.0-beta.16 ### Patch Changes - 48e0ac2: export `useConfig` and `useTheme` - 43409ad: fix: mdx theme is missing ## 2.0.0-beta.15 ## 2.0.0-beta.14 ### Patch Changes - c8605d6: feat: New layout implementation - e596d3d: add missing class names to override styles ## 2.0.0-beta.13 ### Patch Changes - 4157b71: fix: make cusdis a component - 4157b71: set lower build target and share code highlight theme through nextra ## 2.0.0-beta.12 ### Patch Changes - a5cac21: [blog]: add support for `showLineNumbers` prop in code-blocks - 29dc746: fix blog build error - a5cac21: [docs/blog]: extract code styles and import in both themes - 3de0f41: chore(blog/docs): use `postcss-import` to import css variables styles - 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader - 07e4732: [nextra-theme-blog]: fix `Application error: a client-side exception has occurred` when invalid date was provided in frontmatter + TESTS ## 2.0.0-beta.11 ### Patch Changes - a0398e0: fix: avoid mutating nextConfig - fe2b714: upgrade to react 18 - 78f1519: chore: Add strict-peer-dependencies=false ## 2.0.0-beta.10 ### Patch Changes - 3ef42cb: fix(nextra-theme-blog): move css to `className`s, fix duplicate id issue - 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well - 03e90d8: refresh build system with tsup and fix nextra type ## 2.0.0-beta.9 ### Patch Changes - 6644bd5: pass unstable_flexsearch - 4fd7c53: chore(nextra-theme-blog): refactor `sort-date.ts`. - 4edca5e: chore(nextra-theme-blog): refactor `traverse.ts` - acf3a1f: fix(blog): types is missing in bundle - 596ea52: fix(nextra-theme-blog): make nav items center aligned - 94a8587: chore: extract `svg` icons in `/icons` folder, reusing same icons `` / `` in blog from docs - e573175: Fix release CI ## 2.0.0-beta.8 ### Patch Changes - 009bf6a: Fix release workflow. ## 2.0.0-beta.7 ### Patch Changes - 8f55c80: fix(nextra-theme-blog): unneeded spread for `` ================================================ FILE: packages/nextra-theme-blog/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: packages/nextra-theme-blog/README.md ================================================ # nextra-theme-blog A blog site theme for [Nextra](https://github.com/shuding/nextra). ## Example [site-icp9uk8zq.vercel.app](https://site-icp9uk8zq.vercel.app) ================================================ FILE: packages/nextra-theme-blog/__test__/is-valid-date.test.ts ================================================ import { describe, expect, it } from 'vitest' import { isValidDate } from '../src/is-valid-date' describe('date', () => { describe('isValidDate()', () => { it('should be valid', () => { expect(isValidDate('2022-07-28')).toBe(true) expect(isValidDate('2022-07-28T10:40')).toBe(true) expect(isValidDate('2022/10/1')).toBe(true) expect(isValidDate('2016/5/3 10:10')).toBe(true) expect(isValidDate('2022-07-29T20:49:45.112Z')).toBe(true) }) it('should be invalid', () => { expect(isValidDate('2022-07-28 10:40')).toBe(false) }) }) }) ================================================ FILE: packages/nextra-theme-blog/package.json ================================================ { "name": "nextra-theme-blog", "version": "4.6.2", "description": "A Nextra theme for blogs.", "repository": "https://github.com/shuding/nextra", "author": "Shu Ding ", "license": "MIT", "types": "./dist/index.d.mts", "exports": { "./style.css": "./dist/style.css", ".": { "types": "./dist/index.d.mts", "import": "./dist/index.js" } }, "files": [ "dist" ], "scripts": { "build": "NODE_ENV=production tsup", "dev": "tsup --watch . --watch ../nextra/src --watch ../nextra/styles", "prepublishOnly": "pnpm build", "test": "vitest run", "types:check": "tsc --noEmit" }, "peerDependencies": { "next": ">=14", "nextra": "workspace:*", "react": ">=18", "react-dom": ">=18" }, "dependencies": { "next-themes": "^0.4.0", "next-view-transitions": "^0.3.0", "react-compiler-runtime": "^19.1.0-rc.2" }, "devDependencies": { "@tailwindcss/cli": "4.1.10", "@tailwindcss/postcss": "4.1.10", "@tailwindcss/typography": "^0.5.15", "@types/react": "^19.1.8", "esbuild-react-compiler-plugin": "workspace:*", "next": "^16.0.7", "nextra": "workspace:*", "postcss": "^8.4.33", "react": "19.1.0", "tailwindcss": "4.1.10", "vitest": "^3.0.0", "zx": "^8.2.4" }, "sideEffects": false } ================================================ FILE: packages/nextra-theme-blog/postcss.config.mjs ================================================ export { default } from '../nextra-theme-docs/postcss.config.mjs' ================================================ FILE: packages/nextra-theme-blog/src/components/cusdis.tsx ================================================ 'use client' import { useTheme } from 'next-themes' import { usePathname } from 'next/navigation' import { useMounted } from 'nextra/hooks' import type { FC } from 'react' import { useEffect } from 'react' export const Comments: FC<{ appId: string host?: string }> = ({ appId, host = 'https://cusdis.com' }) => { const pathname = usePathname() const { resolvedTheme } = useTheme() const mounted = useMounted() useEffect(() => { try { // update the theme for the cusdis iframe when theme changed if (window.CUSDIS) { // window.CUSDIS? doesn't work with react-compiler window.CUSDIS.setTheme(resolvedTheme as 'dark' | 'light') } } catch (error) { console.error(error) } }, [resolvedTheme]) if (!appId) { console.warn('[nextra/cusdis] `appId` is required') return null } if (!mounted) { return null } return (