Add docs (#89)

* Refactor SubscriptionPage and enhance plan management UI

- Streamlined SubscriptionPage by consolidating plan handling into FreePlan and ProPlan components for better organization.
- Improved UI clarity by directly rendering plan components based on subscription status and enhancing overall user interaction.
- Updated button labels for clarity and removed unnecessary components to create a cleaner interface.
- Adjusted plan details and descriptions to provide clearer information on subscription benefits and features.

* wip
This commit is contained in:
Bill Yang 2025-04-16 16:42:59 -07:00 committed by GitHub
parent 9c605ef00b
commit f890ec9b2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 7798 additions and 0 deletions

1
docs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.next

8
docs/mdx-components.js Normal file
View file

@ -0,0 +1,8 @@
import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'
const docsComponents = getDocsMDXComponents()
export const useMDXComponents = components => ({
...docsComponents,
...components
})

13
docs/next.config.mjs Normal file
View file

@ -0,0 +1,13 @@
import nextra from 'nextra'
const withNextra = nextra({
latex: true,
search: {
codeblocks: false
},
contentDirBasePath: '/docs'
})
export default withNextra({
reactStrictMode: true
})

6124
docs/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

22
docs/package.json Normal file
View file

@ -0,0 +1,22 @@
{
"name": "example-docs",
"license": "MIT",
"private": true,
"scripts": {
"build": "next build",
"dev": "next --turbopack --port 3003",
"postbuild": "pagefind --site .next/server/app --output-path public/_pagefind",
"start": "next start"
},
"dependencies": {
"@theguild/remark-mermaid": "^0.3.0",
"next": "^15.0.2",
"nextra": "^4.2.17",
"nextra-theme-docs": "^4.2.17",
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"pagefind": "^1.3.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/public/demo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,2 @@
// This file will be NOT treated as `_meta` file, since directory starts with underscore
export default {}

View file

@ -0,0 +1 @@
This file will be NOT treated as page, since directory starts with underscore

13
docs/src/app/_meta.js Normal file
View file

@ -0,0 +1,13 @@
export default {
index: {
display: 'hidden'
},
docs: {
type: 'page',
title: 'Documentation'
},
blog: {
type: 'page',
title: 'Blog'
}
}

BIN
docs/src/app/apple-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -0,0 +1,14 @@
export default function BlogPage() {
return (
<h1
style={{
textAlign: 'center',
fontSize: 64,
margin: '25vh 0',
fontWeight: 'bold'
}}
>
Blog page
</h1>
)
}

View file

@ -0,0 +1,23 @@
import { generateStaticParamsFor, importPage } from 'nextra/pages'
import { useMDXComponents as getMDXComponents } from '../../../../mdx-components'
export const generateStaticParams = generateStaticParamsFor('mdxPath')
export async function generateMetadata(props) {
const params = await props.params
const { metadata } = await importPage(params.mdxPath)
return metadata
}
const Wrapper = getMDXComponents().wrapper
export default async function Page(props) {
const params = await props.params
const result = await importPage(params.mdxPath)
const { default: MDXContent, toc, metadata } = result
return (
<Wrapper toc={toc} metadata={metadata}>
<MDXContent {...props} params={params} />
</Wrapper>
)
}

BIN
docs/src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
docs/src/app/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

59
docs/src/app/layout.jsx Normal file
View file

@ -0,0 +1,59 @@
/* eslint-env node */
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 = {
metadataBase: new URL('https://nextra.site'),
title: {
template: '%s - Nextra'
},
description: 'Nextra: the Next.js site builder',
applicationName: 'Nextra',
generator: 'Next.js',
appleWebApp: {
title: 'Nextra'
},
other: {
'msapplication-TileImage': '/ms-icon-144x144.png',
'msapplication-TileColor': '#fff'
},
twitter: {
site: 'https://nextra.site'
}
}
export default async function RootLayout({ children }) {
const navbar = (
<Navbar
logo={
<div>
<b>Nextra</b>{' '}
<span style={{ opacity: '60%' }}>The Next Docs Builder</span>
</div>
}
chatLink="https://discord.gg/hEM84NMkRv"
projectLink="https://github.com/goldflag/frogstats"
/>
)
const pageMap = await getPageMap()
return (
<html lang="en" dir="ltr" suppressHydrationWarning>
<Head faviconGlyph="✦" />
<body>
<Layout
banner={<Banner storageKey="Frogstats">Frogstats Alpha</Banner>}
navbar={navbar}
footer={<Footer>Copyright {new Date().getFullYear()} © Frogstats.</Footer>}
editLink="Edit this page on GitHub"
docsRepositoryBase="https://github.com/shuding/nextra/blob/main/examples/docs"
sidebar={{ defaultMenuCollapseLevel: 1 }}
pageMap={pageMap}
>
{children}
</Layout>
</body>
</html>
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 KiB

14
docs/src/app/page.jsx Normal file
View file

@ -0,0 +1,14 @@
export default function IndexPage() {
return (
<h1
style={{
textAlign: 'center',
fontSize: 64,
margin: '25vh 0',
fontWeight: 'bold'
}}
>
Index page
</h1>
)
}

View file

@ -0,0 +1,14 @@
export default function Page() {
return (
<h1
style={{
textAlign: 'center',
fontSize: 64,
margin: '25vh 0',
fontWeight: 'bold'
}}
>
Showcase
</h1>
)
}

View file

@ -0,0 +1,7 @@
export default {
index: "",
"self-hosting": "",
features: "",
themes: "",
advanced: "",
};

View file

@ -0,0 +1,56 @@
# Code Highlighting
Nextra uses [Shiki](https://shiki.style) and
[Rehype Pretty Code](https://github.com/FormidableLabs/prism-react-renderer) to
highlight the code blocks. This section covers how you can customize it.
## Meta strings
### Highlight lines
````mdx
```jsx {1,3-5}
import 'nextra-theme-docs/style.css'
export default function Nextra({ Component, pageProps }) {
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps} />)
}
```
````
```jsx {1,4-5}
import 'nextra-theme-docs/style.css'
export default function Nextra({ Component, pageProps }) {
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps} />)
}
```
### Title
````mdx
```jsx filename="_app.js"
import 'nextra-theme-docs/style.css'
export default function Nextra({ Component, pageProps }) {
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps} />)
}
```
````
```jsx filename="_app.js"
import 'nextra-theme-docs/style.css'
export default function Nextra({ Component, pageProps }) {
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps} />)
}
```
## Supported Languages
You can find a list of supported languages
[here](https://github.com/shikijs/shiki/blob/main/docs/languages.md).

View file

@ -0,0 +1,8 @@
export default {
mdx: '',
ssg: '',
i18n: '',
image: '',
themes: '',
latex: ''
}

View file

@ -0,0 +1,54 @@
# Next.js I18n
> [!NOTE]
>
> This feature is only available in the docs theme.
Nextra supports
[Next.js Internationalized Routing](https://nextjs.org/docs/advanced-features/i18n-routing)
out of the box.
To add multi-language pages to your Nextra application, just need to config
`i18n` in `next.config.mjs`:
```js filename="next.config.mjs"
import nextra from 'nextra'
const withNextra = nextra({
theme: 'nextra-theme-docs',
themeConfig: './theme.config.js'
})
export default withNextra({
i18n: {
locales: ['en', 'zh', 'de'],
defaultLocale: 'en'
}
})
```
Then, add the locale codes to your file extensions (required for the default
locale too):
```text
/pages
index.en.md
index.zh.md
index.de.md
meta.en.json
meta.zh.json
meta.de.json
...
```
Finally, add the `i18n` option to your `theme.config.js` to configure the
language dropdown:
```jsx filename="theme.config.js"
i18n: [
{ locale: 'en', text: 'English' },
{ locale: 'zh', text: '中文' },
{ locale: 'de', text: 'Deutsch' },
{ locale: 'ar', text: 'العربية', direction: 'rtl' }
]
```

View file

@ -0,0 +1,34 @@
# Next.js Image
You can use
[Next.js Image](https://nextjs.org/docs/basic-features/image-optimization)
directly in MDX.
If the `demo.png` file is located at `/public/demo.png`, you can use the code
below to display it:
```mdx
import Image from 'next/image'
<Image src="/demo.png" alt="Hello" width={500} height={500} />
```
## Static Image
> [!NOTE]
>
> This feature is enabled via `staticImage: true` in the Nextra config by
> default.
Nextra also supports automatic static image imports, you no longer need to
specify the width and height of the image manually, and you can directly use the
Markdown syntax to display the same image:
```mdx
![Hello](/demo.png)
```
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](../../app/opengraph-image.png)

View file

@ -0,0 +1,34 @@
{/* <link rel="stylesheet"> is unsupported in Metadata API https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata */}
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/katex/dist/katex.css"
/>
# LaTeX
Nextra uses [KaTeX](https://katex.org) to render LaTeX expressions directly in
MDX. To enable LaTeX support, you must add the following to your
`next.config.mjs`:
```js filename="next.config.mjs"
import nextra from 'nextra'
const withNextra = nextra({
latex: true
})
export default withNextra()
```
Using LaTeX within MDX is as simple as wrapping your expression in `$$` or `$`.
For example, the following code
```latex
$\sqrt{a^2 + b^2}$
```
will be rendered as: $\sqrt{a^2 + b^2}$
To learn more about KaTeX and its supported functions, visit their
[documentation](https://katex.org/docs/supported.html).

View file

@ -0,0 +1,159 @@
import { compileMdx } from 'nextra/compile'
import { Callout } from 'nextra/components'
import { MDXRemote } from 'nextra/mdx-remote'
# MDX
With Nextra, all your `.md` and `.mdx` files under the pages directory will be
rendered with [MDX](https://mdxjs.com/about), it's an advanced Markdown format
with React component support.
You can use import and use React components inside your Markdown files like
this:
export async function Demo() {
const mdx = `import { Callout } from 'nextra/components'
**Markdown With React Components**
<Callout emoji="✅">
**MDX** (the library), at its core, transforms MDX (the syntax) to JSX. It
receives an MDX string and outputs a _JSX string_. It does this by parsing the
MDX document to a syntax tree and then generates a JSX document from that
tree.
</Callout>`
const rawJs = await compileMdx(`~~~mdx filename="example.mdx"
${mdx}
~~~
Generates:
${mdx}`)
return <MDXRemote compiledSource={rawJs} components={{ Callout }} />
}
<Demo />
## Headings
# **Hello**, This Is a _Title_ Inside `h1`
## **Hello**, This Is a _Title_ Inside `h2`
### **Hello**, This Is a _Title_ Inside `h3`
#### **Hello**, This Is a _Title_ Inside `h4`
##### **Hello**, This Is a _Title_ Inside `h5`
###### **Hello**, This Is a _Title_ Inside `h6`
## List
1. one
1. two
1. three
- one
- two
- three
## Task List
```mdx
- [x] Write the press release
- [ ] Update the website
- [ ] Contact the media
```
Renders
- [x] Write the press release
- [ ] Update the website
- [ ] Contact the media
## Syntax Highlighting
Automatic syntax highlighting
````mdx
```js
console.log('hello, world')
```
````
Renders:
```js
console.log('hello, world')
```
You can also add the `{line|range}` modifier to highlight specific lines:
````mdx
```jsx {4,6-8}
import useSWR from 'swr'
function Profile() {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
```
````
```jsx {4,6-8}
import useSWR from 'swr'
function Profile() {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
```
## Inline Code
You can use \`content\` to wrap inline code content like: `let x = 1`.
## Blockquote
> Where some people measure progress in answers-right per test or tests-passed
> per year, we are more interested in Sistine-Chapel-Ceilings per Lifetime.
>
> — Alan Kay, A Personal Computer for Children of All Ages
Nested quotes:
> > Where some people measure progress in answers-right per test or tests-passed
> > per year, we are more interested in Sistine-Chapel-Ceilings per Lifetime.
> >
> > — Alan Kay, A Personal Computer for Children of All Ages
>
> This is **great**.
>
> — Shu Ding.
## Table
| Syntax | Description | Test Text |
| :------------ | :---------: | ----------: |
| Header | Title | Here's this |
| Paragraph | Text | And more |
| Strikethrough | | ~~Text~~ |
## React Components
React components and Markdown can be **mixed together**, for instance:
```mdx
<Callout>Give [**Nextra**](https://github.com/shuding/nextra) a star!</Callout>
```
Renders:
<Callout>Give [**Nextra**](https://github.com/shuding/nextra) a star!</Callout>

View file

@ -0,0 +1,45 @@
# 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 Stars() {
let stars = 0
try {
const response = await fetch('https://api.github.com/repos/shuding/nextra')
const repo = await response.json()
stars = repo.stargazers_count
} catch {
/* Ignore if there is an error, due rate limiting on CI */
}
return <b>{stars}</b>
}
> Nextra has <Stars /> stars on GitHub!
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.
---
Here's the MDX code for the example above:
```js filename="ssg.mdx"
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 || 0
return <b>{stars}</b>
}
> Nextra has <Stars /> stars on GitHub!
```

View file

@ -0,0 +1,16 @@
# Themes
Nextra itself is basically a plugin that normalizes your Markdown routes in
Next.js into structural data, and it doesn't handle any styling related thing. A
**theme** is what renders your actual pages, it works like a layout component in
React.
Nextra has 2 official themes that you can use:
- [Docs Theme](/themes/docs)
- [Blog Theme](/themes/blog)
You can also extend your own themes. Here's a great starter example by
[@jaredpalmer](https://github.com/jaredpalmer):
- [Nextra Blank Custom Theme/Boilerplate Example](https://github.com/jaredpalmer/nextra-blank-custom-theme)

View file

@ -0,0 +1,17 @@
import { Bleed } from 'nextra/components'
# Introduction
**Frogstats** is an open source web and products analytics platform. Check out our [live demo](https://tracking.tomato.gg) using a real production site that sends over **10,000,000** events a month.
### Key Features
- Extremely comprehensive prebuilt analytics dashboards
- Cookieless and privacy-friendly
- Ability to make your dashboard public
- Support for organizations
- Advanced product analytics like funnels, user retention, user journeys, and custom reports
You can either self-host Frogstats, or use our hosted cloud version.
<Bleed>![Nextra Example](/demo.png)</Bleed>

View file

@ -0,0 +1,22 @@
# Mermaid
```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;
```

View file

@ -0,0 +1,3 @@
# Just Page
{/* this file should not be treated as App Router page */}

View file

@ -0,0 +1,105 @@
import { Steps } from 'nextra/components'
# Self Hosting
You can self-host Frogstats by following the steps below.
## Create manually
Nextra works like a Next.js plugin, and it accepts a theme config (layout) to
render the page. To start: [^3]
<Steps>
### Install Next.js, Nextra and React [^1]
{/* ```sh npm2yarn
npm i react react-dom next nextra
``` */}
### Install the docs theme [^2]
```sh npm2yarn
npm i nextra-theme-docs
```
### Create the following Next.js config and theme config under the root directory
```js filename="next.config.mjs"
import nextra from 'nextra'
const withNextra = nextra({
theme: 'nextra-theme-blog',
themeConfig: './theme.config.js'
})
export default withNextra()
```
### Create a `theme.config.js` file for the docs theme
```js filename="theme.config.js"
export default {
project: {
link: 'https://github.com/shuding/nextra' // GitHub link in the navbar
},
docsRepositoryBase: 'https://github.com/shuding/nextra/blob/master', // base URL for the docs repository
getNextSeoProps: () => ({ titleTemplate: '%s Nextra' }),
navigation: true,
darkMode: true,
footer: {
text: `MIT ${new Date().getFullYear()} © Shu Ding.`
},
editLink: {
text: 'Edit this page on GitHub'
},
logo: (
<>
<svg>...</svg>
<span>Next.js Static Site Generator</span>
</>
),
head: (
<>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Nextra: the next docs builder" />
<meta name="og:title" content="Nextra: the next docs builder" />
</>
),
primaryHue: {
dark: 204,
light: 212
}
}
```
> [!NOTE]
>
> More configuration options for the docs theme can be found
> [here](/themes/docs/configuration).
### You are good to go! Run `next dev` to start
</Steps>
---
<span id="sidebar-and-anchor-links" />
> [!NOTE]
>
> Any `.md` or `.mdx` file will turn into a doc page and be displayed in
> sidebar. You can also create a `_meta.js` file to customize the page order and
> title. <br /> Check the source code: https://github.com/shuding/nextra for
> more information.
> [!TIP]
>
> You can also use
> [`<style jsx>`](https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js)
> to style elements inside `theme.config.js`.
[^1]: Install Next.js, Nextra and React.
[^2]: Install the docs theme.
[^3]: To start.

View file

@ -0,0 +1,4 @@
export default {
docs: 'Docs Theme',
blog: 'Blog Theme'
}

View file

@ -0,0 +1,3 @@
export default {
index: ''
}

View file

@ -0,0 +1,96 @@
---
sidebarTitle: Installation
---
# Get Started
import { Steps } from 'nextra/components'
## Configurations
Similar to the docs theme, you can install the blog theme with the following
commands:
<Steps>
### Install Next.js, Nextra and React
```sh npm2yarn
npm i next nextra react react-dom
```
### Install the blog theme
```sh npm2yarn
npm i nextra-theme-blog
```
### Create the following Next.js config and theme config under the root directory:
```js filename="next.config.mjs"
import nextra from 'nextra'
const withNextra = nextra({
theme: 'nextra-theme-blog',
themeConfig: './theme.config.js'
})
export default withNextra()
```
```jsx filename="theme.config.js"
export default {
footer: <p>MIT 2021 © Nextra.</p>,
head: ({ title, meta }) => (
<>
{meta.description && (
<meta name="description" content={meta.description} />
)}
{meta.tag && <meta name="keywords" content={meta.tag} />}
{meta.author && <meta name="author" content={meta.author} />}
</>
),
readMore: 'Read More →',
titleSuffix: null,
postFooter: null,
cusdis: {
appId: 'your_app_id',
host: 'your_host(optional)',
lang: 'your_lang'
},
darkMode: false,
navs: [
{
url: 'https://github.com/shuding/nextra',
name: 'Nextra'
}
]
}
```
### Create `pages/_app.js` and include the theme stylesheet:
```jsx filename="_app.js"
import 'nextra-theme-blog/style.css'
export default function Nextra({ Component, pageProps }) {
const getLayout = Component.getLayout || (page => page)
return <Component {...pageProps} />
}
```
### You are good to go!
</Steps>
---
> [!TIP]
>
> You can also use
> [`<style jsx>`](https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js)
> to style elements inside `theme.config.js`.
> [!NOTE]
>
> An example of the blog theme can be found
> [here](https://github.com/vercel-solutions/nextjs-portfolio-starter).

View file

@ -0,0 +1,6 @@
export default {
index: '',
configuration: '',
callout: '',
bleed: ''
}

View file

@ -0,0 +1,82 @@
---
sidebarTitle: Bleed
---
# Bleed Component
A built-in component provided by `nextra-theme-docs`.
## Example
When wrapping your content with `<Bleed>`, it will be slightly wider than the
container and will overflow on both sides.
import { Bleed } from 'nextra/components'
<Bleed>
<div style={{ border: '1px solid #888', padding: '4rem 2.5rem', textAlign: 'center' }}>
_There is nothing to writing. All you do is sit down at a typewriter and **bleed**._
— Ernest Hemingway
</div>
</Bleed>
It provides a better reading experience when you want to present some graphical
information, which normally looks nicer in a larger size.
For example, you can put text, image, video or any component inside:
<Bleed>
<iframe
width="100%"
height="430"
src="https://youtube.com/embed/3hccXiXI0u8"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</Bleed>
You can even make it full-bleed using `<Bleed full>`:
<Bleed full>![Nextra](../../../app/opengraph-image.png)</Bleed>
## Usage
### MDX component
```mdx filename="bleed.mdx"
<Bleed>Hey, I can use **Markdown** syntax here.</Bleed>
<Bleed full>![Nextra](https://nextra.site/og.jpeg)</Bleed>
<Bleed full>
<iframe
src="https://codesandbox.io/embed/swr-states-4une7"
width="100%"
height="500px"
title="SWR-States"
/>
</Bleed>
```
### React Component
```jsx filename="bleed.jsx"
import { Bleed } from 'nextra/components'
<Bleed>Hey, I can use **Markdown** syntax here.</Bleed>
<Bleed full>
![Nextra](https://nextra.site/og.jpeg)
</Bleed>
<Bleed full>
<iframe
src="https://codesandbox.io/embed/swr-states-4une7"
width="100%"
height="500px"
title="SWR-States"
/>
</Bleed>
```

View file

@ -0,0 +1,66 @@
---
sidebarTitle: Callout
---
# Callout Component
A built-in component provided by `nextra/components`.
## Example
import { Callout } from 'nextra/components'
<Callout>
A **callout** is a short piece of text intended to attract attention.
</Callout>
## Usage
### Default
<Callout emoji="👾">
**Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro
Nishikado.
</Callout>
```mdx
<Callout emoji="👾">
**Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro
Nishikado.
</Callout>
```
### Warning
<Callout type="warning">This API will be deprecated soon.</Callout>
```mdx
<Callout type="warning">This API will be deprecated soon.</Callout>
```
### Error
<Callout type="error">
This is a dangerous feature that can cause everything to explode.
</Callout>
```mdx
<Callout type="error">
This is a dangerous feature that can cause everything to explode.
</Callout>
```
### React Component
```jsx filename="callout.jsx"
import { Callout } from 'nextra/components'
const Component = () => {
return (
<Callout emoji="👾">
**Space Invaders** is a 1978 shoot 'em up arcade game developed by
Tomohiro Nishikado.
</Callout>
)
}
```

View file

@ -0,0 +1,510 @@
# Configuration
To configure the theme, edit or create the `theme.config.js` file in the root
directory. The file looks something like this:
```js filename="theme.config.js"
export default {
projectLink: 'https://gitlab.com/librewolf-community/browser',
titleSuffix: ' Nextra',
footerText: `MIT ${new Date().getFullYear()} © Nextra.`
}
```
## `projectLink`
The URL that the button in the top right will point to.
**Type:** `string`
**Default:** `https://github.com/shuding/nextra`
**Example:**
```js filename="theme.config.js"
export default {
projectLink: 'https://gitlab.com/librewolf-community/browser'
}
```
## `projectLinkIcon`
Changes the icon that is shown in the top right.
**Type:** `ReactNode | React.FC<{ locale: string }>{:ts}`
**Default:** GitHub icon
**Example:**
```jsx filename="theme.config.jsx"
import Gitlab from '@geist-ui/react-icons/gitlab'
export default {
projectLinkIcon: ({ locale }) => <Gitlab />
}
```
## `docsRepositoryBase`
The base URL of the GitHub repository the docs are located in. This will be used
for the `Edit this Page on GitHub` button.
**Type:** `string`
**Default:** `https://github.com/shuding/nextra`
**Example:**
```js filename="theme.config.js"
export default {
docsRepositoryBase: 'https://github.com/shuding/nextra'
}
```
## `titleSuffix`
Suffix that will be added to page titles in the URL bar.
**Type:** `string`
**Default:** ` Nextra`
**Example:**
```js filename="theme.config.js"
export default {
titleSuffix: ' Nextra'
}
```
## `nextLinks` and `prevLinks`
Specifies if arrows are being shown at the bottom of a page showing the next and
previous page, like the ones at the bottom of this page.
**Type:** `boolean`
**Default:** `true`
**Example:**
```js filename="theme.config.js"
export default {
nextLinks: true,
prevLinks: true
}
```
## `search`
Specifies if a search box should be shown in the top right.
**Type:** `boolean`
**Default:** `true`
**Example:**
```js filename="theme.config.js"
export default {
search: true
}
```
## `searchPlaceholder`
Specifies if a search box should be shown in the top right.
**Type:** `string | ((props: { locale: string }) => string){:ts}`
**Example:**
```js filename="theme.config.js"
export default {
searchPlaceholder({ locale }) {
if (locale === 'zh-CN') return '搜索文档...'
return 'Search documentation...'
}
}
```
## `customSearch`
A custom component to display instead of the search bar in the top right, for
example Algolia.
**Type:** `ReactNode`
**Example:**
```jsx filename="theme.config.jsx"
import Search from 'your-search'
export default {
customSearch: <Search />
}
```
## `darkMode`
Specifies if the user can select a dark mode.
**Type:** `boolean`
**Default:** `true`
**Example:**
```js filename="theme.config.js"
export default {
darkMode: true
}
```
## `defaultMenuCollapseLevel`
Specifies the folder level at which the menu on the left is collapsed by
default.
**Type:** `number`
**Default:** `2`
**Example:**
```js filename="theme.config.js"
export default {
defaultMenuCollapseLevel: 2
}
```
## `footer`
Specifies if the footer should be shown.
**Type:** `boolean`
**Default:** `true`
**Example:**
```js filename="theme.config.js"
export default {
footer: true
}
```
## `footerText`
The text that is shown on the left of the footer.
**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`
**Example:**
```js filename="theme.config.js"
export default {
footerText: ({ locale }) => `MIT ${new Date().getFullYear()} © Nextra.`
}
```
## `footerEditLink`
The components that should be shown on the link that leads to the editable page
on the repository.
**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`
**Default:** `Edit this page`
**Example:**
```js filename="theme.config.js"
export default {
footerEditLink: ({ locale }) => 'Edit this page on GitHub'
}
```
## `feedbackLink`
The components that should be shown on the link that leads to the issues or
discussions of the repository.
**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`
**Default:** ``
**Example:**
```js filename="theme.config.js"
export default {
feedbackLink: ({ locale }) => 'Question? Give us feedback →'
}
```
## `feedbackLabels`
Label used for create issue or discussion.
**Type:** `string`
**Default:** ``
**Example:**
```js filename="theme.config.js"
export default {
feedbackLabels: 'feedbacks'
}
```
## `logo`
The logo in the top left.
**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`
**Example:**
```jsx filename="theme.config.jsx"
export default {
logo: ({ locale }) => (
<>
<span className="mr-2 hidden font-extrabold md:inline">Nextra</span>
<span className="hidden font-normal text-gray-600 md:inline">
The Next Docs Builder
</span>
</>
)
}
```
## `logoLink`
Enable automaticaly linking the logo to root, or provide a custom url.
**Type:** `string` | `boolean`
**Default:** `true` (links to `/` by default)
**Example:**
```js filename="theme.config.js"
export default {
logoLink: '/about'
}
```
Or to disable the logo link:
```js filename="theme.config.js"
export default {
logoLink: false
}
```
## `head`
The head that should be inserted into the html document.
**Type:**
`ReactNode | React.FC<PropsWithChildren<{ locale: string; config: DocsThemeConfig; title: string; meta: Record<string, any> }>>{:ts}`
**Example:**
```jsx filename="theme.config.jsx"
export default {
head: (
<>
<meta name="msapplication-TileColor" content="#fff" />
<meta httpEquiv="Content-Language" content="en" />
<meta name="description" content="Nextra: the next docs builder" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@shuding_" />
<meta property="og:title" content="Nextra: the next docs builder" />
<meta property="og:description" content="Nextra: the next docs builder" />
<meta name="apple-mobile-web-app-title" content="Nextra" />
</>
)
}
```
## `direction`
The direction of the text on the page
**Type:** `'ltr' | 'rtl'`
**Default:** `'ltr'`
**Example:**
```js filename="theme.config.js"
export default {
direction: 'ltr'
}
```
## `floatTOC`
Specifies if the table of contents of a page (the headings) should be displayed
floating on the right instead of being integrated in the menu on the left.
**Type:** `boolean`
**Default:** `false`
**Example:**
```js filename="theme.config.js"
export default {
floatTOC: false
}
```
## `projectChatLink`
The URL that the chat button in the top right will point to.
**Type:** `string`
**Example:**
```js filename="theme.config.js"
export default {
projectChatLink: 'https://discord.gg/hEM84NMkRv'
}
```
## `projectChatLinkIcon`
The icon component that is used as the chat button
**Type:** `ReactNode`
**Example:**
```jsx filename="theme.config.jsx"
export default {
projectChatLinkIcon: <Discord />
}
```
## `banner`
The banner content that will display at top of the page.
**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`
**Example:**
```js filename="theme.config.js"
export default {
banner: ({ locale }) => 'Nextra 2'
}
```
## `bannerKey`
The key that is used to control the display of banner in localStorage.
**Type:** `string`
**Default:** `'nextra-banner'`
**Example:**
```js filename="theme.config.js"
export default {
bannerKey: 'Nextra-banner'
}
```
## `gitTimestamp`
The component that is used to display timestamp of the last commit of current
page.
**Type:**
`string | React.FC<PropsWithChildren<{ locale: string; timestamp: Date }>>{:ts}`
**Example:**
```js filename="theme.config.js"
export default {
gitTimestamp: 'Last updated on'
}
```
## `tocExtraContent`
The extra content that is displayed under the table of contents.
**Type:** `ReactNode | React.FC<PropsWithChildren<unknown>>{:ts}`
**Example:**
```jsx filename="theme.config.jsx"
export default {
tocExtraContent() {
return <img src="https://placecats.com/300/200" alt="" />
}
}
```
## `i18n`
The internationalization (i18n) config. See more [here](/features/i18n).
## `faviconGlyph`
A glyph that should be used as a favicon.
**Type:** `char`
**Example:**
```js filename="theme.config.js"
export default {
faviconGlyph: '🐱'
}
```
## `search`
Enable Nextra built-in search
**Type:** `boolean | { codeblocks: boolean }`
**Example:**
```js filename="next.config.mjs"
import nextra from 'nextra'
const withNextra = nextra({
theme: 'nextra-theme-blog',
themeConfig: './theme.config.js',
search: {
codeblocks: false
}
})
export default withNextra()
```
## `searchResultEmpty`
Empty component for search result.
**Type:** `boolean | { codeblocks: boolean }`
**Example:**
```js filename="theme.config.js"
export default {
searchResultEmpty({ locale }) {
if (locale === 'zh-CN') return '未查找到结果'
return 'No results found'
}
}
```

View file

@ -0,0 +1,82 @@
---
sidebarTitle: Installation
---
# Docs Theme
import { Steps } from 'nextra/components'
> [!NOTE]
>
> This website is built with the docs theme.
you can install the blog theme with the following commands:
## Getting start
<Steps>
### Install Next.js, Nextra and React
```sh npm2yarn
npm i react react-dom next nextra
```
### Install the docs theme
```sh npm2yarn
npm i nextra-theme-docs
```
### Create the following Next.js config and theme config under the root directory:
```jsx filename="next.config.mjs"
import nextra from 'nextra'
const withNextra = nextra({
theme: 'nextra-theme-blog',
themeConfig: './theme.config.js'
})
export default withNextra()
```
```jsx filename="theme.config.js"
export default {
projectLink: 'https://github.com/shuding/nextra', // GitHub link in the navbar
docsRepositoryBase: 'https://github.com/shuding/nextra/blob/master', // base URL for the docs repository
titleSuffix: ' Nextra',
nextLinks: true,
prevLinks: true,
search: true,
customSearch: null, // customizable, you can use algolia for example
darkMode: true,
footer: true,
footerText: `MIT ${new Date().getFullYear()} © Shu Ding.`,
footerEditLink: `Edit this page on GitHub`,
logo: (
<>
<svg>...</svg>
<span>Next.js Static Site Generator</span>
</>
),
head: (
<>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Nextra: the next docs builder" />
<meta name="og:title" content="Nextra: the next docs builder" />
</>
)
}
```
### You are good to go!
</Steps>
---
> [!TIP]
>
> You can also use
> [`<style jsx>`](https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js)
> to style elements inside `theme.config.js`.

View file

@ -0,0 +1,81 @@
---
sidebarTitle: Tabs
---
# Tabs Component
A built-in component provided by `nextra-theme-docs`.
## Example
import { Tabs } from 'nextra/components'
<Tabs items={['JavaScript', 'C++', {label:'C', disabled: true}, 'Python']} defaultIndex={1}>
<Tabs.Tab>
```js filename="hi.js"
import { useState, useEffect } from 'react';
```
</Tabs.Tab>
<Tabs.Tab>
```cpp filename="hi.cpp"
#include <iostream>
```
</Tabs.Tab>
<Tabs.Tab>
```c filename="hi.c"
#include <stdio.h>
```
</Tabs.Tab>
<Tabs.Tab>
```python filename="hello.py"
print('Hello, world!')
```
</Tabs.Tab>
</Tabs>
## Usage
### MDX component
````mdx filename="tabs.mdx"
<Tabs items={['JavaScript', 'C++', {label:'C', disabled: true}, 'Python']} defaultIndex={1}>
<Tabs.Tab>
```js filename="hi.js"
import { useState, useEffect } from 'react';
```
</Tabs.Tab>
<Tabs.Tab>
```cpp filename="hi.cpp"
#include <iostream>
```
</Tabs.Tab>
<Tabs.Tab>
```c filename="hi.c"
#include <stdio.h>
```
</Tabs.Tab>
<Tabs.Tab>
```python filename="hello.py"
print('Hello, world!')
```
</Tabs.Tab>
</Tabs>
````
### React Component
```jsx filename="tabs.jsx"
import { Tabs } from 'nextra/components'
const items = ['1', '2', '3', '4']
const defaultIndex = 1
const Component = () => (
<Tabs items={items} defaultIndex={defaultIndex}>
<Tabs.Tab>1</Tab>
<Tabs.Tab>2</Tab>
<Tabs.Tab>3</Tab>
<Tabs.Tab>4</Tab>
</Tabs>
)
export default Component
```