Compare commits

..

No commits in common. "cloudflare" and "dev/tailwindv4" have entirely different histories.

891 changed files with 16510 additions and 71568 deletions

View File

@ -5,10 +5,6 @@
"args": [
"~/.console-ninja/mcp/"
]
},
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp@latest"]
}
}
}

View File

@ -1,6 +1,6 @@
---
description: Best practices for using Vercel AI SDK
globs: *.tsx,*.ts
globs: **/*.{ts,tsx}
alwaysApply: false
---

View File

@ -1,43 +0,0 @@
---
description:
globs: *.tsx,*.ts
alwaysApply: false
---
# Database and State Management Guide
## Database (Drizzle ORM)
- Schema definitions in `src/db/schema.ts`
- Migrations in `src/db/migrations`
- Use `db:generate` to create new migration files based on schema changes
- Use `db:migrate` to apply pending migrations to the database
- Use `db:push` to sync schema changes directly to the database (development only)
- Use `db:studio` to view and manage database data through the Drizzle Studio UI
- Follow naming conventions for tables and columns
- Use proper data types and constraints
- Implement proper indexes
- Handle relationships properly
- Use transactions when needed
## State Management (Zustand)
- Store definitions in `src/stores/`
- Keep stores modular and focused
- Use TypeScript for store types
- Implement proper state updates
- Handle async operations properly
- Use selectors for derived state
- Implement proper error handling
- Use middleware when needed
- Keep store logic pure
- Document complex state logic
## Data Flow
1. Server-side data fetching in server components
2. Client-side state in Zustand stores
3. Form state in React Hook Form
4. API calls through server actions
5. Database operations through Drizzle
6. File storage through AWS S3
7. Proper error handling at each layer
8. Type safety throughout
9. Proper validation with Zod
10. Proper caching strategies

View File

@ -1,10 +1,10 @@
---
description: Best practices for date and time manipulation with date-fns
globs: *.ts,*.tsx
globs: **/*.{ts,tsx,js,jsx}
alwaysApply: false
---
- Use the `format` function for consistent date formatting across your application.
- Implement proper timezone handling using the `utcToZonedTime` function.
- Utilize the `intervalToDuration` function for calculating time differences.
- Leverage the `isWithinInterval` function for date range checks.
- Leverage the `isWithinInterval` function for date range checks.

View File

@ -1,39 +0,0 @@
---
description:
globs: *.tsx,*.ts
alwaysApply: false
---
# Development Workflow Guide
## Available Scripts
- `pnpm dev`: Start development server with content collections
- `pnpm build`: Build the application and content collections
- `pnpm start`: Start production server
- `pnpm lint`: Run Biome linter
- `pnpm format`: Format code with Biome
- `pnpm db:generate`: Generate new migration files based on schema changes
- `pnpm db:migrate`: Apply pending migrations to the database
- `pnpm db:push`: Sync schema changes directly to the database (development only)
- `pnpm db:studio`: Open Drizzle Studio for database inspection and management
- `pnpm email`: Start email template development server
## Development Process
1. Use TypeScript for all new code
2. Follow Biome formatting rules
3. Write server actions in `src/actions/`
4. Use Zustand for client-side state
5. Implement database changes through Drizzle migrations
6. Use Radix UI components for consistent UI
7. Follow the established directory structure
8. Write tests for new features
9. Update content collections when adding new content
10. Use environment variables from `env.example`
## Code Style
- Use functional components with hooks
- Implement proper error handling
- Follow TypeScript best practices
- Use proper type definitions
- Document complex logic
- Keep components small and focused
- Use proper naming conventions

View File

@ -1,7 +1,6 @@
---
description: Best practices for using Drizzle ORM with database
globs: *.tsx,*.ts
alwaysApply: false
globs: **/*.{ts}
---
- Use Drizzle's type-safe query builder for better code completion and safety.

View File

@ -1,6 +1,6 @@
---
description: Best practices for Next.js applications and routing
globs: *.tsx,*.ts
globs: **/*.{ts,tsx}
alwaysApply: false
---

View File

@ -1,37 +0,0 @@
---
description:
globs: **/*.{ts,tsx}
alwaysApply: false
---
# Project Structure Guide
## Core Directories
- `src/app/`: Next.js app router pages and layouts
- `src/components/`: Reusable React components
- `src/lib/`: Utility functions and shared code
- `src/db/`: Database schema and migrations using Drizzle ORM
- `src/stores/`: Zustand state management
- `src/actions/`: Server actions and API routes
- `src/hooks/`: Custom React hooks
- `src/types/`: TypeScript type definitions
- `src/i18n/`: Internationalization setup
- `src/mail/`: Email templates and mail functionality
- `src/payment/`: Payment integration
- `src/analytics/`: Analytics and tracking
- `src/storage/`: File storage integration
- `src/notification/`: Sending Notifications
## Configuration Files
- `next.config.ts`: Next.js configuration
- `drizzle.config.ts`: Database configuration
- `biome.json`: Code formatting and linting rules
- `tsconfig.json`: TypeScript configuration
- `components.json`: UI components configuration
## Content Management
- `content/`: MDX content files
- `source.config.ts`: Fumadocs source configuration
## Environment
- `env.example`: Environment variables template
- `global.d.ts`: Global TypeScript declarations

View File

@ -1,6 +1,6 @@
---
description: Best practices for using Radix UI components
globs: *.tsx,*.ts
globs: **/*.{ts,tsx}
alwaysApply: false
---

View File

@ -1,6 +1,6 @@
---
description: Best practices for React component development
globs: *.tsx,*.ts
globs: **/*.{ts,tsx,js,jsx}
alwaysApply: false
---

View File

@ -1,10 +1,10 @@
---
description: Best practices for form handling with React Hook Form
globs: *.tsx,*.ts
globs: **/*.{ts,tsx}
alwaysApply: false
---
- Use the `useForm` hook for efficient form state management.
- Implement validation using Zod with `@hookform/resolvers` for type-safe form validation.
- Utilize the `Controller` component for integrating with custom inputs.
- Leverage the `useFormContext` hook for sharing form state across components.
- Leverage the `useFormContext` hook for sharing form state across components.

View File

@ -1,6 +1,6 @@
---
description: Best practices for integrating Stripe payments
globs: *.tsx,*.ts
globs: **/*.{ts,tsx}
alwaysApply: false
---

View File

@ -1,6 +1,6 @@
---
description: Best practices for styling with Tailwind CSS
globs: *.tsx,*.ts
globs: **/*.{ts,tsx,css}
alwaysApply: false
---

View File

@ -1,6 +1,6 @@
---
description: TypeScript coding standards and type safety guidelines
globs: *.tsx,*.ts
globs: **/*.{ts,tsx}
alwaysApply: false
---
@ -10,5 +10,4 @@ alwaysApply: false
- Use generics for reusable components and functions.
- Use strict null checks to prevent null and undefined errors
- Implement proper type inference using generics for reusable components.
- Utilize type guards and assertions for runtime type checking.
- Use `pnpm` as default package manager if run Command in Terminal.
- Utilize type guards and assertions for runtime type checking.

View File

@ -1,54 +0,0 @@
---
description:
globs: **/*.{ts,tsx}
alwaysApply: false
---
# UI and Components Guide
## Component Structure
- Components in `src/components/`
- Follow atomic design principles
- Use Radix UI primitives
- Implement proper accessibility
- Use Tailwind CSS for styling
- Follow consistent naming
- Keep components focused
- Implement proper error states
- Handle loading states
- Use proper TypeScript types
## UI Libraries
- Radix UI for primitives
- Tailwind CSS for styling
- Framer Motion for animations
- React Hook Form for forms
- Zod for validation
- Lucide React for icons
- Tabler Icons for additional icons
- Sonner for toasts
- Vaul for drawers
- Embla Carousel for carousels
## Styling Guidelines
- Use Tailwind CSS classes
- Follow design system tokens
- Implement dark mode support
- Use proper spacing scale
- Follow color palette
- Implement responsive design
- Use proper typography
- Handle hover/focus states
- Implement proper transitions
- Use proper z-index scale
## Accessibility
- Use semantic HTML
- Implement proper ARIA labels
- Handle keyboard navigation
- Support screen readers
- Use proper color contrast
- Implement focus management
- Handle dynamic content
- Support reduced motion
- Test with assistive tools
- Follow WCAG guidelines

View File

@ -1,7 +1,6 @@
---
description: Best practices for schema validation with Zod
globs: *.tsx,*.ts
alwaysApply: false
globs: **/*.{ts,tsx}
---
- Define clear and reusable schemas for data validation

View File

@ -1,10 +1,10 @@
---
description: Best practices for state management with Zustand
globs: *.tsx,*.ts
globs: **/*.{ts,tsx}
alwaysApply: false
---
- Use the `create` function to define your store for simplicity and performance.
- Implement middleware like `persist` for persisting state across sessions.
- Utilize the `useStore` hook for accessing store state in components.
- Leverage the `immer` middleware for easier state updates with mutable syntax.
- Leverage the `immer` middleware for easier state updates with mutable syntax.

46
.cursorrules Normal file
View File

@ -0,0 +1,46 @@
You are an expert in TypeScript, Node.js, Next.js with the app router, React, Shadcn/ui, Magic UI, Tailwind, Better Auth, Drizzle ORM, Content Collections, and Vercel AI SDK.
General Principles
- Write clean, concise, and well-commented TypeScript code
- Favor functional and declarative programming patterns over object-oriented approaches
- Prioritize code reuse and modularization over duplication
Naming and Conventions
- Use PascalCase for class names and type definitions
- Utilize camelCase for variables, functions, and methods
- Employ kebab-case for file and directory names
- Reserve UPPERCASE for environment variables and constants
- Avoid magic numbers by defining constants with meaningful names
- Start each function name with a verb to indicate its purpose
TypeScript Usage
- Leverage TypeScript for all code
- Prefer types over interfaces
- Favor functional components over class components
Code Organization
- Structure files logically, grouping related components, helpers, types, and static content
- Prefer named exports for components over default exports
- Favor small, single-purpose components over large, monolithic ones
- Separate concerns between presentational and container components
UI and Styling
- Utilize Shadcn/ui, Radix, and Tailwind for building consistent and accessible UI components
- Implement responsive design using Tailwind CSS with a mobile-first approach
- Use Magic UI for advanced components and animations
- Use Lucide for icons
Data Management
- Interact with the database using Drizzle ORM
- Leverage Drizzle's generated types
Next.js and React
- Minimize the use of `use client`, `useEffect`, and `setState`
- Favor React Server Components (RSC) whenever possible
- Wrap client-side components in `Suspense` with a fallback
- Implement dynamic loading for non-critical components
- Use server actions for mutations instead of route handlers
Error Handling and Logging
- Implement robust error handling and logging mechanisms
- Provide clear and user-friendly error messages to the end-users

View File

@ -1,16 +0,0 @@
.cursor
.claude
.conductor
.kiro
.github
.next
.open-next
.source
.vscode
.git
.wrangler
.dockerignore
node_modules
**/node_modules
Dockerfile
LICENSE

41
.gitattributes vendored
View File

@ -1,41 +0,0 @@
# Set default behavior to automatically normalize line endings
* text=auto
# Force LF line endings for text files
*.js text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.json text eol=lf
*.md text eol=lf
*.mdx text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.html text eol=lf
*.xml text eol=lf
*.txt text eol=lf
*.sh text eol=lf
# Ensure these files are always treated as text and get LF line endings
.gitignore text eol=lf
.gitattributes text eol=lf
.editorconfig text eol=lf
*.config.js text eol=lf
*.config.ts text eol=lf
# Binary files should be left untouched
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.svg binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
*.pdf binary
*.zip binary
*.tar.gz binary

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: javayhu
---
**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. iPhone16]
- 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.

View File

@ -1,8 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: MkSaaS Community Support
url: https://github.com/MkSaaSHQ/mksaas-template/discussions
about: Please ask and answer questions here.
- name: MkSaaS Documentation
url: https://mksaas.com/docs
about: Please check out the documentation here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[feat]"
labels: enhancement
assignees: javayhu
---
**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.

25
.gitignore vendored
View File

@ -30,38 +30,15 @@ yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
certificates
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# claude code
.claude
# conductor
.conductor
# kiro
.kiro
# typescript
*.tsbuildinfo
next-env.d.ts
# content collections
.content-collections
# fumadocs
.source
# OpenNext build output
.open-next
# wrangler files
.wrangler
.dev.vars
.dev.vars*
!.dev.vars.example
.content-collections

View File

@ -1,10 +0,0 @@
{
"recommendations": [
"biomejs.biome",
"bradlc.vscode-tailwindcss",
"Lokalise.i18n-ally",
"unifiedjs.vscode-mdx",
"eamodio.gitlens",
"editorconfig.editorconfig"
]
}

40
.vscode/settings.json vendored
View File

@ -1,35 +1,7 @@
{
"i18n-ally.localesPaths": [
"messages",
"src/i18n"
],
"i18n-ally.keystyle": "nested",
"editor.defaultFormatter": "biomejs.biome",
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"search.exclude": {
"**/node_modules": true,
".next": true,
".source": true,
".wrangler": true,
".open-next": true,
".vscode": true,
".cursor": true,
".claude": true,
".conductor": true,
".kiro": true,
".github": true
}
}
"i18n-ally.localesPaths": [
"messages",
"src/i18n"
],
"i18n-ally.keystyle": "nested"
}

109
CLAUDE.md
View File

@ -1,109 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Development Commands
### Core Development
- `pnpm dev` - Start development server with content collections
- `pnpm build` - Build the application and content collections
- `pnpm start` - Start production server
- `pnpm lint` - Run Biome linter (use for code quality checks)
- `pnpm format` - Format code with Biome
### Database Operations (Drizzle ORM)
- `pnpm db:generate` - Generate new migration files based on schema changes
- `pnpm db:migrate` - Apply pending migrations to the database
- `pnpm db:push` - Sync schema changes directly to the database (development only)
- `pnpm db:studio` - Open Drizzle Studio for database inspection and management
### Content and Email
- `pnpm content` - Process MDX content collections
- `pnpm email` - Start email template development server on port 3333
## Project Architecture
This is a Next.js 15 full-stack SaaS application with the following key architectural components:
### Core Stack
- **Framework**: Next.js 15 with App Router
- **Database**: PostgreSQL with Drizzle ORM
- **Authentication**: Better Auth with social providers (Google, GitHub)
- **Payments**: Stripe integration with subscription and one-time payments
- **UI**: Radix UI components with TailwindCSS
- **State Management**: Zustand for client-side state
- **Internationalization**: next-intl with English and Chinese locales
- **Content**: Fumadocs for documentation and MDX for content
- **Code Quality**: Biome for formatting and linting
### Key Directory Structure
- `src/app/` - Next.js app router with internationalized routing
- `src/components/` - Reusable React components organized by feature
- `src/lib/` - Utility functions and shared code
- `src/db/` - Database schema and migrations
- `src/actions/` - Server actions for API operations
- `src/stores/` - Zustand state management
- `src/hooks/` - Custom React hooks
- `src/config/` - Application configuration files
- `src/i18n/` - Internationalization setup
- `src/mail/` - Email templates and mail functionality
- `src/payment/` - Stripe payment integration
- `src/credits/` - Credit system implementation
- `content/` - MDX content files for docs and blog
- `messages/` - Translation files (en.json, zh.json) for internationalization
### Authentication & User Management
- Uses Better Auth with PostgreSQL adapter
- Supports email/password and social login (Google, GitHub)
- Includes user management, email verification, and password reset
- Admin plugin for user management and banning
- Automatic newsletter subscription on user creation
### Payment System
- Stripe integration for subscriptions and one-time payments
- Three pricing tiers: Free, Pro (monthly/yearly), and Lifetime
- Credit system with packages for pay-per-use features
- Customer portal for subscription management
### Feature Modules
- **Blog**: MDX-based blog with pagination and categories
- **Docs**: Fumadocs-powered documentation
- **AI Features**: Image generation with multiple providers (OpenAI, Replicate, etc.)
- **Newsletter**: Email subscription system
- **Analytics**: Multiple analytics providers support
- **Storage**: S3 integration for file uploads
### Development Workflow
1. Use TypeScript for all new code
2. Follow Biome formatting rules (single quotes, trailing commas)
3. Write server actions in `src/actions/`
4. Use Zustand for client-side state management
5. Implement database changes through Drizzle migrations
6. Use Radix UI components for consistent UI
7. Follow the established directory structure
8. Use proper error handling with error.tsx and not-found.tsx
9. Leverage Next.js 15 features like Server Actions
10. Use `next-safe-action` for secure form submissions
### Configuration
- Main config in `src/config/website.tsx`
- Environment variables template in `env.example`
- Database config in `drizzle.config.ts`
- Biome config in `biome.json` with specific ignore patterns
- TypeScript config with path aliases (@/* for src/*)
### Testing and Quality
- Use Biome for linting and formatting
- TypeScript for type safety
- Environment variables for configuration
- Proper error boundaries and not-found pages
- Zod for runtime validation
## Important Notes
- The project uses pnpm as the package manager
- Database schema is in `src/db/schema.ts` with auth, payment, and credit tables
- Email templates are in `src/mail/templates/`
- The app supports both light and dark themes
- Content is managed through MDX files in the `content/` directory
- The project includes comprehensive internationalization support

View File

@ -1,62 +0,0 @@
# syntax=docker/dockerfile:1
FROM node:20-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies
COPY package.json pnpm-lock.yaml* ./
# Copy config files needed for fumadocs-mdx postinstall
COPY source.config.ts ./
COPY content ./content
RUN npm install -g pnpm && pnpm i --frozen-lockfile
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN npm install -g pnpm \
&& DOCKER_BUILD=true pnpm build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD ["node", "server.js"]

41
LICENSE
View File

@ -1,41 +0,0 @@
MkSaaS License
Personal, Team, or Organization License
MkSaaS grants you an ongoing, non-exclusive license to use the software components and templates included in the SaaS Starter Kit.
The license permits usage by a single individual, team, or organization (the Licensee) and does not transfer to additional individuals, teams, or organizations without explicit permission.
You can:
- Use MkSaaS to create unlimited end products.
- Modify MkSaaS components to create derivative works, subject to this license.
- Use MkSaaS to create projects for unlimited clients.
- Use MkSaaS to create end products sold to end users.
- Use MkSaaS to build and run SaaS applications where end users interact with your end product.
You cannot:
- Redistribute MkSaaSs components or templates, even if modified, separately from an end product.
- Share your access to MkSaaS with anyone outside your team or organization without explicit permission.
- Use MkSaaS to create products that compete with MkSaaS or provide a SaaS starter kit in conflict with MkSaaSs business.
Example Usage
Examples of permitted usage:
- Creating personal, team, or organizational websites or applications.
- Building commercial SaaS applications or web apps for clients.
Examples of prohibited usage:
- Creating a repository of MkSaaS (components) and sharing or selling it.
- Making a derivative product (e.g. starter kit) and offering it for sale or free.
Enforcement and Liability
MkSaaS reserves the right to revoke licenses in case of a material breach of this agreement. The liability of MkSaaS is limited to the refund of the license fee. This agreement is governed by the laws of Switzerland.
Questions?
Unsure if your use case is covered by the license? Email us at support@MkSaaS.com with your questions.

View File

@ -1,46 +1,36 @@
# MkSaaS
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
Make AI SaaS in a weekend.
## Getting Started
The complete Next.js boilerplate for building profitable SaaS, with auth, payments, i18n, newsletter, dashboard, blog, docs, blocks, themes, SEO and more.
First, run the development server:
## Author
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
This project is created by [Fox](https://x.com/indie_maker_fox), the founder of [MkSaaS](https://mksaas.com) and [Mkdirs](https://mkdirs.com). The official X account for [MkSaaS](https://mksaas.com) is [@mksaascom](https://x.com/mksaascom), you can follow this account for the updates about MkSaaS.
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
## Documentation
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
The documentation is available on the [website](https://mksaas.com/docs). It includes guides, tutorials, and detailed explanations of the code. I designed it to be as beginner-friendly as possible, so you can start making money from day one.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
If you found anything that could be improved, please let me know.
## Learn More
## Links
To learn more about Next.js, take a look at the following resources:
- 🔥 website: [mksaas.com](https://mksaas.com)
- 🌐 demo: [demo.mksaas.com](https://demo.mksaas.com)
- 📚 documentation: [mksaas.com/docs](https://mksaas.com/docs)
- 🗓️ roadmap: [mksaas roadmap](https://mksaas.link/roadmap)
- 👨‍💻 discord: [mksaas.link/discord](https://mksaas.link/discord)
- 📹 video: [mksaas.link/youtube](https://mksaas.link/youtube)
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
## Repositories
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
By default, you should have access to all 5 repositories. If you find that youre unable to access any of them, please dont hesitate to reach out to me, and Ill assist you in resolving the issue.
## Deploy on Vercel
- [mksaas-template (ready)](https://github.com/MkSaaSHQ/mksaas-template): https://demo.mksaas.com
- [mksaas-blog (ready)](https://github.com/MkSaaSHQ/mksaas-blog): https://mksaas.me
- [mksaas-haitang (ready)](https://github.com/MkSaaSHQ/mksaas-haitang): https://haitang.app
- [mksaas-outfit (ready)](https://github.com/MkSaaSHQ/mksaas-outfit)
- [mksaas-app (WIP)](https://github.com/MkSaaSHQ/mksaas-app): https://mksaas.app
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
## Notice
> If you have any questions, please [submit an issue](https://github.com/MkSaaSHQ/mksaas-template/issues/new), or contact me at [support@mksaas.com](mailto:support@mksaas.com), or join our [discord community](https://mksaas.link/discord) and ask for help there.
> If you want to receive notifications whenever code changes, please click `Watch` button in the top right.
> When submitting any content to the issues of the repository, please use **English** as the main Language, so that everyone can read it and help you, thank you for your supports.
## License
For any details on the license, please refer to the [License](LICENSE) file.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

View File

@ -9,28 +9,14 @@
"ignoreUnknown": true,
"ignore": [
".next/**",
".open-next/**",
".wrangler/**",
".cursor/**",
".claude/**",
".kiro/**",
".conductor/**",
".vscode/**",
".source/**",
".content-collections/**",
"node_modules/**",
"dist/**",
"build/**",
"src/db/**",
"tailwind.config.ts",
"src/components/ui/*.tsx",
"src/components/magicui/*.tsx",
"src/components/animate-ui/*.tsx",
"src/components/tailark/*.tsx",
"src/components/ai-elements/*.tsx",
"src/app/[[]locale]/preview/**",
"src/payment/types.ts",
"src/credits/types.ts",
"src/types/index.d.ts"
"tailwind.config.ts",
"src/db/schema.ts"
]
},
"formatter": {
@ -38,8 +24,7 @@
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 80,
"formatWithErrors": true,
"useEditorconfig": true
"formatWithErrors": true
},
"organizeImports": {
"enabled": true
@ -49,53 +34,27 @@
"rules": {
"recommended": true,
"suspicious": {
"noSparseArray": "off",
"noArrayIndexKey": "off",
"noExplicitAny": "off",
"noShadowRestrictedNames": "off"
},
"complexity": {
"noForEach": "off"
},
"correctness": {
"useExhaustiveDependencies": "off"
"noSparseArray": "off"
},
"style": {
"useTemplate": "off",
"noNonNullAssertion": "off",
"useShorthandArrayType": "off",
"useNodejsImportProtocol": "off"
"useShorthandArrayType": "off"
},
"a11y": {
"useValidAnchor": "off",
"noSvgWithoutTitle": "off",
"useKeyWithClickEvents": "off"
"useValidAnchor": "off"
}
},
"ignore": [
".next/**",
".open-next/**",
".wrangler/**",
".cursor/**",
".claude/**",
".conductor/**",
".kiro/**",
".vscode/**",
".source/**",
".content-collections/**",
"node_modules/**",
"dist/**",
"build/**",
"src/db/**",
"tailwind.config.ts",
"src/components/ui/*.tsx",
"src/components/magicui/*.tsx",
"src/components/animate-ui/*.tsx",
"src/components/tailark/*.tsx",
"src/components/ai-elements/*.tsx",
"src/app/[[]locale]/preview/**",
"src/payment/types.ts",
"src/credits/types.ts",
"src/types/index.d.ts"
"tailwind.config.ts",
"src/db/schema.ts"
]
},
"javascript": {

7483
cloudflare-env.d.ts vendored

File diff suppressed because it is too large Load Diff

342
content-collections.ts Normal file
View File

@ -0,0 +1,342 @@
import { defineCollection, defineConfig } from "@content-collections/core";
import { compileMDX } from "@content-collections/mdx";
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import rehypePrettyCode, { Options } from 'rehype-pretty-code';
import rehypeSlug from 'rehype-slug';
import { codeImport } from 'remark-code-import';
import remarkGfm from 'remark-gfm';
import { createHighlighter } from 'shiki';
import path from "path";
import { LOCALES, DEFAULT_LOCALE } from "@/i18n/routing";
import { visit } from 'unist-util-visit';
/**
* Content Collections documentation
* 1. https://www.content-collections.dev/docs/quickstart/next
* 2. https://www.content-collections.dev/docs/configuration
* 3. https://www.content-collections.dev/docs/transform#join-collections
*/
/**
* Blog Author collection
*
* Authors are identified by their slug across all languages
*/
export const authors = defineCollection({
name: 'author',
directory: 'content',
include: '**/author/*.mdx',
schema: (z) => ({
slug: z.string(),
name: z.string(),
avatar: z.string(),
locale: z.enum(LOCALES as [string, ...string[]]).optional()
}),
transform: async (data, context) => {
// Determine the locale from the file path or use the provided locale
const pathParts = data._meta.path.split(path.sep);
const localeFromPath = LOCALES.includes(pathParts[0]) ? pathParts[0] : null;
const locale = data.locale || localeFromPath || DEFAULT_LOCALE;
return {
...data,
locale,
};
}
});
/**
* Blog Category collection
*
* Categories are identified by their slug across all languages
*/
export const categories = defineCollection({
name: 'category',
directory: 'content',
include: '**/category/*.mdx',
schema: (z) => ({
slug: z.string(),
name: z.string(),
description: z.string(),
locale: z.enum(LOCALES as [string, ...string[]]).optional()
}),
transform: async (data, context) => {
// Determine the locale from the file path or use the provided locale
const pathParts = data._meta.path.split(path.sep);
const localeFromPath = LOCALES.includes(pathParts[0]) ? pathParts[0] : null;
const locale = data.locale || localeFromPath || DEFAULT_LOCALE;
return {
...data,
locale
};
}
});
/**
* Blog Post collection
*
* 1. For a blog post at content/en/blog/first-post.mdx:
* locale: en
* slug: /blog/first-post
* slugAsParams: first-post
*
* 2. For a blog post at content/zh/blog/first-post.mdx:
* locale: zh
* slug: /blog/first-post
* slugAsParams: first-post
*/
export const posts = defineCollection({
name: 'post',
directory: 'content',
include: '**/blog/**/*.mdx',
schema: (z) => ({
title: z.string(),
description: z.string(),
image: z.string(),
date: z.string().datetime(),
published: z.boolean().default(true),
categories: z.array(z.string()),
author: z.string(),
locale: z.enum(LOCALES as [string, ...string[]]).optional()
}),
transform: async (data, context) => {
const body = await compileWithCodeCopy(context, data);
// Determine the locale from the file path or use the provided locale
const pathParts = data._meta.path.split(path.sep);
const localeFromPath = LOCALES.includes(pathParts[0]) ? pathParts[0] : null;
const locale = data.locale || localeFromPath || DEFAULT_LOCALE;
// Find the author by matching slug
const blogAuthor = context
.documents(authors)
.find((a) => a.slug === data.author && a.locale === locale) ||
context
.documents(authors)
.find((a) => a.slug === data.author);
// Find categories by matching slug
const blogCategories = data.categories.map(categorySlug => {
// Try to find a category with matching slug and locale
const category = context
.documents(categories)
.find(c => c.slug === categorySlug && c.locale === locale) ||
context
.documents(categories)
.find(c => c.slug === categorySlug);
return category;
}).filter(Boolean); // Remove null values
// Create a slug without the locale in the path
let slugPath = data._meta.path;
if (localeFromPath) {
// Remove the locale from the path for the slug
const pathWithoutLocale = pathParts.slice(1).join(path.sep);
slugPath = pathWithoutLocale;
}
// Create slugAsParams without the locale
const slugParamsParts = slugPath.split(path.sep).slice(1);
const slugAsParams = slugParamsParts.join('/');
return {
...data,
locale,
author: blogAuthor,
categories: blogCategories,
slug: `/${slugPath}`,
slugAsParams,
body: {
raw: data.content,
code: body
}
};
}
});
/**
* Pages collection for policy pages like privacy-policy, terms-of-service, etc.
*
* 1. For a page at content/en/pages/privacy-policy.md:
* locale: en
* slug: /pages/privacy-policy
* slugAsParams: privacy-policy
*
* 2. For a page at content/zh/pages/privacy-policy.md:
* locale: zh
* slug: /pages/privacy-policy
* slugAsParams: privacy-policy
*/
export const pages = defineCollection({
name: 'page',
directory: 'content',
include: '**/pages/**/*.{md,mdx}',
schema: (z) => ({
title: z.string(),
description: z.string(),
date: z.string().datetime(),
published: z.boolean().default(true),
locale: z.enum(LOCALES as [string, ...string[]]).optional()
}),
transform: async (data, context) => {
const body = await compileWithCodeCopy(context, data);
// Determine the locale from the file path or use the provided locale
const pathParts = data._meta.path.split(path.sep);
const localeFromPath = LOCALES.includes(pathParts[0]) ? pathParts[0] : null;
const locale = data.locale || localeFromPath || DEFAULT_LOCALE;
// Create a slug without the locale in the path
let slugPath = data._meta.path;
if (localeFromPath) {
// Remove the locale from the path for the slug
const pathWithoutLocale = pathParts.slice(1).join(path.sep);
slugPath = pathWithoutLocale;
}
// Create slugAsParams without the locale
const slugParamsParts = slugPath.split(path.sep).slice(1);
const slugAsParams = slugParamsParts.join('/');
return {
...data,
locale,
slug: `/${slugPath}`,
slugAsParams,
body: {
raw: data.content,
code: body
}
};
}
});
/**
* Releases collection for changelog
*
* 1. For a release at content/en/release/v1-0-0.md:
* locale: en
* slug: /release/v1-0-0
* slugAsParams: v1-0-0
*
* 2. For a release at content/zh/release/v1-0-0.md:
* locale: zh
* slug: /release/v1-0-0
* slugAsParams: v1-0-0
*/
export const releases = defineCollection({
name: 'release',
directory: 'content',
include: '**/release/**/*.{md,mdx}',
schema: (z) => ({
title: z.string(),
description: z.string(),
date: z.string().datetime(),
version: z.string(),
published: z.boolean().default(true),
locale: z.enum(LOCALES as [string, ...string[]]).optional()
}),
transform: async (data, context) => {
const body = await compileWithCodeCopy(context, data);
// Determine the locale from the file path or use the provided locale
const pathParts = data._meta.path.split(path.sep);
const localeFromPath = LOCALES.includes(pathParts[0]) ? pathParts[0] : null;
const locale = data.locale || localeFromPath || DEFAULT_LOCALE;
// Create a slug without the locale in the path
let slugPath = data._meta.path;
if (localeFromPath) {
// Remove the locale from the path for the slug
const pathWithoutLocale = pathParts.slice(1).join(path.sep);
slugPath = pathWithoutLocale;
}
// Create slugAsParams without the locale
const slugParamsParts = slugPath.split(path.sep).slice(1);
const slugAsParams = slugParamsParts.join('/');
return {
...data,
locale,
slug: `/${slugPath}`,
slugAsParams,
body: {
raw: data.content,
code: body
}
};
}
});
const prettyCodeOptions: Options = {
theme: 'github-dark',
getHighlighter: (options) =>
createHighlighter({
...options
}),
onVisitLine(node) {
// Prevent lines from collapsing in `display: grid` mode, and allow empty
// lines to be copy/pasted
if (node.children.length === 0) {
node.children = [{ type: 'text', value: ' ' }];
}
},
onVisitHighlightedLine(node) {
if (!node.properties.className) {
node.properties.className = [];
}
node.properties.className.push('line--highlighted');
},
onVisitHighlightedChars(node) {
if (!node.properties.className) {
node.properties.className = [];
}
node.properties.className = ['word--highlighted'];
}
};
const compileWithCodeCopy = async (
context: any,
data: any,
options: {
remarkPlugins?: any[];
rehypePlugins?: any[];
} = {}
) => {
return await compileMDX(context, data, {
...options,
remarkPlugins: [
remarkGfm,
codeImport,
...(options.remarkPlugins || [])
],
rehypePlugins: [
rehypeSlug,
[rehypePrettyCode, prettyCodeOptions],
// add __rawString__ to pre element
() => (tree) => {
visit(tree, (node) => {
if (node?.type === "element" && node?.tagName === "pre") {
const [codeEl] = node.children;
if (codeEl.tagName !== "code") return;
// add __rawString__ as a property that will be passed to the React component
if (!node.properties) {
node.properties = {};
}
node.properties.__rawString__ = codeEl.children?.[0]?.value;
}
});
},
rehypeAutolinkHeadings,
...(options.rehypePlugins || [])
]
});
};
export default defineConfig({
collections: [authors, categories, posts, pages, releases]
});

View File

@ -1,4 +0,0 @@
---
name: Fox
avatar: /images/avatars/fox.png
---

View File

@ -1,4 +0,0 @@
---
name: Fox
avatar: /images/avatars/fox.png
---

View File

@ -1,78 +0,0 @@
---
title: Comparisons
description: How is Fumadocs different from other existing frameworks?
image: /images/blog/post-2.png
date: "2025-03-22"
published: true
categories: [news, company]
author: fox
---
## Nextra
Fumadocs is highly inspired by Nextra. For example, the Routing Conventions. That is why
`meta.json` also exists in Fumadocs.
Nextra is more opinionated than Fumadocs. Fumadocs is accelerated by App Router. As a result, It provides many server-side functions, and you have to
configure things manually compared to simply editing a configuration file.
Fumadocs works great if you want more control over everything, such as
adding it to an existing codebase or implementing advanced routing.
### Feature Table
| Feature | Fumadocs | Nextra |
| ------------------- | ------------ | ------------------------- |
| Static Generation | Yes | Yes |
| Cached | Yes | Yes |
| Light/Dark Mode | Yes | Yes |
| Syntax Highlighting | Yes | Yes |
| Table of Contents | Yes | Yes |
| Full-text Search | Yes | Yes |
| i18n | Yes | Yes |
| Last Git Edit Time | Yes | Yes |
| Page Icons | Yes | Yes, via `_meta.js` files |
| RSC | Yes | Yes |
| Remote Source | Yes | Yes |
| SEO | Via Metadata | Yes |
| Built-in Components | Yes | Yes |
| RTL Layout | Yes | Yes |
### Additional Features
Features supported via 3rd party libraries like [TypeDoc](https://typedoc.org) will not be listed here.
| Feature | Fumadocs | Nextra |
| -------------------------- | -------- | ------ |
| OpenAPI Integration | Yes | No |
| TypeScript Docs Generation | Yes | No |
| TypeScript Twoslash | Yes | Yes |
## Mintlify
Mintlify is a documentation service, as compared to Fumadocs, it offers a free tier but isn't completely free and open source.
Fumadocs is not as powerful as Mintlify, for example, the OpenAPI integration of Mintlify.
As the creator of Fumadocs, I wouldn't recommend switching to Fumadocs from Mintlify if you're satisfied with the current way you build docs.
However, I believe Fumadocs is a suitable tool for all Next.js developers who want to have elegant docs.
## Docusaurus
Docusaurus is a powerful framework based on React.js. It offers many cool
features with plugins and custom themes.
### Better DX
Since Fumadocs is built on the top of Next.js, you'll have to start the Next.js dev
server every time to review changes, and initial boilerplate code is relatively more
compared to Docusaurus.
For a simple docs, Docusaurus might be a better choice if you don't need any Next.js specific functionality.
However, when you want to use Next.js, or seek extra customizability like tuning default UI components, Fumadocs could be a better choice.
### Plugins
You can easily achieve many things with plugins, their ecosystem is indeed larger and maintained by many contributors.
In comparison, the flexibility of Fumadocs allows you to implement them on your own, it may take longer to tune it to your satisfaction.

View File

@ -1,72 +0,0 @@
---
title: 对比
description: Fumadocs 与其他现有框架有何不同?
image: /images/blog/post-2.png
date: "2025-03-22"
published: true
categories: [news, company]
author: fox
---
## Nextra
Fumadocs 深受 Nextra 启发。例如,路由约定。这就是为什么 Fumadocs 中也存在 `meta.json`。
Nextra 比 Fumadocs 更加固执己见。Fumadocs 由 App Router 加速。因此,它提供了许多服务器端功能,与简单编辑配置文件相比,您必须手动配置一些内容。
如果您想要对一切都有更多的控制比如将其添加到现有代码库或实现高级路由Fumadocs 会表现得很出色。
### 功能表
| 功能 | Fumadocs | Nextra |
| ------------------- | ------------ | ------------------------- |
| 静态生成 | 是 | 是 |
| 缓存 | 是 | 是 |
| 明/暗模式 | 是 | 是 |
| 语法高亮 | 是 | 是 |
| 目录 | 是 | 是 |
| 全文搜索 | 是 | 是 |
| 国际化 | 是 | 是 |
| 最后 Git 编辑时间 | 是 | 是 |
| 页面图标 | 是 | 是,通过 `_meta.js` 文件 |
| RSC | 是 | 是 |
| 远程源 | 是 | 是 |
| SEO | 通过元数据 | 是 |
| 内置组件 | 是 | 是 |
| RTL 布局 | 是 | 是 |
### 附加功能
通过第三方库支持的功能(如 [TypeDoc](https://typedoc.org))不会在此列出。
| 功能 | Fumadocs | Nextra |
| -------------------------- | -------- | ------ |
| OpenAPI 集成 | 是 | 否 |
| TypeScript 文档生成 | 是 | 否 |
| TypeScript Twoslash | 是 | 是 |
## Mintlify
Mintlify 是一项文档服务,与 Fumadocs 相比,它提供免费套餐,但并非完全免费和开源。
Fumadocs 不如 Mintlify 强大,例如 Mintlify 的 OpenAPI 集成。
作为 Fumadocs 的创建者,如果您对当前构建文档的方式感到满意,我不建议从 Mintlify 切换到 Fumadocs。
然而,我相信 Fumadocs 是所有想要拥有优雅文档的 Next.js 开发者的合适工具。
## Docusaurus
Docusaurus 是一个基于 React.js 的强大框架。它通过插件和自定义主题提供了许多酷炫的功能。
### 更好的开发者体验
由于 Fumadocs 构建在 Next.js 之上,您每次都必须启动 Next.js 开发服务器来查看更改,并且相对于 Docusaurus初始样板代码较多。
对于简单的文档,如果您不需要任何特定于 Next.js 的功能Docusaurus 可能是更好的选择。
然而,当您想要使用 Next.js或寻求更多的可定制性如调整默认 UI 组件时Fumadocs 可能是更好的选择。
### 插件
您可以通过插件轻松实现许多功能,他们的生态系统确实更大,并由许多贡献者维护。
相比之下Fumadocs 的灵活性允许您自己实现它们,可能需要更长的时间来调整它以达到您的满意度。

View File

@ -1,278 +0,0 @@
---
title: Quick Start
description: Getting Started with Fumadocs
image: /images/blog/post-8.png
date: "2025-03-28"
published: true
categories: [company, news]
author: mksaas
---
## Introduction
Fumadocs <span className='text-fd-muted-foreground text-sm'>(Foo-ma docs)</span> is a **documentation framework** based on Next.js, designed to be fast, flexible,
and composes seamlessly into Next.js App Router.
Fumadocs has different parts:
<Cards>
<Card icon={<CpuIcon className="text-purple-300" />} title='Fumadocs Core'>
Handles most of the logic, including document search, content source adapters, and Markdown extensions.
</Card>
<Card icon={<PanelsTopLeft className="text-blue-300" />} title='Fumadocs UI'>
The default theme of Fumadocs offers a beautiful look for documentation sites and interactive components.
</Card>
<Card icon={<Database />} title='Content Source'>
The source of your content, can be a CMS or local data layers like [Content Collections](https://www.content-collections.dev) and [Fumadocs MDX](/docs/mdx), the official content source.
</Card>
<Card icon={<Terminal />} title='Fumadocs CLI'>
A command line tool to install UI components and automate things, useful for customizing layouts.
</Card>
</Cards>
<Callout title="Want to learn more?">
Read our in-depth [What is Fumadocs](/docs/what-is-fumadocs) introduction.
</Callout>
### Terminology
**Markdown/MDX:** Markdown is a markup language for creating formatted text. Fumadocs supports Markdown and MDX (superset of Markdown) out-of-the-box.
Although not required, some basic knowledge of Next.js App Router would be useful for further customisations.
## Automatic Installation
A minimum version of Node.js 18 required, note that Node.js 23.1 might have problems with Next.js production build.
<Tabs groupId='package-manager' persist items={['npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm create fumadocs-app
```
```bash tab="pnpm"
pnpm create fumadocs-app
```
```bash tab="yarn"
yarn create fumadocs-app
```
```bash tab="bun"
bun create fumadocs-app
```
</Tabs>
It will ask you the framework and content source to use, a new fumadocs app should be initialized. Now you can start hacking!
<Callout title='From Existing Codebase?'>
You can follow the [Manual Installation](/docs/manual-installation) guide to get started.
</Callout>
### Enjoy!
Create your first MDX file in the docs folder.
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Yo what's up
```
Run the app in development mode and see http://localhost:3000/docs.
```mdx
npm run dev
```
## Explore
In the project, you can see:
- `lib/source.ts`: Code for content source adapter, [`loader()`](/docs/headless/source-api) provides an interface to interact with your content source, and assigns URL to your pages.
- `app/layout.config.tsx`: Shared options for layouts, optional but preferred to keep.
| Route | Description |
| ------------------------- | ------------------------------------------------------ |
| `app/(home)` | The route group for your landing page and other pages. |
| `app/docs` | The documentation layout and pages. |
| `app/api/search/route.ts` | The Route Handler for search. |
### Writing Content
For authoring docs, make sure to read:
<Cards>
<Card href="/docs/markdown" title="Markdown">
Fumadocs has some additional features for authoring content too.
</Card>
<Card href="/docs/navigation" title="Navigation">
Learn how to customise navigation links/sidebar items.
</Card>
</Cards>
### Content Source
Content source handles all your content, like compiling Markdown files and validating frontmatter.
<Tabs items={['Fumadocs MDX', 'Custom Source']}>
<Tab value='Fumadocs MDX'>
Read the [Introduction](/docs/mdx) to learn how it handles your content.
A `source.config.ts` config file has been included, you can customise different options like frontmatter schema.
</Tab>
<Tab value='Custom Source'>
Fumadocs is not Markdown-exclusive. For other sources like Sanity, you can build a [custom content source](/docs/headless/custom-source).
</Tab>
</Tabs>
### Customise UI
See [Customisation Guide](/docs/customisation).
## FAQ
Some common questions you may encounter.
<Accordions>
<Accordion id='fix-monorepo-styling' title="How to fix stylings not being applied in Monorepo?">
Sometimes, `fumadocs-ui` is not installed in the workspace of your Tailwind CSS configuration file. (e.g. a monorepo setup).
You have to ensure the `fumadocs-ui` package is scanned by Tailwind CSS, and give a correct relative path to `@source`.
For example, add `../../` to point to the `node_modules` folder in root workspace.
```css
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* [!code --] */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
/* [!code ++] */
@source '../../../node_modules/fumadocs-ui/dist/**/*.js';
```
</Accordion>
<Accordion id='change-base-url' title="How to change the base route of /docs?">
You can change the base route of docs (e.g. from `/docs/page` to `/info/page`).
Since Fumadocs uses Next.js App Router, you can simply rename the route:
<Files>
<Folder name="app/docs" defaultOpen className="opacity-50" disabled>
<File name="layout.tsx" />
</Folder>
<Folder name="app/info" defaultOpen>
<File name="layout.tsx" />
</Folder>
</Files>
And tell Fumadocs to use the new route in `source.ts`:
```ts title="lib/source.ts"
import { loader } from 'fumadocs-core/source';
export const source = loader({
baseUrl: '/info',
// other options
});
```
</Accordion>
<Accordion id='dynamic-route' title="It uses Dynamic Route, will it be poor in performance?">
Next.js turns dynamic route into static routes when `generateStaticParams` is configured.
Hence, it is as fast as static pages.
You can enable Static Exports on Next.js to get a static build output. (Notice that Route Handler doesn't work with static export, you have to configure static search)
</Accordion>
<Accordion id='custom-layout-docs-page' title='How to create a page in /docs without docs layout?'>
Same as managing layouts in Next.js App Router, remove the original MDX file from content directory (`/content/docs`).
This ensures duplicated pages will not cause errors.
Now, You can add the page to another route group, which isn't a descendant of docs layout.
For example, under your `app` folder:
<Files>
<File name="(home)/docs/page.tsx" />
<Folder name="docs">
<File name="layout.tsx" />
<File name="[[...slug]]/page.tsx" />
</Folder>
</Files>
will replace the `/docs` page with your `page.tsx`.
</Accordion>
<Accordion id='multi-versions' title="How to implement docs with multi-version?">
Use a separate deployment for each version.
On Vercel, this can be done by creating another branch for a specific version on your GitHub repository.
To link to the sites of other versions, use the Links API or a custom navigation component.
</Accordion>
<Accordion id='multi-docs' title="How to implement multi-docs?">
We recommend to use [Sidebar Tabs](/docs/navigation/sidebar#sidebar-tabs).
</Accordion>
</Accordions>
## Learn More
New to here? Don't worry, we are welcome for your questions.
If you find anything confusing, please give your feedback on [Github Discussion](https://github.com/fuma-nama/fumadocs/discussions)!
<Cards>
<Card
href="/docs/static-export"
title="Configure Static Export"
description="Learn how to enable static export on your docs"
/>
<Card
href="/docs/search"
title="Customise Search"
description="Learn how to customise document search"
/>
<Card
href="/docs/theme"
title="Theming"
description="Add themes to Fumadocs UI"
/>
<Card
href="/docs/components"
title="Components"
description="See all available components to enhance your docs"
/>
</Cards>

View File

@ -1,253 +0,0 @@
---
title: 快速入门
description: Fumadocs 入门指南
image: /images/blog/post-8.png
date: "2025-03-28"
published: true
categories: [company, news]
author: mksaas
---
## 简介
Fumadocs <span className='text-fd-muted-foreground text-sm'>(Foo-ma docs)</span> 是一个基于 Next.js 的**文档框架**,设计为快速、灵活,
并无缝集成到 Next.js App Router 中。
Fumadocs 由不同部分组成:
<Cards>
<Card icon={<CpuIcon className="text-purple-300" />} title='Fumadocs Core'>
处理大部分逻辑,包括文档搜索、内容源适配器和 Markdown 扩展。
</Card>
<Card icon={<PanelsTopLeft className="text-blue-300" />} title='Fumadocs UI'>
Fumadocs 的默认主题为文档站点提供了美观的外观和交互式组件。
</Card>
<Card icon={<Database />} title='Content Source'>
您内容的来源,可以是 CMS 或本地数据层,如 [Content Collections](https://www.content-collections.dev) 和 [Fumadocs MDX](/docs/mdx),即官方内容源。
</Card>
<Card icon={<Terminal />} title='Fumadocs CLI'>
一个命令行工具,用于安装 UI 组件和自动化操作,对于自定义布局非常有用。
</Card>
</Cards>
<Callout title="想了解更多?">
阅读我们深入的 [什么是 Fumadocs](/docs/what-is-fumadocs) 介绍。
</Callout>
### 术语
**Markdown/MDX:** Markdown 是一种用于创建格式化文本的标记语言。Fumadocs 默认支持 Markdown 和 MDXMarkdown 的超集)。
虽然不是必需的,但对 Next.js App Router 的基本了解对于进一步的自定义会很有帮助。
## 自动安装
需要 Node.js 18 或更高版本,请注意 Node.js 23.1 可能在 Next.js 生产构建中存在问题。
<Tabs groupId='package-manager' persist items={['npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm create fumadocs-app
```
```bash tab="pnpm"
pnpm create fumadocs-app
```
```bash tab="yarn"
yarn create fumadocs-app
```
```bash tab="bun"
bun create fumadocs-app
```
</Tabs>
它会询问您要使用的框架和内容源,随后将初始化一个新的 fumadocs 应用程序。现在您可以开始动手了!
<Callout title='从现有代码库开始?'>
您可以按照 [手动安装](/docs/manual-installation) 指南开始。
</Callout>
### 尽情使用!
在 docs 文件夹中创建您的第一个 MDX 文件。
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Yo what's up
```
在开发模式下运行应用程序并查看 http://localhost:3000/docs。
```mdx
npm run dev
```
## 探索
在项目中,您可以看到:
- `lib/source.ts`:内容源适配器的代码,[`loader()`](/docs/headless/source-api) 提供了与内容源交互的接口,并为您的页面分配 URL。
- `app/layout.config.tsx`:布局的共享选项,可选但建议保留。
| 路由 | 描述 |
| ------------------------- | -------------------------------------- |
| `app/(home)` | 您的登陆页面和其他页面的路由组。 |
| `app/docs` | 文档布局和页面。 |
| `app/api/search/route.ts` | 搜索的路由处理器。 |
### 编写内容
对于编写文档,请务必阅读:
<Cards>
<Card href="/docs/markdown" title="Markdown">
Fumadocs 还有一些额外的内容创作功能。
</Card>
<Card href="/docs/navigation" title="Navigation">
了解如何自定义导航链接/侧边栏项目。
</Card>
</Cards>
### 内容源
内容源处理您的所有内容,例如编译 Markdown 文件和验证前言。
<Tabs items={['Fumadocs MDX', 'Custom Source']}>
<Tab value='Fumadocs MDX'>
阅读 [介绍](/docs/mdx) 了解它如何处理您的内容。
项目中已包含 `source.config.ts` 配置文件,您可以自定义不同的选项,如前言模式。
</Tab>
<Tab value='Custom Source'>
Fumadocs 不仅限于 Markdown。对于其他源如 Sanity您可以构建 [自定义内容源](/docs/headless/custom-source)。
</Tab>
</Tabs>
### 自定义 UI
请参阅 [自定义指南](/docs/customisation)。
## 常见问题
您可能遇到的一些常见问题。
<Accordions>
<Accordion id='fix-monorepo-styling' title="如何修复 Monorepo 中样式不应用的问题?">
有时,`fumadocs-ui` 没有安装在您的 Tailwind CSS 配置文件的工作区中(例如,在 monorepo 设置中)。
您必须确保 Tailwind CSS 扫描 `fumadocs-ui` 包,并为 `@source` 提供正确的相对路径。
例如,添加 `../../` 指向根工作区中的 `node_modules` 文件夹。
```css
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* [!code --] */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
/* [!code ++] */
@source '../../../node_modules/fumadocs-ui/dist/**/*.js';
```
</Accordion>
<Accordion id='change-base-url' title="如何更改 /docs 的基本路由?">
您可以更改文档的基本路由(例如,从 `/docs/page` 更改为 `/info/page`)。
由于 Fumadocs 使用 Next.js App Router您可以简单地重命名路由
<Files>
<Folder name="app/docs" defaultOpen className="opacity-50" disabled>
<File name="layout.tsx" />
</Folder>
<Folder name="app/info" defaultOpen>
<File name="layout.tsx" />
</Folder>
</Files>
并在 `source.ts` 中告诉 Fumadocs 使用新的路由:
```ts title="lib/source.ts"
import { loader } from 'fumadocs-core/source';
export const source = loader({
baseUrl: '/info',
// other options
});
```
</Accordion>
<Accordion id='dynamic-route' title="它使用动态路由,性能会很差吗?">
当配置了 `generateStaticParams` 时Next.js 会将动态路由转换为静态路由。
因此,它与静态页面一样快。
您可以在 Next.js 上启用静态导出,获得静态构建输出。(请注意,路由处理器不适用于静态导出,您必须配置静态搜索)
</Accordion>
<Accordion id='custom-layout-docs-page' title='如何在 /docs 中创建没有文档布局的页面?'>
与在 Next.js App Router 中管理布局相同,从内容目录(`/content/docs`)中删除原始 MDX 文件。
这确保重复的页面不会导致错误。
现在,您可以将页面添加到另一个路由组,该组不是文档布局的后代。
例如,在您的 `app` 文件夹下:
<Files>
<File name="(home)/docs/page.tsx" />
<Folder name="docs">
<File name="layout.tsx" />
<File name="[[...slug]]/page.tsx" />
</Folder>
</Files>
将用您的 `page.tsx` 替换 `/docs` 页面。
</Accordion>
<Accordion id='multi-versions' title="如何实现多版本文档?">
为每个版本使用单独的部署。
在 Vercel 上,可以通过在 GitHub 存储库中为特定版本创建另一个分支来实现。
要链接到其他版本的站点,请使用 Links API 或自定义导航组件。
</Accordion>
<Accordion id='multi-docs' title="如何实现多文档?">
我们建议使用 [侧边栏标签](/docs/navigation/sidebar#sidebar-tabs)。
</Accordion>
</Accordions>
## 了解更多
刚来这里?别担心,我们欢迎您的问题。

View File

@ -1,227 +0,0 @@
---
title: Internationalization
description: Support multiple languages in your documentation
image: /images/blog/post-3.png
date: "2025-03-15"
published: true
categories: [company, product]
author: mksaas
---
<Callout title='Before you get started'>
Fumadocs is not a full-powered i18n library, it manages only its own components and utilities.
You can use other libraries like [next-intl](https://github.com/amannn/next-intl) for the rest of your app.
Read the [Next.js Docs](https://nextjs.org/docs/app/building-your-application/routing/internationalization) to learn more about implementing I18n in Next.js.
</Callout>
## Manual Setup
Define the i18n configurations in a file, we will import it with `@/ilb/i18n` in this guide.
{/* <include cwd meta='title="lib/i18n.ts"'>
../../examples/i18n/lib/i18n.ts
</include> */}
Pass it to the source loader.
```ts title="lib/source.ts"
import { i18n } from '@/lib/i18n';
import { loader } from 'fumadocs-core/source';
export const source = loader({
i18n, // [!code highlight]
// other options
});
```
And update Fumadocs UI layout options.
```tsx title="app/layout.config.tsx"
import { i18n } from '@/lib/i18n';
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export function baseOptions(locale: string): BaseLayoutProps {
return {
i18n,
// different props based on `locale`
};
}
```
### Middleware
Create a middleware that redirects users to appropriate locale.
```json doc-gen:file
{
"file": "../../examples/i18n/middleware.ts",
"codeblock": {
"lang": "ts",
"meta": "title=\"middleware.ts\""
}
}
```
See [Middleware](/docs/headless/internationalization#middleware) for customisable options.
> Note that this is optional, you can also use your own middleware or the one provided by i18n libraries.
### Routing
Create a `/app/[lang]` folder, and move all files (e.g. `page.tsx`, `layout.tsx`) from `/app` to the folder.
Wrap the root provider inside `I18nProvider`, and provide available languages & translations to it.
Note that only English translations are provided by default.
```tsx title="app/[lang]/layout.tsx"
import { RootProvider } from 'fumadocs-ui/provider';
import { I18nProvider, type Translations } from 'fumadocs-ui/i18n';
const cn: Partial<Translations> = {
search: 'Translated Content',
// other translations
};
// available languages that will be displayed on UI
// make sure `locale` is consistent with your i18n config
const locales = [
{
name: 'English',
locale: 'en',
},
{
name: 'Chinese',
locale: 'cn',
},
];
export default async function RootLayout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: React.ReactNode;
}) {
const lang = (await params).lang;
return (
<html lang={lang}>
<body>
<I18nProvider
locale={lang}
locales={locales}
translations={{ cn }[lang]}
>
<RootProvider>{children}</RootProvider>
</I18nProvider>
</body>
</html>
);
}
```
### Pass Locale
Pass the locale to Fumadocs in your pages and layouts.
{/* ```tsx title="/app/[lang]/(home)/layout.tsx" tab="Home Layout"
import type { ReactNode } from 'react';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return <HomeLayout {...baseOptions(lang)}>{children}</HomeLayout>;
}
```
```tsx title="/app/[lang]/docs/layout.tsx" tab="Docs Layout"
import type { ReactNode } from 'react';
import { source } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return (
<DocsLayout {...baseOptions(lang)} tree={source.pageTree[lang]}>
{children}
</DocsLayout>
);
}
```
```ts title="page.tsx" tab="Docs Page"
import { source } from '@/lib/source';
export default async function Page({
params,
}: {
params: Promise<{ lang: string; slug?: string[] }>;
}) {
const { slug, lang } = await params;
// get page
source.getPage(slug); // [!code --]
source.getPage(slug, lang); // [!code ++]
// get pages
source.getPages(); // [!code --]
source.getPages(lang); // [!code ++]
}
``` */}
### Search
Configure i18n on your search solution.
- **Built-in Search (Orama):**
For [Supported Languages](https://docs.orama.com/open-source/supported-languages#officially-supported-languages), no further changes are needed.
Otherwise, additional config is required (e.g. Chinese & Japanese). See [Special Languages](/docs/headless/search/orama#special-languages).
- **Cloud Solutions (e.g. Algolia):**
They usually have official support for multilingual.
## Writing Documents
{/* <include>../../shared/page-conventions.i18n.mdx</include> */}
## Navigation
Fumadocs only handles navigation for its own layouts (e.g. sidebar).
For other places, you can use the `useParams` hook to get the locale from url, and attend it to `href`.
```tsx
import Link from 'next/link';
import { useParams } from 'next/navigation';
const { lang } = useParams();
return <Link href={`/${lang}/another-page`}>This is a link</Link>;
```
In addition, the [`fumadocs-core/dynamic-link`](/docs/headless/components/link#dynamic-hrefs) component supports dynamic hrefs, you can use it to attend the locale prefix.
It is useful for Markdown/MDX content.
```mdx title="content.mdx"
import { DynamicLink } from 'fumadocs-core/dynamic-link';
<DynamicLink href="/[lang]/another-page">This is a link</DynamicLink>
```

View File

@ -1,227 +0,0 @@
---
title: 国际化
description: 在您的文档中支持多种语言
image: /images/blog/post-3.png
date: "2025-03-15"
published: true
categories: [company, product]
author: mksaas
---
<Callout title='开始之前'>
Fumadocs 不是一个功能齐全的 i18n 库,它只管理自己的组件和工具。
您可以使用其他库,如 [next-intl](https://github.com/amannn/next-intl),用于应用程序的其余部分。
阅读 [Next.js 文档](https://nextjs.org/docs/app/building-your-application/routing/internationalization),了解更多关于在 Next.js 中实现 I18n 的信息。
</Callout>
## 手动设置
在一个文件中定义 i18n 配置,我们将在本指南中使用 `@/ilb/i18n` 导入它。
{/* <include cwd meta='title="lib/i18n.ts"'>
../../examples/i18n/lib/i18n.ts
</include> */}
将其传递给源加载器。
```ts title="lib/source.ts"
import { i18n } from '@/lib/i18n';
import { loader } from 'fumadocs-core/source';
export const source = loader({
i18n, // [!code highlight]
// other options
});
```
并更新 Fumadocs UI 布局选项。
```tsx title="app/layout.config.tsx"
import { i18n } from '@/lib/i18n';
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export function baseOptions(locale: string): BaseLayoutProps {
return {
i18n,
// different props based on `locale`
};
}
```
### 中间件
创建一个将用户重定向到适当语言环境的中间件。
```json doc-gen:file
{
"file": "../../examples/i18n/middleware.ts",
"codeblock": {
"lang": "ts",
"meta": "title=\"middleware.ts\""
}
}
```
查看[中间件](/docs/headless/internationalization#middleware)了解可自定义选项。
> 请注意,这是可选的,您也可以使用自己的中间件或 i18n 库提供的中间件。
### 路由
创建一个 `/app/[lang]` 文件夹,并将所有文件(例如 `page.tsx`、`layout.tsx`)从 `/app` 移动到该文件夹。
将根提供程序包装在 `I18nProvider` 中,并向其提供可用语言和翻译。
请注意,默认情况下只提供英文翻译。
```tsx title="app/[lang]/layout.tsx"
import { RootProvider } from 'fumadocs-ui/provider';
import { I18nProvider, type Translations } from 'fumadocs-ui/i18n';
const cn: Partial<Translations> = {
search: 'Translated Content',
// other translations
};
// available languages that will be displayed on UI
// make sure `locale` is consistent with your i18n config
const locales = [
{
name: 'English',
locale: 'en',
},
{
name: 'Chinese',
locale: 'cn',
},
];
export default async function RootLayout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: React.ReactNode;
}) {
const lang = (await params).lang;
return (
<html lang={lang}>
<body>
<I18nProvider
locale={lang}
locales={locales}
translations={{ cn }[lang]}
>
<RootProvider>{children}</RootProvider>
</I18nProvider>
</body>
</html>
);
}
```
### 传递区域设置
在您的页面和布局中将区域设置传递给 Fumadocs。
{/* ```tsx title="/app/[lang]/(home)/layout.tsx" tab="Home Layout"
import type { ReactNode } from 'react';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return <HomeLayout {...baseOptions(lang)}>{children}</HomeLayout>;
}
```
```tsx title="/app/[lang]/docs/layout.tsx" tab="Docs Layout"
import type { ReactNode } from 'react';
import { source } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return (
<DocsLayout {...baseOptions(lang)} tree={source.pageTree[lang]}>
{children}
</DocsLayout>
);
}
```
```ts title="page.tsx" tab="Docs Page"
import { source } from '@/lib/source';
export default async function Page({
params,
}: {
params: Promise<{ lang: string; slug?: string[] }>;
}) {
const { slug, lang } = await params;
// get page
source.getPage(slug); // [!code --]
source.getPage(slug, lang); // [!code ++]
// get pages
source.getPages(); // [!code --]
source.getPages(lang); // [!code ++]
}
``` */}
### 搜索
在您的搜索解决方案上配置 i18n。
- **内置搜索 (Orama)**
对于[支持的语言](https://docs.orama.com/open-source/supported-languages#officially-supported-languages),无需进一步更改。
否则,需要额外配置(例如中文和日语)。请参阅[特殊语言](/docs/headless/search/orama#special-languages)。
- **云解决方案(例如 Algolia**
它们通常官方支持多语言。
## 编写文档
{/* <include>../../shared/page-conventions.i18n.mdx</include> */}
## 导航
Fumadocs 只处理其自己的布局(例如侧边栏)的导航。
对于其他地方,您可以使用 `useParams` 钩子从 url 获取区域设置,并将其添加到 `href`。
```tsx
import Link from 'next/link';
import { useParams } from 'next/navigation';
const { lang } = useParams();
return <Link href={`/${lang}/another-page`}>This is a link</Link>;
```
另外,[`fumadocs-core/dynamic-link`](/docs/headless/components/link#dynamic-hrefs) 组件支持动态 hrefs您可以使用它来添加区域设置前缀。
这对于 Markdown/MDX 内容很有用。
```mdx title="content.mdx"
import { DynamicLink } from 'fumadocs-core/dynamic-link';
<DynamicLink href="/[lang]/another-page">This is a link</DynamicLink>
```

View File

@ -1,198 +0,0 @@
---
title: Manual Installation
description: Create a new fumadocs project from scratch.
image: /images/blog/post-4.png
date: "2025-03-14"
published: true
categories: [company, product]
author: mkdirs
---
> Read the [Quick Start](/docs) guide first for basic concept.
## Getting Started
Create a new Next.js application with `create-next-app`, and install required packages.
```mdx
fumadocs-ui fumadocs-core
```
### Content Source
Fumadocs supports different content sources, you can choose one you prefer.
There is a list of officially supported sources:
- [Setup Fumadocs MDX](/docs/mdx)
- [Setup Content Collections](/docs/headless/content-collections)
Make sure to configure the library correctly following their setup guide before continuing, we will import the source adapter using `@/lib/source.ts` in this guide.
### Root Layout
Wrap the entire application inside [Root Provider](/docs/layouts/root-provider), and add required styles to `body`.
```tsx
import { RootProvider } from 'fumadocs-ui/provider';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body
// you can use Tailwind CSS too
style={{
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
}}
>
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}
```
### Styles
Setup Tailwind CSS v4 on your Next.js app, add the following to `global.css`.
```css title="Tailwind CSS"
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* path of `fumadocs-ui` relative to the CSS file */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
```
> It doesn't come with a default font, you may choose one from `next/font`.
### Layout
Create a `app/layout.config.tsx` file to put the shared options for our layouts.
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/layout.config.tsx",
"codeblock": {
"meta": "title=\"app/layout.config.tsx\""
}
}
```
Create a folder `/app/docs` for our docs, and give it a proper layout.
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/layout.tsx",
"codeblock": {
"meta": "title=\"app/docs/layout.tsx\""
}
}
```
> `pageTree` refers to Page Tree, it should be provided by your content source.
### Page
Create a catch-all route `/app/docs/[[...slug]]` for docs pages.
In the page, wrap your content in the [Page](/docs/layouts/page) component.
It may vary depending on your content source. You should configure static rendering with `generateStaticParams` and metadata with `generateMetadata`.
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
### Search
Use the default document search based on Orama.
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
Learn more about [Document Search](/docs/headless/search).
### Done
You can start the dev server and create MDX files.
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Introduction
I love Anime.
```
## Customise
You can use [Home Layout](/docs/layouts/home-layout) for other pages of the site, it includes a navbar with theme toggle.
## Deploying
It should work out-of-the-box with Vercel & Netlify.
### Docker Deployment
If you want to deploy your Fumadocs app using Docker with **Fumadocs MDX configured**, make sure to add the `source.config.ts` file to the `WORKDIR` in the Dockerfile.
The following snippet is taken from the official [Next.js Dockerfile Example](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile):
```zsh title="Dockerfile"
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* source.config.ts ./
```
This ensures Fumadocs MDX can access your configuration file during builds.

View File

@ -1,196 +0,0 @@
---
title: 手动安装
description: 从零开始创建一个新的 Fumadocs 项目
image: /images/blog/post-4.png
date: "2025-03-14"
published: true
categories: [company, product]
author: mkdirs
---
> 请先阅读[快速入门](/docs)指南了解基本概念。
## 入门
使用 `create-next-app` 创建一个新的 Next.js 应用程序,并安装所需的包。
```mdx
fumadocs-ui fumadocs-core
```
### 内容源
Fumadocs 支持不同的内容源,您可以选择您喜欢的一种。
以下是官方支持的源列表:
- [设置 Fumadocs MDX](/docs/mdx)
- [设置 Content Collections](/docs/headless/content-collections)
请确保在继续之前按照其设置指南正确配置库,我们将在本指南中使用 `@/lib/source.ts` 导入源适配器。
### 根布局
将整个应用程序包装在 [Root Provider](/docs/layouts/root-provider) 中,并为 `body` 添加所需的样式。
```tsx
import { RootProvider } from 'fumadocs-ui/provider';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body
// you can use Tailwind CSS too
style={{
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
}}
>
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}
```
### 样式
在您的 Next.js 应用程序上设置 Tailwind CSS v4将以下内容添加到 `global.css`。
```css title="Tailwind CSS"
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* path of `fumadocs-ui` relative to the CSS file */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
```
> 它不附带默认字体,您可以从 `next/font` 中选择一个。
### 布局
创建一个 `app/layout.config.tsx` 文件,放置我们布局的共享选项。
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/layout.config.tsx",
"codeblock": {
"meta": "title=\"app/layout.config.tsx\""
}
}
```
为我们的文档创建一个文件夹 `/app/docs`,并给它一个适当的布局。
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/layout.tsx",
"codeblock": {
"meta": "title=\"app/docs/layout.tsx\""
}
}
```
> `pageTree` 指的是页面树,应该由您的内容源提供。
### 页面
为文档页面创建一个捕获所有路由 `/app/docs/[[...slug]]`。
在页面中,将您的内容包装在 [Page](/docs/layouts/page) 组件中。
这可能因您的内容源而异。您应该使用 `generateStaticParams` 配置静态渲染,并使用 `generateMetadata` 配置元数据。
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
### 搜索
使用基于 Orama 的默认文档搜索。
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
了解更多关于[文档搜索](/docs/headless/search)的信息。
### 完成
您可以启动开发服务器并创建 MDX 文件。
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Introduction
I love Anime.
```
## 自定义
您可以为网站的其他页面使用 [Home Layout](/docs/layouts/home-layout),它包含一个带有主题切换的导航栏。
## 部署
它应该在 Vercel 和 Netlify 上开箱即用。
### Docker 部署
如果您想使用 Docker 部署您的 Fumadocs 应用程序,并且已**配置了 Fumadocs MDX**,请确保将 `source.config.ts` 文件添加到 Dockerfile 中的 `WORKDIR`。
以下片段取自官方 [Next.js Dockerfile 示例](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile)
```zsh title="Dockerfile"
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* source.config.ts ./
```
这确保 Fumadocs MDX 在构建期间可以访问您的配置文件。

View File

@ -1,385 +0,0 @@
---
title: Markdown
description: How to write documents
image: /images/blog/post-5.png
date: "2025-03-05"
published: true
categories: [news, company]
author: mkdirs
---
## Introduction
Fumadocs provides many useful extensions to MDX, a markup language. Here is a brief introduction to the default MDX syntax of Fumadocs UI.
> MDX is not the only supported format of Fumadocs. In fact, you can use any renderers such as `next-mdx-remote` or CMS.
## Markdown
We use GFM (GitHub Flavored Markdown), a superset of Markdown (CommonMark).
See [GFM Specification](https://github.github.com/gfm).
````md
# Heading
## Heading
### Heading
#### Heading
Hello World, **Bold**, _Italic_, ~~Hidden~~
```js
console.log('Hello World');
```
1. First
2. Second
3. Third
- Item 1
- Item 2
> Quote here
![alt](/image.png)
| Table | Description |
| ----- | ----------- |
| Hello | World |
````
### Auto Links
Internal links use the `next/link` component to allow prefetching and avoid hard-reload.
External links will get the default `rel="noreferrer noopener" target="_blank"` attributes for security.
```mdx
[My Link](https://github.github.com/gfm)
This also works: https://github.github.com/gfm.
```
## MDX
MDX is a superset of Markdown, with support of JSX syntax.
It allows you to import components, and use them right in the document, or even export values.
```mdx
import { Component } from './component';
<Component name="Hello" />
```
see [MDX Syntax](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) to learn more.
### Cards
Useful for adding links, it is included by default.
```mdx
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
```
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
#### Icon
You can specify an icon to cards.
```mdx
import { HomeIcon } from 'lucide-react';
<Cards>
<Card icon={<HomeIcon />} href="/" title="Home">
Go back to home
</Card>
</Cards>
```
<Cards>
<Card icon={<HomeIcon />} href="/" title="Go back to home">
The home page of Fumadocs.
</Card>
</Cards>
#### Without href
```mdx
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
```
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
### Callouts
Useful for adding tips/warnings, it is included by default.
```mdx
<Callout>Hello World</Callout>
```
<Callout>Hello World</Callout>
#### Title
Specify a callout title.
```mdx
<Callout title="Title">Hello World</Callout>
```
<Callout title="Title">Hello World</Callout>
#### Types
You can specify the type of callout.
- `info` (default)
- `warn`
- `error`
```mdx
<Callout title="Title" type="error">
Hello World
</Callout>
```
<Callout title="Title" type="error">
Hello World
</Callout>
### Customise Components
See [all MDX components and available options](/docs/mdx).
## Headings
An anchor is automatically applied to each heading, it sanitizes invalid characters like spaces. (e.g. `Hello World` to `hello-world`)
```md
# Hello `World`
```
### TOC Settings
The table of contents (TOC) will be generated based on headings, you can also customise the effects of headings:
```md
# Heading [!toc]
This heading will be hidden from TOC.
# Another Heading [toc]
This heading will **only** be visible in TOC, you can use it to add additional TOC items.
Like headings rendered in a React component:
<MyComp />
```
### Custom Anchor
You can add `[#slug]` to customise heading anchors.
```md
# heading [#my-heading-id]
```
You can also chain it with TOC settings like:
```md
# heading [toc] [#my-heading-id]
```
To link people to a specific heading, add the heading id to hash fragment: `/page#my-heading-id`.
## Frontmatter
We support YAML frontmatter. It is a way to specify common information of the document (e.g. title).
Place it at the top of document.
```mdx
---
title: Hello World
---
## Title
```
See [Page Conventions](/docs/page-conventions#frontmatter) for a list of properties available for frontmatter.
## Codeblock
Syntax Highlighting is supported by default using [Rehype Code](/docs/headless/mdx/rehype-code).
````mdx
```js
console.log('Hello World');
```
````
You can add a title to the codeblock.
````mdx
```js title="My Title"
console.log('Hello World');
```
````
### Highlight Lines
You can highlight specific lines by adding `[!code highlight]`.
````md
```tsx
<div>Hello World</div> // [\!code highlight]
<div>Hello World</div>
<div>Goodbye</div>
<div>Hello World</div>
```
````
### Highlight Words
You can highlight a specific word by adding `[!code word:<match>]`.
````md
```js
// [\!code word:config]
const config = {
reactStrictMode: true,
};
```
````
### Diffs
````mdx
```ts
console.log('hewwo'); // [\!code --]
console.log('hello'); // [\!code ++]
```
````
```ts
console.log('hewwo'); // [!code --]
console.log('hello'); // [!code ++]
```
### Tab Groups
You can use code blocks with the `<Tab />` component.
````mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
````
> Note that you can add MDX components instead of importing them in MDX files.
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
### Using Typescript Twoslash
Write Typescript codeblocks with hover type information and detected types errors.
Not enabled by default. See [Twoslash](/docs/twoslash).
## Images
All built-in content sources handle images properly.
Images are automatically optimized for `next/image`.
```mdx
![Image](/image.png)
```
![Image](/images/blog/post-1.png)
## Optional
Some optional plugins you can enable.
### Math Equations
Write math equations with TeX.
````md
```mdx
f(x) = x * e^{2 pi i \xi x}
```
````
```mdx
f(x) = x * e^{2 pi i \xi x}
```
To enable, see [Math Integration](/docs/math).
### Package Install
Generate code blocks for installing packages via package managers (JS/Node.js).
````md
```mdx
npm i next -D
```
````
```mdx
npm i next -D
```
To enable, see [Remark Install](/docs/headless/mdx/install).
### More
You can see [a list of plugins](/docs/headless/mdx) supported by Fumadocs.

View File

@ -1,345 +0,0 @@
---
title: Markdown
description: 如何撰写文档
image: /images/blog/post-5.png
date: "2025-03-05"
published: true
categories: [news, company]
author: mkdirs
---
## 介绍
Fumadocs 为 MDX一种标记语言提供了许多有用的扩展。以下是 Fumadocs UI 默认 MDX 语法的简要介绍。
> MDX 不是 Fumadocs 唯一支持的格式。实际上,您可以使用任何渲染器,如 `next-mdx-remote` 或 CMS。
## Markdown
我们使用 GFMGitHub 风格的 Markdown这是 MarkdownCommonMark的超集。
参见 [GFM 规范](https://github.github.com/gfm)。
````md
# Heading
## Heading
### Heading
#### Heading
Hello World, **Bold**, _Italic_, ~~Hidden~~
```js
console.log('Hello World');
```
1. First
2. Second
3. Third
- Item 1
- Item 2
> Quote here
![alt](/image.png)
| Table | Description |
| ----- | ----------- |
| Hello | World |
````
### 自动链接
内部链接使用 `next/link` 组件,允许预取并避免硬重载。
外部链接将获得默认的 `rel="noreferrer noopener" target="_blank"` 属性以增强安全性。
```mdx
[My Link](https://github.github.com/gfm)
This also works: https://github.github.com/gfm.
```
## MDX
MDX 是 Markdown 的超集,支持 JSX 语法。
它允许您导入组件,并直接在文档中使用它们,甚至导出值。
```mdx
import { Component } from './component';
<Component name="Hello" />
```
参见 [MDX 语法](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) 了解更多信息。
### 卡片
对于添加链接很有用,默认包含。
```mdx
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
```
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
#### 图标
您可以为卡片指定图标。
```mdx
import { HomeIcon } from 'lucide-react';
<Cards>
<Card icon={<HomeIcon />} href="/" title="Home">
Go back to home
</Card>
</Cards>
```
<Cards>
<Card icon={<HomeIcon />} href="/" title="Go back to home">
The home page of Fumadocs.
</Card>
</Cards>
#### 无 href
```mdx
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
```
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
### 提示框
对于添加提示/警告很有用,默认包含。
```mdx
<Callout>Hello World</Callout>
```
<Callout>Hello World</Callout>
#### 标题
指定提示框标题。
```mdx
<Callout title="Title">Hello World</Callout>
```
<Callout title="Title">Hello World</Callout>
#### 类型
您可以指定提示框的类型。
- `info`(默认)
- `warn`
- `error`
```mdx
<Callout title="Title" type="error">
Hello World
</Callout>
```
<Callout title="Title" type="error">
Hello World
</Callout>
### 自定义组件
参见[所有 MDX 组件和可用选项](/docs/mdx)。
## 标题
每个标题会自动应用锚点,它会清理空格等无效字符。(例如,`Hello World` 变为 `hello-world`
```md
# Hello `World`
```
### 目录设置
目录 (TOC) 将基于标题生成,您还可以自定义标题的效果:
```md
# Heading [!toc]
This heading will be hidden from TOC.
# Another Heading [toc]
This heading will **only** be visible in TOC, you can use it to add additional TOC items.
Like headings rendered in a React component:
<MyComp />
```
### 自定义锚点
您可以添加 `[#slug]` 来自定义标题锚点。
```md
# heading [#my-heading-id]
```
您也可以将其与目录设置链接起来,例如:
```md
# heading [toc] [#my-heading-id]
```
要将人们链接到特定标题,请将标题 ID 添加到哈希片段:`/page#my-heading-id`。
## 前言
我们支持 YAML 前言。这是一种指定文档常见信息(例如标题)的方式。
将其放在文档顶部。
```mdx
---
title: Hello World
---
## Title
```
有关前言可用属性的列表,请参见[页面约定](/docs/page-conventions#frontmatter)。
## 代码块
默认使用 [Rehype Code](/docs/headless/mdx/rehype-code) 支持语法高亮。
````mdx
```js
console.log('Hello World');
```
````
您可以为代码块添加标题。
````mdx
```js title="My Title"
console.log('Hello World');
```
````
### 高亮行
````md
```tsx
<div>Hello World</div> // [\!code highlight]
<div>Hello World</div>
<div>Goodbye</div>
<div>Hello World</div>
```
````
### 高亮单词
您可以通过添加 `[!code word:<match>]` 来高亮特定单词。
````md
```js
// [\!code word:config]
const config = {
reactStrictMode: true,
};
```
````
### 差异
````mdx
```ts
console.log('hewwo'); // [\!code --]
console.log('hello'); // [\!code ++]
```
````
```ts
console.log('hewwo'); // [!code --]
console.log('hello'); // [!code ++]
```
### 标签组
您可以使用 `<Tab />` 组件与代码块一起使用。
````mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
````
> 注意,您可以在 MDX 文件中添加 MDX 组件,而不必导入它们。
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
### 使用 Typescript Twoslash
编写带有悬停类型信息和检测到类型错误的 Typescript 代码块。
默认情况下未启用。参见 [Twoslash](/docs/twoslash)。
## 图片
所有内置内容源都能正确处理图片。
图片会自动为 `next/image` 优化。
```mdx
![Image](/image.png)
```
## 可选功能
一些您可以启用的可选插件。

View File

@ -1,56 +0,0 @@
---
title: "Premium Blog Post"
description: "This blog post is a test for premium content."
date: "2025-08-30"
published: true
premium: true
categories: ["product"]
author: "fox"
image: "/images/blog/post-7.png"
---
This blog post is a test for premium content.
You can read this part of the blog post if you are not a premium user.
But for the rest of the blog post, you need to be logged in as a premium user.
You can click the "Sign In" button to sign in as a user with free plan.
Then you can click the "Upgrade Now" button to upgrade to a premium plan.
<Callout type="warn">
Don't worry, you don't actually pay any cents, because we are in the sandbox environment of Stripe.
</Callout>
You can use the test card number to pay for monthly or yearly PRO plan or LIFETIME plan.
```
Card number: 4242 4242 4242 4242
Exp: 12/34
CVV: 567
```
After that, you can return to the blog post and you can read the rest of the blog post.
For more details, please check out the documentation: [Blog](https://mksaas.com/docs/blog).
Now the rest of the blog post is premium content.
<PremiumContent>
<Callout type="info">
This is the beginning of the premium content part.
</Callout>
This is the premium content part.
You can read this paragraph only if you are a premium user.
Please don't share this blog post with others.
<Callout type="info">
This is the end of the premium content part.
</Callout>
</PremiumContent>

View File

@ -1,56 +0,0 @@
---
title: "测试专用付费文章"
description: "这是一篇测试专用付费文章。"
date: "2025-08-30"
published: true
premium: true
categories: ["product"]
author: "fox"
image: "/images/blog/post-7.png"
---
这是一篇测试专用的付费文章。
如果你不是付费用户,你可以阅读这篇文章的这部分内容。
但如果你想阅读剩下的内容,你需要成为一个付费用户。
你可以点击 "登录" 按钮来以免费用户的身份登录。
然后你可以点击 "立即升级" 按钮来升级到付费计划。
<Callout type="warn">
不用担心,你实际上不需要支付任何费用,因为我们处于 Stripe 的沙盒环境中。
</Callout>
你可以使用测试卡号来支付月度或年度 PRO 计划或终身计划。
```
Card number: 4242 4242 4242 4242
Exp: 12/34
CVV: 567
```
之后,你可以返回这篇博客文章,然后你可以阅读剩下的内容。
更多详情,请参考文档:[博客](https://mksaas.com/docs/blog)。
现在剩下的内容是付费内容。
<PremiumContent>
<Callout type="info">
这是付费内容部分的开始。
</Callout>
这是付费内容部分。
你可以阅读这篇内容,只要你是一个付费用户。
请不要分享这篇文章给其他人。
<Callout type="info">
这是付费内容部分的结束。
</Callout>
</PremiumContent>

View File

@ -1,280 +0,0 @@
---
title: Search
description: Implement document search in your docs
image: /images/blog/post-6.png
date: "2025-02-15"
published: true
categories: [company, news]
author: mksaas
---
Fumadocs UI provides a good-looking search UI for your docs, the search functionality is instead provided and documented on Fumadocs Core.
See [Document Search](/docs/headless/search).
## Search UI
Open with <kbd>⌘</kbd> <kbd>K</kbd> or <kbd>Ctrl</kbd> <kbd>K</kbd>.
### Configurations
You can customize search UI from the [Root Provider](/docs/layouts/root-provider) component in root layout.
When not specified, it uses the Default [`fetch` Search Client](/docs/headless/search/orama) powered by Orama.
### Custom Links
Add custom link items to search dialog.
They are shown as fallbacks when the query is empty.
```tsx title="app/layout.tsx"
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
links: [
['Home', '/'],
['Docs', '/docs'],
],
}}
>
{children}
</RootProvider>;
```
### Disable Search
To opt-out of document search, disable it from root provider.
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
enabled: false,
}}
>
{children}
</RootProvider>;
```
### Hot Keys
Customise the hot keys to trigger search dialog.
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
hotKey: [
{
display: 'K',
key: 'k', // key code, or a function determining whether the key is pressed
},
],
}}
>
{children}
</RootProvider>;
```
### Tag Filter
Add UI to change filters.
Make sure to configure [Tag Filter](/docs/headless/search/orama#tag-filter) on search server first.
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
options: {
defaultTag: 'value',
tags: [
{
name: 'Tag Name',
value: 'value',
},
],
},
}}
>
{children}
</RootProvider>;
```
### Search Options
Pass options to the search client, like changing the API endpoint for Orama search server:
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
options: {
api: '/api/search/docs',
},
}}
>
{children}
</RootProvider>;
```
### Replace Search Dialog
You can replace the default Search Dialog with:
```tsx title="components/search.tsx"
'use client';
import SearchDialog from 'fumadocs-ui/components/dialog/search-default';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
export default function CustomDialog(props: SharedProps) {
// your own logic here
return <SearchDialog {...props} />;
}
```
To pass it to the Root Provider, you need a wrapper with `use client` directive.
```tsx title="provider.tsx"
'use client';
import { RootProvider } from 'fumadocs-ui/provider';
import dynamic from 'next/dynamic';
import type { ReactNode } from 'react';
const SearchDialog = dynamic(() => import('@/components/search')); // lazy load
export function Provider({ children }: { children: ReactNode }) {
return (
<RootProvider
search={{
SearchDialog,
}}
>
{children}
</RootProvider>
);
}
```
Use it instead of your previous Root Provider
```tsx title="layout.tsx"
import { Provider } from './provider';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<Provider>{children}</Provider>
</body>
</html>
);
}
```
## Other Solutions
### Algolia
For the setup guide, see [Integrate Algolia Search](/docs/headless/search/algolia).
While generally we recommend building your own search with their client-side
SDK, you can also plug the built-in dialog interface.
```tsx title="components/search.tsx"
'use client';
import algo from 'algoliasearch/lite';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
import SearchDialog from 'fumadocs-ui/components/dialog/search-algolia';
const client = algo('appId', 'apiKey');
const index = client.initIndex('indexName');
export default function CustomSearchDialog(props: SharedProps) {
return <SearchDialog index={index} {...props} />;
}
```
1. Replace `appId`, `apiKey` and `indexName` with your desired values.
2. [Replace the default search dialog](#replace-search-dialog) with your new component.
<Callout title="Note" className='mt-4'>
The built-in implementation doesn't use instant search (their official
javascript client).
</Callout>
#### Tag Filter
Same as default search client, you can configure [Tag Filter](/docs/headless/search/algolia#tag-filter) on the dialog.
```tsx title="components/search.tsx"
import SearchDialog from 'fumadocs-ui/components/dialog/search-algolia';
<SearchDialog
defaultTag="value"
tags={[
{
name: 'Tag Name',
value: 'value',
},
]}
/>;
```
### Orama Cloud
For the setup guide, see [Integrate Orama Cloud](/docs/headless/search/orama-cloud).
```tsx title="components/search.tsx"
'use client';
import { OramaClient } from '@oramacloud/client';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
import SearchDialog from 'fumadocs-ui/components/dialog/search-orama';
const client = new OramaClient({
endpoint: 'endpoint',
api_key: 'apiKey',
});
export default function CustomSearchDialog(props: SharedProps) {
return <SearchDialog {...props} client={client} showOrama />;
}
```
1. Replace `endpoint`, `apiKey` with your desired values.
2. [Replace the default search dialog](#replace-search-dialog) with your new component.
### Community Integrations
A list of integrations maintained by community.
- [Trieve Search](/docs/headless/search/trieve)
## Built-in UI
If you want to use the built-in search dialog UI instead of building your own,
you may use the `SearchDialog` component.
```tsx
import {
SearchDialog,
type SharedProps,
} from 'fumadocs-ui/components/dialog/search';
export default function CustomSearchDialog(props: SharedProps) {
return <SearchDialog {...props} />;
}
```
<Callout type="warn" title="Unstable">
It is an internal API, might break during iterations
</Callout>

View File

@ -1,252 +0,0 @@
---
title: 搜索
description: 在您的文档中实现文档搜索
image: /images/blog/post-6.png
date: "2025-02-15"
published: true
categories: [company, news]
author: mksaas
---
Fumadocs UI 为您的文档提供了一个美观的搜索界面,而搜索功能则由 Fumadocs Core 提供和记录。
参见[文档搜索](/docs/headless/search)。
## 搜索 UI
使用 <kbd>⌘</kbd> <kbd>K</kbd> 或 <kbd>Ctrl</kbd> <kbd>K</kbd> 打开。
### 配置
您可以通过根布局中的 [Root Provider](/docs/layouts/root-provider) 组件自定义搜索 UI。
当未指定时,它使用由 Orama 提供支持的默认 [`fetch` 搜索客户端](/docs/headless/search/orama)。
### 自定义链接
向搜索对话框添加自定义链接项。
当查询为空时,它们会显示为备选项。
```tsx title="app/layout.tsx"
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
links: [
['Home', '/'],
['Docs', '/docs'],
],
}}
>
{children}
</RootProvider>;
```
### 禁用搜索
要禁用文档搜索,请在根提供程序中禁用它。
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
enabled: false,
}}
>
{children}
</RootProvider>;
```
### 热键
自定义触发搜索对话框的热键。
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
hotKey: [
{
display: 'K',
key: 'k', // key code, or a function determining whether the key is pressed
},
],
}}
>
{children}
</RootProvider>;
```
### 标签过滤器
添加 UI 以更改过滤器。
确保首先在搜索服务器上配置[标签过滤器](/docs/headless/search/orama#tag-filter)。
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
options: {
defaultTag: 'value',
tags: [
{
name: 'Tag Name',
value: 'value',
},
],
},
}}
>
{children}
</RootProvider>;
```
### 搜索选项
向搜索客户端传递选项,例如更改 Orama 搜索服务器的 API 端点:
```tsx
import { RootProvider } from 'fumadocs-ui/root-provider';
<RootProvider
search={{
options: {
api: '/api/search/docs',
},
}}
>
{children}
</RootProvider>;
```
### 替换搜索对话框
您可以用以下内容替换默认搜索对话框:
```tsx title="components/search.tsx"
'use client';
import SearchDialog from 'fumadocs-ui/components/dialog/search-default';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
export default function CustomDialog(props: SharedProps) {
// your own logic here
return <SearchDialog {...props} />;
}
```
要将其传递给 Root Provider您需要一个带有 `use client` 指令的包装器。
```tsx title="provider.tsx"
'use client';
import { RootProvider } from 'fumadocs-ui/provider';
import dynamic from 'next/dynamic';
import type { ReactNode } from 'react';
const SearchDialog = dynamic(() => import('@/components/search')); // lazy load
export function Provider({ children }: { children: ReactNode }) {
return (
<RootProvider
search={{
SearchDialog,
}}
>
{children}
</RootProvider>
);
}
```
使用它替代您之前的 Root Provider
```tsx title="layout.tsx"
import { Provider } from './provider';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<Provider>{children}</Provider>
</body>
</html>
);
}
```
## 其他解决方案
### Algolia
关于设置指南,请参见[集成 Algolia 搜索](/docs/headless/search/algolia)。
虽然我们通常建议使用他们的客户端 SDK 构建您自己的搜索,但您也可以插入内置的对话框接口。
```tsx title="components/search.tsx"
'use client';
import algo from 'algoliasearch/lite';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
import SearchDialog from 'fumadocs-ui/components/dialog/search-algolia';
const client = algo('appId', 'apiKey');
const index = client.initIndex('indexName');
export default function CustomSearchDialog(props: SharedProps) {
return <SearchDialog index={index} {...props} />;
}
```
1. 将 `appId`、`apiKey` 和 `indexName` 替换为您想要的值。
2. 用您的新组件[替换默认搜索对话框](#replace-search-dialog)。
<Callout title="注意" className='mt-4'>
内置实现不使用即时搜索(他们的官方 JavaScript 客户端)。
</Callout>
#### 标签过滤器
与默认搜索客户端相同,您可以在对话框上配置[标签过滤器](/docs/headless/search/algolia#tag-filter)。
```tsx title="components/search.tsx"
import SearchDialog from 'fumadocs-ui/components/dialog/search-algolia';
<SearchDialog
defaultTag="value"
tags={[
{
name: 'Tag Name',
value: 'value',
},
]}
/>;
```
### Orama Cloud
关于设置指南,请参见[集成 Orama Cloud](/docs/headless/search/orama-cloud)。
```tsx title="components/search.tsx"
'use client';
import { OramaClient } from '@oramacloud/client';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
import SearchDialog from 'fumadocs-ui/components/dialog/search-orama';
const client = new OramaClient({
endpoint: 'endpoint',
api_key: 'apiKey',
});
export default function CustomSearchDialog(props: SharedProps) {
return <SearchDialog {...props} client={client} showOrama />;
}
```
1. 将 `endpoint`、`apiKey` 替换为您想要的值。
2. 用您的新组件[替换默认搜索对话框](#replace-search-dialog)。

View File

@ -1,171 +0,0 @@
---
title: Themes
description: Add Theme to Fumadocs UI
image: /images/blog/post-7.png
date: "2025-01-15"
published: true
categories: [product, news]
author: mkdirs
---
## Usage
Note only Tailwind CSS v4 is supported:
```css title="Tailwind CSS"
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* path of `fumadocs-ui` relative to the CSS file */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
```
### Preflight Changes
By using the Tailwind CSS plugin, or the pre-built stylesheet, your default border, text and background
colors will be changed.
### Light/Dark Modes
Fumadocs supports light/dark modes with [`next-themes`](https://github.com/pacocoursey/next-themes), it is included in Root Provider.
See [Root Provider](/docs/layouts/root-provider#theme-provider) to learn more.
### RTL Layout
RTL (Right-to-left) layout is supported.
To enable RTL, set the `dir` prop to `rtl` in body and root provider (required for Radix UI).
```tsx
import { RootProvider } from 'fumadocs-ui/provider';
import type { ReactNode } from 'react';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body dir="rtl">
<RootProvider dir="rtl">{children}</RootProvider>
</body>
</html>
);
}
```
### Prefix
Fumadocs UI has its own colors, animations, and utilities.
By default, it adds a `fd-` prefix to avoid conflicts with Shadcn UI or your own CSS variables.
You can use them without the prefix by adding some aliases:
```css title="Tailwind CSS"
@theme {
--color-primary: var(--color-fd-primary);
}
```
> You can use it with CSS media queries for responsive design.
### Layout Width
Customise the max width of docs layout with CSS Variables.
```css
:root {
--fd-layout-width: 1400px;
}
```
{/* <WidthTrigger /> */}
## Tailwind CSS Preset
The Tailwind CSS preset introduces new colors and extra utilities including `fd-steps`.
### Themes
It comes with many themes out-of-the-box, you can pick one you prefer.
```css
@import 'fumadocs-ui/css/<theme>.css';
/* Example */
@import 'fumadocs-ui/css/black.css';
```
<Tabs items={['neutral', 'black', 'vitepress', 'dusk', 'catppuccin', 'ocean', 'purple']}>
<Tab value='neutral'>
![Neutral](/images/docs/themes/neutral.png)
</Tab>
<Tab value='black'>
![Black](/images/docs/themes/black.png)
</Tab>
<Tab value='vitepress'>
![Vitepress](/images/docs/themes/vitepress.png)
</Tab>
<Tab value='dusk'>
![Dusk](/images/docs/themes/dusk.png)
</Tab>
<Tab value='Catppuccin'>
![Catppuccin](/images/docs/themes/catppuccin.png)
</Tab>
<Tab value='ocean'>
![Ocean](/images/docs/themes/ocean.png)
</Tab>
<Tab value='purple'>
![Purple](/images/docs/themes/purple.png)
</Tab>
</Tabs>
### Colors
The design system was inspired by [Shadcn UI](https://ui.shadcn.com), you can easily customize the colors using CSS variables.
```css title="global.css"
:root {
--color-fd-background: hsl(0, 0%, 100%);
}
.dark {
--color-fd-background: hsl(0, 0%, 0%);
}
```
### Typography
We have a built-in plugin forked from [Tailwind CSS Typography](https://tailwindcss.com/docs/typography-plugin).
The plugin adds a `prose` class and variants to customise it.
```tsx
<div className="prose">
<h1>Good Heading</h1>
</div>
```
> The plugin works with and only with Fumadocs UI's MDX components, it may conflict with `@tailwindcss/typography`.
> If you need to use `@tailwindcss/typography` over the default plugin, [set a class name option](https://github.com/tailwindlabs/tailwindcss-typography/blob/main/README.md#changing-the-default-class-name) to avoid conflicts.

View File

@ -1,170 +0,0 @@
---
title: 主题
description: 为 Fumadocs UI 添加主题
image: /images/blog/post-7.png
date: "2025-01-15"
published: true
categories: [product, news]
author: mkdirs
---
## 使用方法
注意只支持 Tailwind CSS v4
```css title="Tailwind CSS"
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* path of `fumadocs-ui` relative to the CSS file */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
```
### 预设更改
通过使用 Tailwind CSS 插件或预构建的样式表,您的默认边框、文本和背景颜色将被更改。
### 明/暗模式
Fumadocs 通过 [`next-themes`](https://github.com/pacocoursey/next-themes) 支持明/暗模式,它包含在 Root Provider 中。
参见 [Root Provider](/docs/layouts/root-provider#theme-provider) 了解更多信息。
### RTL 布局
支持 RTL从右到左布局。
要启用 RTL请在 body 和 root providerRadix UI 需要)中将 `dir` 属性设置为 `rtl`。
```tsx
import { RootProvider } from 'fumadocs-ui/provider';
import type { ReactNode } from 'react';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body dir="rtl">
<RootProvider dir="rtl">{children}</RootProvider>
</body>
</html>
);
}
```
### 前缀
Fumadocs UI 有自己的颜色、动画和工具。
默认情况下,它添加了 `fd-` 前缀,以避免与 Shadcn UI 或您自己的 CSS 变量冲突。
您可以通过添加一些别名来使用它们,而无需前缀:
```css title="Tailwind CSS"
@theme {
--color-primary: var(--color-fd-primary);
}
```
> 您可以将其与 CSS 媒体查询一起使用,实现响应式设计。
### 布局宽度
使用 CSS 变量自定义文档布局的最大宽度。
```css
:root {
--fd-layout-width: 1400px;
}
```
{/* <WidthTrigger /> */}
## Tailwind CSS 预设
Tailwind CSS 预设引入了新的颜色和额外的工具,包括 `fd-steps`。
### 主题
它开箱即用地提供了许多主题,您可以选择一个您喜欢的。
```css
@import 'fumadocs-ui/css/<theme>.css';
/* Example */
@import 'fumadocs-ui/css/black.css';
```
<Tabs items={['neutral', 'black', 'vitepress', 'dusk', 'catppuccin', 'ocean', 'purple']}>
<Tab value='neutral'>
![Neutral](/images/docs/themes/neutral.png)
</Tab>
<Tab value='black'>
![Black](/images/docs/themes/black.png)
</Tab>
<Tab value='vitepress'>
![Vitepress](/images/docs/themes/vitepress.png)
</Tab>
<Tab value='dusk'>
![Dusk](/images/docs/themes/dusk.png)
</Tab>
<Tab value='Catppuccin'>
![Catppuccin](/images/docs/themes/catppuccin.png)
</Tab>
<Tab value='ocean'>
![Ocean](/images/docs/themes/ocean.png)
</Tab>
<Tab value='purple'>
![Purple](/images/docs/themes/purple.png)
</Tab>
</Tabs>
### 颜色
设计系统的灵感来自 [Shadcn UI](https://ui.shadcn.com),您可以使用 CSS 变量轻松自定义颜色。
```css title="global.css"
:root {
--color-fd-background: hsl(0, 0%, 100%);
}
.dark {
--color-fd-background: hsl(0, 0%, 0%);
}
```
### 排版
我们有一个内置插件,它是从 [Tailwind CSS Typography](https://tailwindcss.com/docs/typography-plugin) 派生而来的。
该插件添加了一个 `prose` 类和变体来自定义它。
```tsx
<div className="prose">
<h1>Good Heading</h1>
</div>
```
> 该插件仅与 Fumadocs UI 的 MDX 组件一起工作,它可能与 `@tailwindcss/typography` 冲突。
> 如果您需要使用 `@tailwindcss/typography` 而不是默认插件,请[设置类名选项](https://github.com/tailwindlabs/tailwindcss-typography/blob/main/README.md#changing-the-default-class-name)以避免冲突。

View File

@ -1,62 +0,0 @@
---
title: What is Fumadocs
description: Introducing Fumadocs, a docs framework that you can break.
image: /images/blog/post-1.png
date: "2025-04-01"
published: true
categories: [company, product]
author: fox
---
Fumadocs was created because I wanted a more customisable experience for building docs, to be a docs framework that is not opinionated, **a "framework" that you can break**.
## Philosophy
**Less Abstraction:** Fumadocs expects you to write code and cooperate with the rest of your software.
While most frameworks are configured with a configuration file, they usually lack flexibility when you hope to tune its details.
You cant control how they render the page nor the internal logic. Fumadocs shows you how the app works, instead of a single configuration file.
**Next.js Fundamentals:** It gives you the utilities and a good-looking UI.
You are still using features of Next.js App Router, like **Static Site Generation**. There is nothing new for Next.js developers, so you can use it with confidence.
**Opinionated on UI:** The only thing Fumadocs UI (the default theme) offers is **User Interface**. The UI is opinionated for bringing better mobile responsiveness and user experience.
Instead, we use a much more flexible approach inspired by Shadcn UI — [Fumadocs CLI](/docs/cli), so we can iterate our design quick, and welcome for more feedback about the UI.
## Why Fumadocs
Fumadocs is designed with flexibility in mind.
You can use `fumadocs-core` as a headless UI library and bring your own styles.
Fumadocs MDX is also a useful library to handle MDX content in Next.js. It also includes:
- Many built-in components.
- Typescript Twoslash, OpenAPI, and Math (KaTeX) integrations.
- Fast and optimized by default, natively built on App Router.
- Tight integration with Next.js, you can add it to an existing Next.js project easily.
You can read [Comparisons](/docs/comparisons) if you're interested.
### Documentation
Fumadocs focuses on **authoring experience**, it provides a beautiful theme and many docs automation tools.
It helps you to iterate your codebase faster while never leaving your docs behind.
You can take this site as an example of docs site built with Fumadocs.
### Blog sites
Since Next.js is already a powerful framework, most features can be implemented with **just Next.js**.
Fumadocs provides additional tooling for Next.js, including syntax highlighting, document search, and a default theme (Fumadocs UI).
It helps you to avoid reinventing the wheels.
## When to use Fumadocs
For most of the web applications, vanilla React.js is no longer enough.
Nowadays, we also wish to have a blog, a showcase page, a FAQ page, etc. With a
fancy UI that's breathtaking, in these cases, Fumadocs can help you build the
docs easier, with less boilerplate.
Fumadocs is maintained by Fuma and many contributors, with care on the maintainability of codebase.
While we don't aim to offer every functionality people wanted, we're more focused on making basic features perfect and well-maintained.
You can also help Fumadocs to be more useful by contributing!

View File

@ -1,60 +0,0 @@
---
title: 什么是 Fumadocs
description: 介绍 Fumadocs一个可以打破常规的文档框架
image: /images/blog/post-1.png
date: "2025-04-01"
published: true
categories: [company, product]
author: fox
---
Fumadocs 的创建是因为我想要一种更加可定制化的文档构建体验,一个不固执己见的文档框架,**一个你可以"打破"的"框架"**。
## 理念
**更少的抽象:** Fumadocs 期望您编写代码并与您的其余软件协作。
虽然大多数框架都是通过配置文件进行配置,但当您希望调整其细节时,它们通常缺乏灵活性。
您无法控制它们如何渲染页面或内部逻辑。Fumadocs 向您展示应用程序如何工作,而不是仅提供单一的配置文件。
**Next.js 基础:** 它为您提供实用工具和美观的 UI。
您仍然使用 Next.js App Router 的功能,如**静态站点生成**。对于 Next.js 开发者来说没有新的东西,所以您可以放心使用。
**对 UI 有自己的看法:** Fumadocs UI默认主题提供的唯一东西是**用户界面**。UI 的设计理念是提供更好的移动响应性和用户体验。
相反,我们使用受 Shadcn UI 启发的更灵活的方法 — [Fumadocs CLI](/docs/cli),这样我们可以快速迭代设计,并欢迎更多关于 UI 的反馈。
## 为什么选择 Fumadocs
Fumadocs 的设计考虑了灵活性。
您可以将 `fumadocs-core` 用作无头 UI 库并带来您自己的样式。
Fumadocs MDX 也是处理 Next.js 中 MDX 内容的有用库。它还包括:
- 许多内置组件。
- Typescript Twoslash、OpenAPI 和 Math (KaTeX) 集成。
- 默认情况下快速且优化,原生构建在 App Router 上。
- 与 Next.js 紧密集成,您可以轻松将其添加到现有的 Next.js 项目中。
如果您感兴趣,可以阅读 [比较](/docs/comparisons)。
### 文档
Fumadocs 专注于**创作体验**,它提供了一个漂亮的主题和许多文档自动化工具。
它帮助您更快地迭代代码库,同时不会落下您的文档。
您可以将此站点作为使用 Fumadocs 构建的文档站点的示例。
### 博客站点
由于 Next.js 已经是一个强大的框架,大多数功能可以**仅使用 Next.js** 实现。
Fumadocs 为 Next.js 提供了额外的工具包括语法高亮、文档搜索和默认主题Fumadocs UI
它帮助您避免重新发明轮子。
## 何时使用 Fumadocs
对于大多数 Web 应用程序,原生 React.js 已经不够用了。
如今我们还希望有一个博客、展示页面、FAQ 页面等。带有令人惊叹的精美 UI在这些情况下Fumadocs 可以帮助您更轻松地构建文档,减少样板代码。
Fumadocs 由 Fuma 和许多贡献者维护,关注代码库的可维护性。
虽然我们不打算提供人们想要的每一项功能,但我们更专注于使基本功能完美且维护良好。
您也可以通过贡献来帮助 Fumadocs 变得更加有用!

View File

@ -1,74 +0,0 @@
---
title: Comparisons
description: How is Fumadocs different from other existing frameworks?
icon: GitCompareArrows
---
## Nextra
Fumadocs is highly inspired by Nextra. For example, the Routing Conventions. That is why
`meta.json` also exists in Fumadocs.
Nextra is more opinionated than Fumadocs. Fumadocs is accelerated by App Router. As a result, It provides many server-side functions, and you have to
configure things manually compared to simply editing a configuration file.
Fumadocs works great if you want more control over everything, such as
adding it to an existing codebase or implementing advanced routing.
### Feature Table
| Feature | Fumadocs | Nextra |
| ------------------- | ------------ | ------------------------- |
| Static Generation | Yes | Yes |
| Cached | Yes | Yes |
| Light/Dark Mode | Yes | Yes |
| Syntax Highlighting | Yes | Yes |
| Table of Contents | Yes | Yes |
| Full-text Search | Yes | Yes |
| i18n | Yes | Yes |
| Last Git Edit Time | Yes | Yes |
| Page Icons | Yes | Yes, via `_meta.js` files |
| RSC | Yes | Yes |
| Remote Source | Yes | Yes |
| SEO | Via Metadata | Yes |
| Built-in Components | Yes | Yes |
| RTL Layout | Yes | Yes |
### Additional Features
Features supported via 3rd party libraries like [TypeDoc](https://typedoc.org) will not be listed here.
| Feature | Fumadocs | Nextra |
| -------------------------- | -------- | ------ |
| OpenAPI Integration | Yes | No |
| TypeScript Docs Generation | Yes | No |
| TypeScript Twoslash | Yes | Yes |
## Mintlify
Mintlify is a documentation service, as compared to Fumadocs, it offers a free tier but isn't completely free and open source.
Fumadocs is not as powerful as Mintlify, for example, the OpenAPI integration of Mintlify.
As the creator of Fumadocs, I wouldn't recommend switching to Fumadocs from Mintlify if you're satisfied with the current way you build docs.
However, I believe Fumadocs is a suitable tool for all Next.js developers who want to have elegant docs.
## Docusaurus
Docusaurus is a powerful framework based on React.js. It offers many cool
features with plugins and custom themes.
### Better DX
Since Fumadocs is built on the top of Next.js, you'll have to start the Next.js dev
server every time to review changes, and initial boilerplate code is relatively more
compared to Docusaurus.
For a simple docs, Docusaurus might be a better choice if you don't need any Next.js specific functionality.
However, when you want to use Next.js, or seek extra customizability like tuning default UI components, Fumadocs could be a better choice.
### Plugins
You can easily achieve many things with plugins, their ecosystem is indeed larger and maintained by many contributors.
In comparison, the flexibility of Fumadocs allows you to implement them on your own, it may take longer to tune it to your satisfaction.

View File

@ -1,68 +0,0 @@
---
title: 对比
description: Fumadocs 与其他现有框架有何不同?
icon: GitCompareArrows
---
## Nextra
Fumadocs 深受 Nextra 启发。例如,路由约定。这就是为什么 Fumadocs 中也存在 `meta.json`。
Nextra 比 Fumadocs 更加固执己见。Fumadocs 由 App Router 加速。因此,它提供了许多服务器端功能,与简单编辑配置文件相比,您必须手动配置一些内容。
如果您想要对一切都有更多的控制比如将其添加到现有代码库或实现高级路由Fumadocs 会表现得很出色。
### 功能表
| 功能 | Fumadocs | Nextra |
| ------------------- | ------------ | ------------------------- |
| 静态生成 | 是 | 是 |
| 缓存 | 是 | 是 |
| 明/暗模式 | 是 | 是 |
| 语法高亮 | 是 | 是 |
| 目录 | 是 | 是 |
| 全文搜索 | 是 | 是 |
| 国际化 | 是 | 是 |
| 最后 Git 编辑时间 | 是 | 是 |
| 页面图标 | 是 | 是,通过 `_meta.js` 文件 |
| RSC | 是 | 是 |
| 远程源 | 是 | 是 |
| SEO | 通过元数据 | 是 |
| 内置组件 | 是 | 是 |
| RTL 布局 | 是 | 是 |
### 附加功能
通过第三方库支持的功能(如 [TypeDoc](https://typedoc.org))不会在此列出。
| 功能 | Fumadocs | Nextra |
| -------------------------- | -------- | ------ |
| OpenAPI 集成 | 是 | 否 |
| TypeScript 文档生成 | 是 | 否 |
| TypeScript Twoslash | 是 | 是 |
## Mintlify
Mintlify 是一项文档服务,与 Fumadocs 相比,它提供免费套餐,但并非完全免费和开源。
Fumadocs 不如 Mintlify 强大,例如 Mintlify 的 OpenAPI 集成。
作为 Fumadocs 的创建者,如果您对当前构建文档的方式感到满意,我不建议从 Mintlify 切换到 Fumadocs。
然而,我相信 Fumadocs 是所有想要拥有优雅文档的 Next.js 开发者的合适工具。
## Docusaurus
Docusaurus 是一个基于 React.js 的强大框架。它通过插件和自定义主题提供了许多酷炫的功能。
### 更好的开发者体验
由于 Fumadocs 构建在 Next.js 之上,您每次都必须启动 Next.js 开发服务器来查看更改,并且相对于 Docusaurus初始样板代码较多。
对于简单的文档,如果您不需要任何特定于 Next.js 的功能Docusaurus 可能是更好的选择。
然而,当您想要使用 Next.js或寻求更多的可定制性如调整默认 UI 组件时Fumadocs 可能是更好的选择。
### 插件
您可以通过插件轻松实现许多功能,他们的生态系统确实更大,并由许多贡献者维护。
相比之下Fumadocs 的灵活性允许您自己实现它们,可能需要更长的时间来调整它以达到您的满意度。

View File

@ -1,43 +0,0 @@
---
title: Accordion
description: Add Accordions to your documentation
preview: accordion
---
## Usage
Based on
[Radix UI Accordion](https://www.radix-ui.com/primitives/docs/components/accordion), useful for FAQ sections.
```tsx
import React from 'react';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
<Accordions type="single">
<Accordion title="My Title">My Content</Accordion>
</Accordions>;
```
### Accordions
{/* <AutoTypeTable path="./content/docs/props.ts" name="AccordionsProps" /> */}
### Accordion
{/* <AutoTypeTable path="./content/docs/props.ts" name="AccordionProps" /> */}
### Linking to Accordion
You can specify an `id` for accordion. The accordion will automatically open when the user is navigating to the page with the specified `id` in hash parameter.
```mdx
<Accordions>
<Accordion title="My Title" id="my-title">
My Content
</Accordion>
</Accordions>
```
> The value of accordion is same as title by default. When an id presents, it will be used as the value instead.

View File

@ -1,42 +0,0 @@
---
title: 手风琴
description: 在文档中添加手风琴组件
preview: accordion
---
## 使用方法
基于 [Radix UI Accordion](https://www.radix-ui.com/primitives/docs/components/accordion),对 FAQ 部分特别有用。
```tsx
import React from 'react';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
<Accordions type="single">
<Accordion title="我的标题">我的内容</Accordion>
</Accordions>;
```
### Accordions
{/* <AutoTypeTable path="./content/docs/props.ts" name="AccordionsProps" /> */}
### Accordion
{/* <AutoTypeTable path="./content/docs/props.ts" name="AccordionProps" /> */}
### 链接到手风琴
您可以为手风琴指定一个 `id`。当用户导航到带有指定 `id` 的哈希参数的页面时,手风琴将自动打开。
```mdx
<Accordions>
<Accordion title="我的标题" id="my-title">
我的内容
</Accordion>
</Accordions>
```
> 手风琴的值默认与标题相同。当存在 id 时,它将被用作值。

View File

@ -1,61 +0,0 @@
---
title: Banner
description: Add a banner to your site
preview: banner
---
## Usage
Put the element at the top of your root layout, you can use it for displaying announcements.
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}): React.ReactElement {
return (
<html lang="en">
<body>
<Banner>Hello World</Banner>
{children}
</body>
</html>
);
}
```
### Variant
Change the default variant.
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
<Banner variant="rainbow">Hello World</Banner>;
```
### Change Layout
By default, the banner uses a `style` tag to modify Fumadocs layouts (e.g. reduce the sidebar height).
You can disable it with:
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
<Banner changeLayout={false}>Hello World</Banner>;
```
### Close
To allow users to close the banner, give the banner an ID.
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
<Banner id="hello-world">Hello World</Banner>;
```
The state will be automatically persisted.

View File

@ -1,61 +0,0 @@
---
title: 横幅
description: 在您的网站添加横幅
preview: banner
---
## 使用方法
将元素放在根布局的顶部,您可以用它来显示公告。
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}): React.ReactElement {
return (
<html lang="en">
<body>
<Banner>Hello World</Banner>
{children}
</body>
</html>
);
}
```
### 变体
更改默认变体。
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
<Banner variant="rainbow">Hello World</Banner>;
```
### 更改布局
默认情况下,横幅使用 `style` 标签来修改 Fumadocs 布局(例如减少侧边栏高度)。
您可以通过以下方式禁用它:
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
<Banner changeLayout={false}>Hello World</Banner>;
```
### 关闭
要允许用户关闭横幅,请给横幅一个 ID。
```tsx
import { Banner } from 'fumadocs-ui/components/banner';
<Banner id="hello-world">Hello World</Banner>;
```
状态将自动保持。

View File

@ -1,38 +0,0 @@
---
title: Code Block (Dynamic)
description: A codeblock that also highlights code
preview: dynamicCodeBlock
---
## Usage
```tsx
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
<DynamicCodeBlock lang="ts" code='console.log("Hello World")' />;
```
This component, different from the MDX [`CodeBlock`](/docs/mdx/codeblock) component, can be used without MDX.
It highlights the code with Shiki and use the default component to render it.
Features:
- Can be pre-rendered on server
- load languages and themes on browser lazily
### Options
```tsx
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
<DynamicCodeBlock
lang="ts"
code='console.log("Hello World")'
options={{
components: {
// add/override components
},
// or Shiki options
}}
/>;
```

View File

@ -1,38 +0,0 @@
---
title: 代码块(动态)
description: 也能高亮代码的代码块
preview: dynamicCodeBlock
---
## 使用方法
```tsx
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
<DynamicCodeBlock lang="ts" code='console.log("Hello World")' />;
```
这个组件与 MDX [`CodeBlock`](/docs/mdx/codeblock) 组件不同,可以在不使用 MDX 的情况下使用。
它使用 Shiki 高亮代码,并使用默认组件渲染它。
特点:
- 可以在服务器上预渲染
- 在浏览器上懒加载语言和主题
### 选项
```tsx
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
<DynamicCodeBlock
lang="ts"
code='console.log("Hello World")'
options={{
components: {
// 添加/覆盖组件
},
// 或 Shiki 选项
}}
/>;
```

View File

@ -1,35 +0,0 @@
---
title: Files
description: Display file structure in your documentation
preview: 'files'
---
## Usage
Wrap file components in `Files`.
```mdx
import { File, Folder, Files } from 'fumadocs-ui/components/files';
<Files>
<Folder name="app" defaultOpen>
<File name="layout.tsx" />
<File name="page.tsx" />
<File name="global.css" />
</Folder>
<Folder name="components">
<File name="button.tsx" />
<File name="tabs.tsx" />
<File name="dialog.tsx" />
</Folder>
<File name="package.json" />
</Files>
```
### File
{/* <AutoTypeTable path="./content/docs/props.ts" name="FileProps" /> */}
### Folder
{/* <AutoTypeTable path="./content/docs/props.ts" name="FolderProps" /> */}

View File

@ -1,35 +0,0 @@
---
title: 文件
description: 在文档中显示文件结构
preview: 'files'
---
## 使用方法
将文件组件包装在 `Files` 中。
```mdx
import { File, Folder, Files } from 'fumadocs-ui/components/files';
<Files>
<Folder name="app" defaultOpen>
<File name="layout.tsx" />
<File name="page.tsx" />
<File name="global.css" />
</Folder>
<Folder name="components">
<File name="button.tsx" />
<File name="tabs.tsx" />
<File name="dialog.tsx" />
</Folder>
<File name="package.json" />
</Files>
```
### File
{/* <AutoTypeTable path="./content/docs/props.ts" name="FileProps" /> */}
### Folder
{/* <AutoTypeTable path="./content/docs/props.ts" name="FolderProps" /> */}

View File

@ -1,45 +0,0 @@
---
title: GitHub Info
description: Display your GitHub repository information
preview: githubInfo
---
## Usage
```tsx
import { GithubInfo } from 'fumadocs-ui/components/github-info';
<GithubInfo
owner="fuma-nama"
repo="fumadocs"
// your own GitHub access token (optional)
token={process.env.GITHUB_TOKEN}
/>;
```
It's recommended to add it to your docs layout with `links` option:
```tsx title="app/docs/layout.tsx"
import { DocsLayout, type DocsLayoutProps } from 'fumadocs-ui/layouts/notebook';
import type { ReactNode } from 'react';
import { baseOptions } from '@/app/layout.config';
import { source } from '@/lib/source';
import { GithubInfo } from 'fumadocs-ui/components/github-info';
const docsOptions: DocsLayoutProps = {
...baseOptions,
tree: source.pageTree,
links: [
{
type: 'custom',
children: (
<GithubInfo owner="fuma-nama" repo="fumadocs" className="lg:-mx-2" />
),
},
],
};
export default function Layout({ children }: { children: ReactNode }) {
return <DocsLayout {...docsOptions}>{children}</DocsLayout>;
}
```

View File

@ -1,45 +0,0 @@
---
title: GitHub 信息
description: 显示您的 GitHub 仓库信息
preview: githubInfo
---
## 使用方法
```tsx
import { GithubInfo } from 'fumadocs-ui/components/github-info';
<GithubInfo
owner="fuma-nama"
repo="fumadocs"
// 您自己的 GitHub 访问令牌(可选)
token={process.env.GITHUB_TOKEN}
/>;
```
建议将其添加到您的文档布局中,使用 `links` 选项:
```tsx title="app/docs/layout.tsx"
import { DocsLayout, type DocsLayoutProps } from 'fumadocs-ui/layouts/notebook';
import type { ReactNode } from 'react';
import { baseOptions } from '@/app/layout.config';
import { source } from '@/lib/source';
import { GithubInfo } from 'fumadocs-ui/components/github-info';
const docsOptions: DocsLayoutProps = {
...baseOptions,
tree: source.pageTree,
links: [
{
type: 'custom',
children: (
<GithubInfo owner="fuma-nama" repo="fumadocs" className="lg:-mx-2" />
),
},
],
};
export default function Layout({ children }: { children: ReactNode }) {
return <DocsLayout {...docsOptions}>{children}</DocsLayout>;
}
```

View File

@ -1,34 +0,0 @@
---
title: Zoomable Image
description: Allow zoom-in images in your documentation
preview: zoomImage
---
## Usage
Replace `img` with `ImageZoom` in your MDX components.
```tsx title="app/docs/[[...slug]]/page.tsx"
import { ImageZoom } from 'fumadocs-ui/components/image-zoom';
import defaultMdxComponents from 'fumadocs-ui/mdx';
return (
<MdxContent
components={{
...defaultMdxComponents,
img: (props) => <ImageZoom {...(props as any)} />,
// other Mdx components
}}
/>
);
```
Now image zoom will be automatically enabled on all images.
```mdx
![Test](/banner.png)
```
### Image Optimization
A default [`sizes` property](https://nextjs.org/docs/app/api-reference/components/image#sizes) will be defined for Next.js `<Image />` component if not specified.

View File

@ -1,34 +0,0 @@
---
title: 可缩放图片
description: 在文档中允许放大图片
preview: zoomImage
---
## 使用方法
在 MDX 组件中用 `ImageZoom` 替换 `img`。
```tsx title="app/docs/[[...slug]]/page.tsx"
import { ImageZoom } from 'fumadocs-ui/components/image-zoom';
import defaultMdxComponents from 'fumadocs-ui/mdx';
return (
<MdxContent
components={{
...defaultMdxComponents,
img: (props) => <ImageZoom {...(props as any)} />,
// 其他 Mdx 组件
}}
/>
);
```
现在,所有图片都将自动启用图片缩放功能。
```mdx
![Test](/banner.png)
```
### 图片优化
如果未指定,将为 Next.js `<Image />` 组件定义默认的 [`sizes` 属性](https://nextjs.org/docs/app/api-reference/components/image#sizes)。

View File

@ -1,5 +0,0 @@
---
title: Components
description: Additional components to improve your docs
index: true
---

View File

@ -1,5 +0,0 @@
---
title: 组件
description: 改进文档的额外组件
index: true
---

View File

@ -1,31 +0,0 @@
---
title: Inline TOC
description: Add Inline TOC into your documentation
preview: inlineTOC
---
## Usage
Pass TOC items to the component.
```mdx
import { InlineTOC } from 'fumadocs-ui/components/inline-toc';
<InlineTOC items={toc} />
```
### Use in Pages
You can add inline TOC into every page.
```tsx
<DocsPage>
...
<InlineTOC items={toc} />
...
</DocsPage>
```
## Reference
{/* <AutoTypeTable path="./content/docs/props.ts" name="InlineTOCProps" /> */}

View File

@ -1,31 +0,0 @@
---
title: 内联目录
description: 在文档中添加内联目录
preview: inlineTOC
---
## 使用方法
将 TOC 项目传递给组件。
```mdx
import { InlineTOC } from 'fumadocs-ui/components/inline-toc';
<InlineTOC items={toc} />
```
### 在页面中使用
您可以在每个页面中添加内联目录。
```tsx
<DocsPage>
...
<InlineTOC items={toc} />
...
</DocsPage>
```
## 参考
{/* <AutoTypeTable path="./content/docs/props.ts" name="InlineTOCProps" /> */}

View File

@ -1,35 +0,0 @@
---
title: Root Toggle
description: Switch between page trees
preview: rootToggle
---
## Usages
Add this component to your sidebar or other places you want.
```tsx
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { RootToggle } from 'fumadocs-ui/components/layout/root-toggle';
<DocsLayout
sidebar={{
banner: (
<RootToggle
options={[
{
title: 'Folder 1',
description: 'Pages in folder 1',
url: '/path/to/page-tree-1',
},
{
title: 'Folder 2',
description: 'Pages in folder 2',
url: '/path/to/page-tree-2',
},
]}
/>
),
}}
/>;
```

View File

@ -1,35 +0,0 @@
---
title: 根切换器
description: 在页面树之间切换
preview: rootToggle
---
## 使用方法
将此组件添加到您的侧边栏或您想要的其他地方。
```tsx
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { RootToggle } from 'fumadocs-ui/components/layout/root-toggle';
<DocsLayout
sidebar={{
banner: (
<RootToggle
options={[
{
title: '文件夹 1',
description: '文件夹 1 中的页面',
url: '/path/to/page-tree-1',
},
{
title: '文件夹 2',
description: '文件夹 2 中的页面',
url: '/path/to/page-tree-2',
},
]}
/>
),
}}
/>;
```

View File

@ -1,57 +0,0 @@
---
title: Steps
description: Adding steps to your docs
preview: steps
---
## Usage
Put your steps into the `Steps` container.
```mdx
import { Step, Steps } from 'fumadocs-ui/components/steps';
<Steps>
<Step>
### Hello World
</Step>
<Step>
### Hello World
</Step>
</Steps>
```
> We recommend using Tailwind CSS utility classes directly on Tailwind CSS projects.
### Without imports
You can use the Tailwind CSS utilities without importing it.
```mdx
<div className="fd-steps">
<div className="fd-step" />
</div>
```
It supports adding step styles to only headings with arbitrary variants.
```mdx
<div className='fd-steps [&_h3]:fd-step'>
### Hello World
</div>
```
<div className='fd-steps [&_h3]:fd-step'>
### Hello World
You no longer need to use the step component anymore.
</div>

View File

@ -1,57 +0,0 @@
---
title: 步骤
description: 在文档中添加步骤
preview: steps
---
## 使用方法
将您的步骤放入 `Steps` 容器中。
```mdx
import { Step, Steps } from 'fumadocs-ui/components/steps';
<Steps>
<Step>
### 你好世界
</Step>
<Step>
### 你好世界
</Step>
</Steps>
```
> 我们建议在 Tailwind CSS 项目中直接使用 Tailwind CSS 实用类。
### 不使用导入
您可以在不导入的情况下使用 Tailwind CSS 实用工具。
```mdx
<div className="fd-steps">
<div className="fd-step" />
</div>
```
它支持仅对带有任意变体的标题添加步骤样式。
```mdx
<div className='fd-steps [&_h3]:fd-step'>
### 你好世界
</div>
```
<div className='fd-steps [&_h3]:fd-step'>
### 你好世界
您不再需要使用步骤组件了。
</div>

View File

@ -1,146 +0,0 @@
---
title: Tabs
description:
A Tabs component built with Radix UI, with additional features such as
persistent and shared value.
preview: tabs
---
## Usage
Import it in your MDX documents.
```mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Javascript', 'Rust']}>
<Tab value="Javascript">Javascript is weird</Tab>
<Tab value="Rust">Rust is fast</Tab>
</Tabs>
```
### Without `value`
Without a `value`, it detects from the children index. Note that it might cause errors on re-renders, it's not encouraged if the tabs might change.
```mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Javascript', 'Rust']}>
<Tab>Javascript is weird</Tab>
<Tab>Rust is fast</Tab>
</Tabs>
```
#### Demo with Re-renders
<Tabs items={['Javascript', 'Rust']}>
<Tab>Javascript is weird</Tab>
<Tab>Rust is fast</Tab>
</Tabs>
{/* <WithoutValueTest /> */}
### Shared Value
By passing an `groupId` property, you can share a value across all tabs with the same
id.
```mdx
<Tabs groupId="language" items={['Javascript', 'Rust']}>
<Tab value="Javascript">Javascript is weird</Tab>
<Tab value="Rust">Rust is fast</Tab>
</Tabs>
```
### Persistent
You can enable persistent by passing a `persist` property. The value will be
stored in `localStorage`, with its id as the key.
```mdx
<Tabs groupId="language" items={['Javascript', 'Rust']} persist>
<Tab value="Javascript">Javascript is weird</Tab>
<Tab value="Rust">Rust is fast</Tab>
</Tabs>
```
> Persistent only works if you have passed an `id`.
### Default Value
Set a default value by passing `defaultIndex`.
```mdx
<Tabs items={['Javascript', 'Rust']} defaultIndex={1}>
<Tab value="Javascript">Javascript is weird</Tab>
<Tab value="Rust">Rust is fast</Tab>
</Tabs>
```
### Link to Tab
Use HTML `id` attribute to link to a specific tab.
```mdx
<Tabs items={['Javascript', 'Rust', 'C++']}>
<Tab value="Javascript">Javascript is weird</Tab>
<Tab value="Rust">Rust is fast</Tab>
<Tab id="tab-cpp" value="C++">
`Hello World`
</Tab>
</Tabs>
```
You can add the hash `#tab-cpp` to your URL and reload, the C++ tab will be activated.
<Tabs items={['Javascript', 'Rust', 'C++']}>
<Tab value="Javascript">Javascript is weird</Tab>
<Tab value="Rust">Rust is fast</Tab>
<Tab id="tab-cpp" value="C++">
`Hello World`
</Tab>
</Tabs>
Additionally, the `updateAnchor` property can be set to `true` in the `Tabs` component
to automatically update the URL hash whenever time a new tab is selected:
```mdx
<Tabs items={['Javascript', 'Rust', 'C++']} updateAnchor>
<Tab id="tab-js" value="Javascript">
Javascript is weird
</Tab>
<Tab id="tab-rs" value="Rust">
Rust is fast
</Tab>
<Tab id="tab-cpp" value="C++">
`Hello World`
</Tab>
</Tabs>
```
{/* <UrlBar /> */}
<Tabs items={['Hello', 'World']} updateAnchor>
<Tab id="tab-hello" value="Hello">
Hello!
</Tab>
<Tab id="tab-world" value="World">
World!
</Tab>
</Tabs>
### Advanced
You can use the styled Radix UI primitive directly from exported `Primitive`.
```mdx
import { Primitive } from 'fumadocs-ui/components/tabs';
<Primitive.Tabs>
<Primitive.TabsList>
<Primitive.TabsTrigger />
</Primitive.TabsList>
<Primitive.TabsContent />
</Primitive.Tabs>
```

View File

@ -1,114 +0,0 @@
---
title: 选项卡
description:
使用 Radix UI 构建的选项卡组件,具有持久性和共享值等附加功能。
preview: tabs
---
## 使用方法
在 MDX 文档中导入它。
```mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Javascript', 'Rust']}>
<Tab value="Javascript">Javascript 很奇怪</Tab>
<Tab value="Rust">Rust 很快</Tab>
</Tabs>
```
### 不使用 `value`
如果没有 `value`,它会从子元素索引中检测。请注意,这可能会在重新渲染时导致错误,如果选项卡可能会改变,不建议这样做。
```mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Javascript', 'Rust']}>
<Tab>Javascript 很奇怪</Tab>
<Tab>Rust 很快</Tab>
</Tabs>
```
### 共享值
通过传递 `groupId` 属性,您可以在具有相同 ID 的所有选项卡之间共享值。
```mdx
<Tabs groupId="language" items={['Javascript', 'Rust']}>
<Tab value="Javascript">Javascript 很奇怪</Tab>
<Tab value="Rust">Rust 很快</Tab>
</Tabs>
```
### 持久性
您可以通过传递 `persist` 属性启用持久性。该值将存储在 `localStorage` 中,以其 ID 作为键。
```mdx
<Tabs groupId="language" items={['Javascript', 'Rust']} persist>
<Tab value="Javascript">Javascript 很奇怪</Tab>
<Tab value="Rust">Rust 很快</Tab>
</Tabs>
```
> 持久性仅在您传递了 `id` 时有效。
### 默认值
通过传递 `defaultIndex` 设置默认值。
```mdx
<Tabs items={['Javascript', 'Rust']} defaultIndex={1}>
<Tab value="Javascript">Javascript 很奇怪</Tab>
<Tab value="Rust">Rust 很快</Tab>
</Tabs>
```
### 链接到选项卡
使用 HTML `id` 属性链接到特定选项卡。
```mdx
<Tabs items={['Javascript', 'Rust', 'C++']}>
<Tab value="Javascript">Javascript 很奇怪</Tab>
<Tab value="Rust">Rust 很快</Tab>
<Tab id="tab-cpp" value="C++">
`Hello World`
</Tab>
</Tabs>
```
您可以在 URL 中添加哈希 `#tab-cpp` 并重新加载C++ 选项卡将被激活。
此外,可以在 `Tabs` 组件中将 `updateAnchor` 属性设置为 `true`,以便在每次选择新选项卡时自动更新 URL 哈希:
```mdx
<Tabs items={['Javascript', 'Rust', 'C++']} updateAnchor>
<Tab id="tab-js" value="Javascript">
Javascript 很奇怪
</Tab>
<Tab id="tab-rs" value="Rust">
Rust 很快
</Tab>
<Tab id="tab-cpp" value="C++">
`Hello World`
</Tab>
</Tabs>
```
### 高级用法
您可以直接从导出的 `Primitive` 中使用样式化的 Radix UI 原语。
```mdx
import { Primitive } from 'fumadocs-ui/components/tabs';
<Primitive.Tabs>
<Primitive.TabsList>
<Primitive.TabsTrigger />
</Primitive.TabsList>
<Primitive.TabsContent />
</Primitive.Tabs>
```

View File

@ -1,34 +0,0 @@
---
title: Type Table
description: A table for documenting types
preview: typeTable
---
## Usage
It accepts a `type` property.
```mdx
import { TypeTable } from 'fumadocs-ui/components/type-table';
<TypeTable
type={{
percentage: {
description:
'The percentage of scroll position to display the roll button',
type: 'number',
default: 0.2,
},
}}
/>
```
## References
### Type Table
{/* <AutoTypeTable path="./content/docs/props.ts" name="TypeTableProps" /> */}
### Object Type
{/* <AutoTypeTable path="./content/docs/props.ts" name="ObjectTypeProps" /> */}

View File

@ -1,34 +0,0 @@
---
title: 类型表格
description: 用于记录类型的表格
preview: typeTable
---
## 使用方法
它接受一个 `type` 属性。
```mdx
import { TypeTable } from 'fumadocs-ui/components/type-table';
<TypeTable
type={{
percentage: {
description:
'显示滚动按钮的滚动位置百分比',
type: 'number',
default: 0.2,
},
}}
/>
```
## 参考
### Type Table
{/* <AutoTypeTable path="./content/docs/props.ts" name="TypeTableProps" /> */}
### Object Type
{/* <AutoTypeTable path="./content/docs/props.ts" name="ObjectTypeProps" /> */}

View File

@ -1,51 +0,0 @@
---
title: Overview
description: An overview of Fumadocs UI
---
## Architecture
### Page Tree
Navigation elements like sidebar take a [Page Tree](/docs/headless/page-tree) to render navigation links, it's a tree that describes all available pages and folders.
Normally, it is generated from your file structure using [`loader()`](/docs/headless/source-api), you can learn [how to organize pages](/docs/page-conventions).
## Customisation
### Layouts
You can use the exposed options of different layouts:
<Cards>
<Card title="Docs Layout" href="/docs/layouts/docs">
Layout for docs
</Card>
<Card title="Docs Page" href="/docs/layouts/page">
Layout for docs content
</Card>
<Card title="Notebook Layout" href="/docs/layouts/notebook">
A more compact version of Docs Layout
</Card>
<Card title="Home Layout" href="/docs/layouts/home-layout">
Layout for other pages
</Card>
</Cards>
### Components
Fumadocs UI also offers styled components for interactive examples to enhance your docs, you can customise them with exposed props like `style` and `className`.
See [Components](/docs/components).
### Design System
Since the design system is built on Tailwind CSS, you can customise it [with CSS Variables](/docs/theme#colors).
### CLI
If none of them suits you, Fumadocs CLI is a tool to install Fumadocs UI components and layouts to your codebase, similar to Shadcn UI. Allowing you to fully customise Fumadocs UI:
```mdx
npx fumadocs add
```

View File

@ -1,51 +0,0 @@
---
title: 概览
description: Fumadocs UI 的概览
---
## 架构
### 页面树
侧边栏等导航元素使用[页面树](/docs/headless/page-tree)来渲染导航链接,它是描述所有可用页面和文件夹的树形结构。
通常,它是使用 [`loader()`](/docs/headless/source-api) 从您的文件结构生成的,您可以了解[如何组织页面](/docs/page-conventions)。
## 自定义
### 布局
您可以使用不同布局的暴露选项:
<Cards>
<Card title="文档布局" href="/docs/layouts/docs">
文档的布局
</Card>
<Card title="文档页面" href="/docs/layouts/page">
文档内容的布局
</Card>
<Card title="笔记本布局" href="/docs/layouts/notebook">
文档布局的更紧凑版本
</Card>
<Card title="主页布局" href="/docs/layouts/home-layout">
其他页面的布局
</Card>
</Cards>
### 组件
Fumadocs UI 还提供了样式化组件,用于交互式示例以增强您的文档,您可以使用暴露的道具如 `style` 和 `className` 来自定义它们。
参见[组件](/docs/components)。
### 设计系统
由于设计系统是基于 Tailwind CSS 构建的,您可以[通过 CSS 变量](/docs/theme#colors)自定义它。
### CLI
如果这些都不适合您Fumadocs CLI 是一个工具,可以将 Fumadocs UI 组件和布局安装到您的代码库中,类似于 Shadcn UI。允许您完全自定义 Fumadocs UI
```mdx
npx fumadocs add
```

View File

@ -1,278 +0,0 @@
---
title: Quick Start
description: Getting Started with Fumadocs
icon: Album
---
## Introduction
Fumadocs <span className='text-fd-muted-foreground text-sm'>(Foo-ma docs)</span> is a **documentation framework** based on Next.js, designed to be fast, flexible,
and composes seamlessly into Next.js App Router.
Fumadocs has different parts:
<Cards>
<Card icon={<CpuIcon className="text-purple-300" />} title='Fumadocs Core'>
Handles most of the logic, including document search, content source adapters, and Markdown extensions.
</Card>
<Card icon={<PanelsTopLeft className="text-blue-300" />} title='Fumadocs UI'>
The default theme of Fumadocs offers a beautiful look for documentation sites and interactive components.
</Card>
<Card icon={<Database />} title='Content Source'>
The source of your content, can be a CMS or local data layers like [Content Collections](https://www.content-collections.dev) and [Fumadocs MDX](/docs/mdx), the official content source.
</Card>
<Card icon={<Terminal />} title='Fumadocs CLI'>
A command line tool to install UI components and automate things, useful for customizing layouts.
</Card>
</Cards>
<Callout title="Want to learn more?">
Read our in-depth [What is Fumadocs](/docs/what-is-fumadocs) introduction.
</Callout>
### Terminology
**Markdown/MDX:** Markdown is a markup language for creating formatted text. Fumadocs supports Markdown and MDX (superset of Markdown) out-of-the-box.
Although not required, some basic knowledge of Next.js App Router would be useful for further customisations.
## Automatic Installation
A minimum version of Node.js 18 required, note that Node.js 23.1 might have problems with Next.js production build.
<Tabs groupId='package-manager' persist items={['npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm create fumadocs-app
```
```bash tab="pnpm"
pnpm create fumadocs-app
```
```bash tab="yarn"
yarn create fumadocs-app
```
```bash tab="bun"
bun create fumadocs-app
```
</Tabs>
It will ask you the framework and content source to use, a new fumadocs app should be initialized. Now you can start hacking!
<Callout title='From Existing Codebase?'>
You can follow the [Manual Installation](/docs/manual-installation) guide to get started.
</Callout>
### Enjoy!
Create your first MDX file in the docs folder.
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Yo what's up
```
Run the app in development mode and see http://localhost:3000/docs.
```mdx
npm run dev
```
## Explore
In the project, you can see:
- `lib/source.ts`: Code for content source adapter, [`loader()`](/docs/headless/source-api) provides an interface to interact with your content source, and assigns URL to your pages.
- `app/layout.config.tsx`: Shared options for layouts, optional but preferred to keep.
| Route | Description |
| ------------------------- | ------------------------------------------------------ |
| `app/(home)` | The route group for your landing page and other pages. |
| `app/docs` | The documentation layout and pages. |
| `app/api/search/route.ts` | The Route Handler for search. |
### Writing Content
For authoring docs, make sure to read:
<Cards>
<Card href="/docs/markdown" title="Markdown">
Fumadocs has some additional features for authoring content too.
</Card>
<Card href="/docs/navigation" title="Navigation">
Learn how to customise navigation links/sidebar items.
</Card>
</Cards>
### Content Source
Content source handles all your content, like compiling Markdown files and validating frontmatter.
<Tabs items={['Fumadocs MDX', 'Custom Source']}>
<Tab value='Fumadocs MDX'>
Read the [Introduction](/docs/mdx) to learn how it handles your content.
A `source.config.ts` config file has been included, you can customise different options like frontmatter schema.
</Tab>
<Tab value='Custom Source'>
Fumadocs is not Markdown-exclusive. For other sources like Sanity, you can build a [custom content source](/docs/headless/custom-source).
</Tab>
</Tabs>
### Customise UI
See [Customisation Guide](/docs/customisation).
## FAQ
Some common questions you may encounter.
<Accordions>
<Accordion id='fix-monorepo-styling' title="How to fix stylings not being applied in Monorepo?">
Sometimes, `fumadocs-ui` is not installed in the workspace of your Tailwind CSS configuration file. (e.g. a monorepo setup).
You have to ensure the `fumadocs-ui` package is scanned by Tailwind CSS, and give a correct relative path to `@source`.
For example, add `../../` to point to the `node_modules` folder in root workspace.
```css
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* [!code --] */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
/* [!code ++] */
@source '../../../node_modules/fumadocs-ui/dist/**/*.js';
```
</Accordion>
<Accordion id='change-base-url' title="How to change the base route of /docs?">
You can change the base route of docs (e.g. from `/docs/page` to `/info/page`).
Since Fumadocs uses Next.js App Router, you can simply rename the route:
<Files>
<Folder name="app/docs" defaultOpen className="opacity-50" disabled>
<File name="layout.tsx" />
</Folder>
<Folder name="app/info" defaultOpen>
<File name="layout.tsx" />
</Folder>
</Files>
And tell Fumadocs to use the new route in `source.ts`:
```ts title="lib/source.ts"
import { loader } from 'fumadocs-core/source';
export const source = loader({
baseUrl: '/info',
// other options
});
```
</Accordion>
<Accordion id='dynamic-route' title="It uses Dynamic Route, will it be poor in performance?">
Next.js turns dynamic route into static routes when `generateStaticParams` is configured.
Hence, it is as fast as static pages.
You can enable Static Exports on Next.js to get a static build output. (Notice that Route Handler doesn't work with static export, you have to configure static search)
</Accordion>
<Accordion id='custom-layout-docs-page' title='How to create a page in /docs without docs layout?'>
Same as managing layouts in Next.js App Router, remove the original MDX file from content directory (`/content/docs`).
This ensures duplicated pages will not cause errors.
Now, You can add the page to another route group, which isn't a descendant of docs layout.
For example, under your `app` folder:
<Files>
<File name="(home)/docs/page.tsx" />
<Folder name="docs">
<File name="layout.tsx" />
<File name="[[...slug]]/page.tsx" />
</Folder>
</Files>
will replace the `/docs` page with your `page.tsx`.
</Accordion>
<Accordion id='multi-versions' title="How to implement docs with multi-version?">
Use a separate deployment for each version.
On Vercel, this can be done by creating another branch for a specific version on your GitHub repository.
To link to the sites of other versions, use the Links API or a custom navigation component.
</Accordion>
<Accordion id='multi-docs' title="How to implement multi-docs?">
We recommend to use [Sidebar Tabs](/docs/navigation/sidebar#sidebar-tabs).
</Accordion>
</Accordions>
## Video Tutorials
<YoutubeVideo url="https://www.youtube.com/embed/BPnK-YbISHQ?si=TH_tI3e4MCgMHzGr" />
## Learn More
New to here? Don't worry, we are welcome for your questions.
If you find anything confusing, please give your feedback on [Github Discussion](https://github.com/fuma-nama/fumadocs/discussions)!
<Cards>
<Card
href="/docs/static-export"
title="Configure Static Export"
description="Learn how to enable static export on your docs"
/>
<Card
href="/docs/search"
title="Customise Search"
description="Learn how to customise document search"
/>
<Card
href="/docs/theme"
title="Theming"
description="Add themes to Fumadocs UI"
/>
<Card
href="/docs/components"
title="Components"
description="See all available components to enhance your docs"
/>
</Cards>

View File

@ -1,253 +0,0 @@
---
title: 快速入门
description: Fumadocs 入门指南
icon: Album
---
## 简介
Fumadocs <span className='text-fd-muted-foreground text-sm'>(Foo-ma docs)</span> 是一个基于 Next.js 的**文档框架**,设计为快速、灵活,
并无缝集成到 Next.js App Router 中。
Fumadocs 由不同部分组成:
<Cards>
<Card icon={<CpuIcon className="text-purple-300" />} title='Fumadocs Core'>
处理大部分逻辑,包括文档搜索、内容源适配器和 Markdown 扩展。
</Card>
<Card icon={<PanelsTopLeft className="text-blue-300" />} title='Fumadocs UI'>
Fumadocs 的默认主题为文档站点提供了美观的外观和交互式组件。
</Card>
<Card icon={<Database />} title='Content Source'>
您内容的来源,可以是 CMS 或本地数据层,如 [Content Collections](https://www.content-collections.dev) 和 [Fumadocs MDX](/docs/mdx),即官方内容源。
</Card>
<Card icon={<Terminal />} title='Fumadocs CLI'>
一个命令行工具,用于安装 UI 组件和自动化操作,对于自定义布局非常有用。
</Card>
</Cards>
<Callout title="想了解更多?">
阅读我们深入的 [什么是 Fumadocs](/docs/what-is-fumadocs) 介绍。
</Callout>
### 术语
**Markdown/MDX:** Markdown 是一种用于创建格式化文本的标记语言。Fumadocs 默认支持 Markdown 和 MDXMarkdown 的超集)。
虽然不是必需的,但对 Next.js App Router 的基本了解对于进一步的自定义会很有帮助。
## 自动安装
需要 Node.js 18 或更高版本,请注意 Node.js 23.1 可能在 Next.js 生产构建中存在问题。
<Tabs groupId='package-manager' persist items={['npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm create fumadocs-app
```
```bash tab="pnpm"
pnpm create fumadocs-app
```
```bash tab="yarn"
yarn create fumadocs-app
```
```bash tab="bun"
bun create fumadocs-app
```
</Tabs>
它会询问您要使用的框架和内容源,随后将初始化一个新的 fumadocs 应用程序。现在您可以开始动手了!
<Callout title='从现有代码库开始?'>
您可以按照 [手动安装](/docs/manual-installation) 指南开始。
</Callout>
### 尽情使用!
在 docs 文件夹中创建您的第一个 MDX 文件。
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Yo what's up
```
在开发模式下运行应用程序并查看 http://localhost:3000/docs。
```mdx
npm run dev
```
## 探索
在项目中,您可以看到:
- `lib/source.ts`:内容源适配器的代码,[`loader()`](/docs/headless/source-api) 提供了与内容源交互的接口,并为您的页面分配 URL。
- `app/layout.config.tsx`:布局的共享选项,可选但建议保留。
| 路由 | 描述 |
| ------------------------- | -------------------------------------- |
| `app/(home)` | 您的登陆页面和其他页面的路由组。 |
| `app/docs` | 文档布局和页面。 |
| `app/api/search/route.ts` | 搜索的路由处理器。 |
### 编写内容
对于编写文档,请务必阅读:
<Cards>
<Card href="/docs/markdown" title="Markdown">
Fumadocs 还有一些额外的内容创作功能。
</Card>
<Card href="/docs/navigation" title="Navigation">
了解如何自定义导航链接/侧边栏项目。
</Card>
</Cards>
### 内容源
内容源处理您的所有内容,例如编译 Markdown 文件和验证前言。
<Tabs items={['Fumadocs MDX', 'Custom Source']}>
<Tab value='Fumadocs MDX'>
阅读 [介绍](/docs/mdx) 了解它如何处理您的内容。
项目中已包含 `source.config.ts` 配置文件,您可以自定义不同的选项,如前言模式。
</Tab>
<Tab value='Custom Source'>
Fumadocs 不仅限于 Markdown。对于其他源如 Sanity您可以构建 [自定义内容源](/docs/headless/custom-source)。
</Tab>
</Tabs>
### 自定义 UI
请参阅 [自定义指南](/docs/customisation)。
## 常见问题
您可能遇到的一些常见问题。
<Accordions>
<Accordion id='fix-monorepo-styling' title="如何修复 Monorepo 中样式不应用的问题?">
有时,`fumadocs-ui` 没有安装在您的 Tailwind CSS 配置文件的工作区中(例如,在 monorepo 设置中)。
您必须确保 Tailwind CSS 扫描 `fumadocs-ui` 包,并为 `@source` 提供正确的相对路径。
例如,添加 `../../` 指向根工作区中的 `node_modules` 文件夹。
```css
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* [!code --] */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
/* [!code ++] */
@source '../../../node_modules/fumadocs-ui/dist/**/*.js';
```
</Accordion>
<Accordion id='change-base-url' title="如何更改 /docs 的基本路由?">
您可以更改文档的基本路由(例如,从 `/docs/page` 更改为 `/info/page`)。
由于 Fumadocs 使用 Next.js App Router您可以简单地重命名路由
<Files>
<Folder name="app/docs" defaultOpen className="opacity-50" disabled>
<File name="layout.tsx" />
</Folder>
<Folder name="app/info" defaultOpen>
<File name="layout.tsx" />
</Folder>
</Files>
并在 `source.ts` 中告诉 Fumadocs 使用新的路由:
```ts title="lib/source.ts"
import { loader } from 'fumadocs-core/source';
export const source = loader({
baseUrl: '/info',
// other options
});
```
</Accordion>
<Accordion id='dynamic-route' title="它使用动态路由,性能会很差吗?">
当配置了 `generateStaticParams` 时Next.js 会将动态路由转换为静态路由。
因此,它与静态页面一样快。
您可以在 Next.js 上启用静态导出,获得静态构建输出。(请注意,路由处理器不适用于静态导出,您必须配置静态搜索)
</Accordion>
<Accordion id='custom-layout-docs-page' title='如何在 /docs 中创建没有文档布局的页面?'>
与在 Next.js App Router 中管理布局相同,从内容目录(`/content/docs`)中删除原始 MDX 文件。
这确保重复的页面不会导致错误。
现在,您可以将页面添加到另一个路由组,该组不是文档布局的后代。
例如,在您的 `app` 文件夹下:
<Files>
<File name="(home)/docs/page.tsx" />
<Folder name="docs">
<File name="layout.tsx" />
<File name="[[...slug]]/page.tsx" />
</Folder>
</Files>
将用您的 `page.tsx` 替换 `/docs` 页面。
</Accordion>
<Accordion id='multi-versions' title="如何实现多版本文档?">
为每个版本使用单独的部署。
在 Vercel 上,可以通过在 GitHub 存储库中为特定版本创建另一个分支来实现。
要链接到其他版本的站点,请使用 Links API 或自定义导航组件。
</Accordion>
<Accordion id='multi-docs' title="如何实现多文档?">
我们建议使用 [侧边栏标签](/docs/navigation/sidebar#sidebar-tabs)。
</Accordion>
</Accordions>
## 视频教程
<YoutubeVideo url="https://www.youtube.com/embed/BPnK-YbISHQ?si=TH_tI3e4MCgMHzGr" />
## 了解更多
刚来这里?别担心,我们欢迎您的问题。

View File

@ -1,222 +0,0 @@
---
title: Internationalization
description: Support multiple languages in your documentation
---
<Callout title='Before you get started'>
Fumadocs is not a full-powered i18n library, it manages only its own components and utilities.
You can use other libraries like [next-intl](https://github.com/amannn/next-intl) for the rest of your app.
Read the [Next.js Docs](https://nextjs.org/docs/app/building-your-application/routing/internationalization) to learn more about implementing I18n in Next.js.
</Callout>
## Manual Setup
Define the i18n configurations in a file, we will import it with `@/ilb/i18n` in this guide.
{/* <include cwd meta='title="lib/i18n.ts"'>
../../examples/i18n/lib/i18n.ts
</include> */}
Pass it to the source loader.
```ts title="lib/source.ts"
import { i18n } from '@/lib/i18n';
import { loader } from 'fumadocs-core/source';
export const source = loader({
i18n, // [!code highlight]
// other options
});
```
And update Fumadocs UI layout options.
```tsx title="app/layout.config.tsx"
import { i18n } from '@/lib/i18n';
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export function baseOptions(locale: string): BaseLayoutProps {
return {
i18n,
// different props based on `locale`
};
}
```
### Middleware
Create a middleware that redirects users to appropriate locale.
```json doc-gen:file
{
"file": "../../examples/i18n/middleware.ts",
"codeblock": {
"lang": "ts",
"meta": "title=\"middleware.ts\""
}
}
```
See [Middleware](/docs/headless/internationalization#middleware) for customisable options.
> Note that this is optional, you can also use your own middleware or the one provided by i18n libraries.
### Routing
Create a `/app/[lang]` folder, and move all files (e.g. `page.tsx`, `layout.tsx`) from `/app` to the folder.
Wrap the root provider inside `I18nProvider`, and provide available languages & translations to it.
Note that only English translations are provided by default.
```tsx title="app/[lang]/layout.tsx"
import { RootProvider } from 'fumadocs-ui/provider';
import { I18nProvider, type Translations } from 'fumadocs-ui/i18n';
const cn: Partial<Translations> = {
search: 'Translated Content',
// other translations
};
// available languages that will be displayed on UI
// make sure `locale` is consistent with your i18n config
const locales = [
{
name: 'English',
locale: 'en',
},
{
name: 'Chinese',
locale: 'cn',
},
];
export default async function RootLayout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: React.ReactNode;
}) {
const lang = (await params).lang;
return (
<html lang={lang}>
<body>
<I18nProvider
locale={lang}
locales={locales}
translations={{ cn }[lang]}
>
<RootProvider>{children}</RootProvider>
</I18nProvider>
</body>
</html>
);
}
```
### Pass Locale
Pass the locale to Fumadocs in your pages and layouts.
{/* ```tsx title="/app/[lang]/(home)/layout.tsx" tab="Home Layout"
import type { ReactNode } from 'react';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return <HomeLayout {...baseOptions(lang)}>{children}</HomeLayout>;
}
```
```tsx title="/app/[lang]/docs/layout.tsx" tab="Docs Layout"
import type { ReactNode } from 'react';
import { source } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return (
<DocsLayout {...baseOptions(lang)} tree={source.pageTree[lang]}>
{children}
</DocsLayout>
);
}
```
```ts title="page.tsx" tab="Docs Page"
import { source } from '@/lib/source';
export default async function Page({
params,
}: {
params: Promise<{ lang: string; slug?: string[] }>;
}) {
const { slug, lang } = await params;
// get page
source.getPage(slug); // [!code --]
source.getPage(slug, lang); // [!code ++]
// get pages
source.getPages(); // [!code --]
source.getPages(lang); // [!code ++]
}
``` */}
### Search
Configure i18n on your search solution.
- **Built-in Search (Orama):**
For [Supported Languages](https://docs.orama.com/open-source/supported-languages#officially-supported-languages), no further changes are needed.
Otherwise, additional config is required (e.g. Chinese & Japanese). See [Special Languages](/docs/headless/search/orama#special-languages).
- **Cloud Solutions (e.g. Algolia):**
They usually have official support for multilingual.
## Writing Documents
{/* <include>../../shared/page-conventions.i18n.mdx</include> */}
## Navigation
Fumadocs only handles navigation for its own layouts (e.g. sidebar).
For other places, you can use the `useParams` hook to get the locale from url, and attend it to `href`.
```tsx
import Link from 'next/link';
import { useParams } from 'next/navigation';
const { lang } = useParams();
return <Link href={`/${lang}/another-page`}>This is a link</Link>;
```
In addition, the [`fumadocs-core/dynamic-link`](/docs/headless/components/link#dynamic-hrefs) component supports dynamic hrefs, you can use it to attend the locale prefix.
It is useful for Markdown/MDX content.
```mdx title="content.mdx"
import { DynamicLink } from 'fumadocs-core/dynamic-link';
<DynamicLink href="/[lang]/another-page">This is a link</DynamicLink>
```

View File

@ -1,222 +0,0 @@
---
title: 国际化
description: 在您的文档中支持多种语言
---
<Callout title='开始之前'>
Fumadocs 不是一个功能齐全的 i18n 库,它只管理自己的组件和工具。
您可以使用其他库,如 [next-intl](https://github.com/amannn/next-intl),用于应用程序的其余部分。
阅读 [Next.js 文档](https://nextjs.org/docs/app/building-your-application/routing/internationalization),了解更多关于在 Next.js 中实现 I18n 的信息。
</Callout>
## 手动设置
在一个文件中定义 i18n 配置,我们将在本指南中使用 `@/ilb/i18n` 导入它。
{/* <include cwd meta='title="lib/i18n.ts"'>
../../examples/i18n/lib/i18n.ts
</include> */}
将其传递给源加载器。
```ts title="lib/source.ts"
import { i18n } from '@/lib/i18n';
import { loader } from 'fumadocs-core/source';
export const source = loader({
i18n, // [!code highlight]
// other options
});
```
并更新 Fumadocs UI 布局选项。
```tsx title="app/layout.config.tsx"
import { i18n } from '@/lib/i18n';
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export function baseOptions(locale: string): BaseLayoutProps {
return {
i18n,
// different props based on `locale`
};
}
```
### 中间件
创建一个将用户重定向到适当语言环境的中间件。
```json doc-gen:file
{
"file": "../../examples/i18n/middleware.ts",
"codeblock": {
"lang": "ts",
"meta": "title=\"middleware.ts\""
}
}
```
查看[中间件](/docs/headless/internationalization#middleware)了解可自定义选项。
> 请注意,这是可选的,您也可以使用自己的中间件或 i18n 库提供的中间件。
### 路由
创建一个 `/app/[lang]` 文件夹,并将所有文件(例如 `page.tsx`、`layout.tsx`)从 `/app` 移动到该文件夹。
将根提供程序包装在 `I18nProvider` 中,并向其提供可用语言和翻译。
请注意,默认情况下只提供英文翻译。
```tsx title="app/[lang]/layout.tsx"
import { RootProvider } from 'fumadocs-ui/provider';
import { I18nProvider, type Translations } from 'fumadocs-ui/i18n';
const cn: Partial<Translations> = {
search: 'Translated Content',
// other translations
};
// available languages that will be displayed on UI
// make sure `locale` is consistent with your i18n config
const locales = [
{
name: 'English',
locale: 'en',
},
{
name: 'Chinese',
locale: 'cn',
},
];
export default async function RootLayout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: React.ReactNode;
}) {
const lang = (await params).lang;
return (
<html lang={lang}>
<body>
<I18nProvider
locale={lang}
locales={locales}
translations={{ cn }[lang]}
>
<RootProvider>{children}</RootProvider>
</I18nProvider>
</body>
</html>
);
}
```
### 传递区域设置
在您的页面和布局中将区域设置传递给 Fumadocs。
{/* ```tsx title="/app/[lang]/(home)/layout.tsx" tab="Home Layout"
import type { ReactNode } from 'react';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return <HomeLayout {...baseOptions(lang)}>{children}</HomeLayout>;
}
```
```tsx title="/app/[lang]/docs/layout.tsx" tab="Docs Layout"
import type { ReactNode } from 'react';
import { source } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/app/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return (
<DocsLayout {...baseOptions(lang)} tree={source.pageTree[lang]}>
{children}
</DocsLayout>
);
}
```
```ts title="page.tsx" tab="Docs Page"
import { source } from '@/lib/source';
export default async function Page({
params,
}: {
params: Promise<{ lang: string; slug?: string[] }>;
}) {
const { slug, lang } = await params;
// get page
source.getPage(slug); // [!code --]
source.getPage(slug, lang); // [!code ++]
// get pages
source.getPages(); // [!code --]
source.getPages(lang); // [!code ++]
}
``` */}
### 搜索
在您的搜索解决方案上配置 i18n。
- **内置搜索 (Orama)**
对于[支持的语言](https://docs.orama.com/open-source/supported-languages#officially-supported-languages),无需进一步更改。
否则,需要额外配置(例如中文和日语)。请参阅[特殊语言](/docs/headless/search/orama#special-languages)。
- **云解决方案(例如 Algolia**
它们通常官方支持多语言。
## 编写文档
{/* <include>../../shared/page-conventions.i18n.mdx</include> */}
## 导航
Fumadocs 只处理其自己的布局(例如侧边栏)的导航。
对于其他地方,您可以使用 `useParams` 钩子从 url 获取区域设置,并将其添加到 `href`。
```tsx
import Link from 'next/link';
import { useParams } from 'next/navigation';
const { lang } = useParams();
return <Link href={`/${lang}/another-page`}>This is a link</Link>;
```
另外,[`fumadocs-core/dynamic-link`](/docs/headless/components/link#dynamic-hrefs) 组件支持动态 hrefs您可以使用它来添加区域设置前缀。
这对于 Markdown/MDX 内容很有用。
```mdx title="content.mdx"
import { DynamicLink } from 'fumadocs-core/dynamic-link';
<DynamicLink href="/[lang]/another-page">This is a link</DynamicLink>
```

View File

@ -1,166 +0,0 @@
---
title: Docs Layout
description: The layout of documentation
---
The layout of documentation pages, it includes a sidebar and mobile-only navbar.
> It is a server component, you should not reference it in a client component.
## Usage
Pass your page tree to the component.
```tsx title="layout.tsx"
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/app/layout.config';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout {...baseOptions} tree={tree}>
{children}
</DocsLayout>
);
}
```
{/* <AutoTypeTable
path="./content/docs/props.ts"
type="Omit<DocsLayoutProps, 'children' | 'disableThemeSwitch'>"
/> */}
## Sidebar
```tsx title="layout.tsx"
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
<DocsLayout
sidebar={{
// sidebar options:
enabled: true,
}}
/>;
```
{/* <AutoTypeTable path="./content/docs/props.ts" name="SidebarProps" /> */}
### Sidebar Tabs
See [Navigation Guide](/docs/navigation/sidebar#sidebar-tabs) for usages.
#### Decoration
Change the icon/styles of tabs.
```tsx
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
<DocsLayout
sidebar={{
tabs: {
transform: (option, node) => ({
...option,
icon: 'my icon',
}),
},
}}
/>;
```
## Nav
A mobile-only navbar, we recommend to customise it from `baseOptions`.
<div className='max-w-[460px] mx-auto'>
![Docs Nav](/images/docs/docs-nav.png)
</div>
```tsx
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export const baseOptions: BaseLayoutProps = {
githubUrl: 'https://github.com/fuma-nama/fumadocs',
nav: {
title: 'My App',
},
};
```
{/* <AutoTypeTable
path="./content/docs/props.ts"
type="Omit<NavbarProps, 'children'>"
/> */}
### Transparent Mode
To make the navbar background transparent, you can configure transparent mode.
```tsx
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export const baseOptions: BaseLayoutProps = {
nav: {
transparentMode: 'top',
},
};
```
| Mode | Description |
| -------- | ---------------------------------------- |
| `always` | Always use a transparent background |
| `top` | When at the top of page |
| `none` | Disable transparent background (default) |
### Replace Navbar
To replace the navbar in Docs Layout, set `nav.component` to your own component.
```tsx title="layout.tsx"
import { baseOptions } from '@/app/layout.config';
import { DocsLayout } from 'fumadocs-ui/layouts/notebook';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
{...baseOptions}
nav={{
component: <CustomNavbar />,
}}
>
{children}
</DocsLayout>
);
}
```
Fumadocs uses **CSS Variables** to share the size of layout components, and fit each layout component into appropriate position.
You need to override `--fd-nav-height` to the exact height of your custom navbar, this can be done with a CSS stylesheet (e.g. in `global.css`):
```css
:root {
--fd-nav-height: 80px !important;
}
```
## Advanced
### Disable Prefetching
By default, it uses the Next.js Link component with prefetch enabled.
When the link component appears into the browser viewport, the content (RSC payload) will be prefetched.
On Vercel, this may cause a high usage of serverless functions and Data Cache.
It can also hit the limits of some other hosting platforms.
You can disable prefetching to reduce the amount of RSC requests.
```tsx
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
<DocsLayout sidebar={{ prefetch: false }} />;
```

View File

@ -1,160 +0,0 @@
---
title: 文档布局
description: 文档的布局
---
文档页面的布局,它包括一个侧边栏和仅限移动设备的导航栏。
> 它是一个服务器组件,您不应该在客户端组件中引用它。
## 使用方法
将您的页面树传递给组件。
```tsx title="layout.tsx"
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/app/layout.config';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout {...baseOptions} tree={tree}>
{children}
</DocsLayout>
);
}
```
{/* <AutoTypeTable
path="./content/docs/props.ts"
type="Omit<DocsLayoutProps, 'children' | 'disableThemeSwitch'>"
/> */}
## 侧边栏
```tsx title="layout.tsx"
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
<DocsLayout
sidebar={{
// sidebar options:
enabled: true,
}}
/>;
```
{/* <AutoTypeTable path="./content/docs/props.ts" name="SidebarProps" /> */}
### 侧边栏标签
有关用法,请参见[导航指南](/docs/navigation/sidebar#sidebar-tabs)。
#### 装饰
更改标签的图标/样式。
```tsx
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
<DocsLayout
sidebar={{
tabs: {
transform: (option, node) => ({
...option,
icon: 'my icon',
}),
},
}}
/>;
```
## 导航栏
一个仅限移动设备的导航栏,我们建议从 `baseOptions` 自定义它。
```tsx
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export const baseOptions: BaseLayoutProps = {
githubUrl: 'https://github.com/fuma-nama/fumadocs',
nav: {
title: 'My App',
},
};
```
{/* <AutoTypeTable
path="./content/docs/props.ts"
type="Omit<NavbarProps, 'children'>"
/> */}
### 透明模式
要使导航栏背景透明,您可以配置透明模式。
```tsx
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export const baseOptions: BaseLayoutProps = {
nav: {
transparentMode: 'top',
},
};
```
| 模式 | 描述 |
| -------- | ------------------------------ |
| `always` | 始终使用透明背景 |
| `top` | 在页面顶部时 |
| `none` | 禁用透明背景(默认) |
### 替换导航栏
要替换文档布局中的导航栏,将 `nav.component` 设置为您自己的组件。
```tsx title="layout.tsx"
import { baseOptions } from '@/app/layout.config';
import { DocsLayout } from 'fumadocs-ui/layouts/notebook';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
{...baseOptions}
nav={{
component: <CustomNavbar />,
}}
>
{children}
</DocsLayout>
);
}
```
Fumadocs 使用 **CSS 变量**来共享布局组件的大小,并将每个布局组件放置在适当的位置。
您需要将 `--fd-nav-height` 覆盖为自定义导航栏的确切高度,这可以通过 CSS 样式表(例如在 `global.css` 中)完成:
```css
:root {
--fd-nav-height: 80px !important;
}
```
## 高级
### 禁用预取
默认情况下,它使用启用了预取的 Next.js Link 组件。
当链接组件出现在浏览器视口中时内容RSC 有效载荷)将被预取。
在 Vercel 上,这可能会导致大量使用无服务器函数和数据缓存。
它也可能会达到一些其他托管平台的限制。
您可以禁用预取以减少 RSC 请求的数量。
```tsx
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
<DocsLayout sidebar={{ prefetch: false }} />;
```

View File

@ -1,33 +0,0 @@
---
title: Home Layout
description: Shared layout for other pages
---
## Usage
Add a navbar and search dialog across other pages.
```tsx title="/app/(home)/layout.tsx"
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/layout.config';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return <HomeLayout {...baseOptions}>{children}</HomeLayout>;
}
```
Create a [Route Group](https://nextjs.org/docs/app/building-your-application/routing/route-groups) to share the same layout across multiple pages.
<Files>
<Folder name="(home)" defaultOpen>
<File name="page.tsx" />
<File name="layout.tsx" />
</Folder>
<Folder name="/docs">
<Folder name={'[[..slugs]]'}>
<File name="page.tsx" />
</Folder>
<File name="layout.tsx" />
</Folder>
</Files>

View File

@ -1,33 +0,0 @@
---
title: 主页布局
description: 其他页面的共享布局
---
## 使用方法
在其他页面上添加导航栏和搜索对话框。
```tsx title="/app/(home)/layout.tsx"
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/layout.config';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return <HomeLayout {...baseOptions}>{children}</HomeLayout>;
}
```
创建一个[路由组](https://nextjs.org/docs/app/building-your-application/routing/route-groups)来在多个页面之间共享相同的布局。
<Files>
<Folder name="(home)" defaultOpen>
<File name="page.tsx" />
<File name="layout.tsx" />
</Folder>
<Folder name="/docs">
<Folder name={'[[..slugs]]'}>
<File name="page.tsx" />
</Folder>
<File name="layout.tsx" />
</Folder>
</Files>

View File

@ -1,32 +0,0 @@
---
title: Notebook
description: A more compact version of Docs Layout
---
## Usage
Enable the notebook layout with `fumadocs-ui/layouts/notebook`, it's a more compact layout than the default one.
![Notebook](/images/docs/notebook.png)
```tsx title="layout.tsx"
import { DocsLayout } from 'fumadocs-ui/layouts/notebook';
import { baseOptions } from '@/app/layout.config';
import { source } from '@/lib/source';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
{...baseOptions}
// the position of navbar
nav={{ ...baseOptions.nav, mode: 'top' }}
// the position of Sidebar Tabs
tabMode="navbar"
tree={source.pageTree}
>
{children}
</DocsLayout>
);
}
```

View File

@ -1,32 +0,0 @@
---
title: 笔记本
description: 文档布局的更紧凑版本
---
## 使用方法
使用 `fumadocs-ui/layouts/notebook` 启用笔记本布局,它比默认布局更加紧凑。
![Notebook](/images/docs/notebook.png)
```tsx title="layout.tsx"
import { DocsLayout } from 'fumadocs-ui/layouts/notebook';
import { baseOptions } from '@/app/layout.config';
import { source } from '@/lib/source';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
{...baseOptions}
// the position of navbar
nav={{ ...baseOptions.nav, mode: 'top' }}
// the position of Sidebar Tabs
tabMode="navbar"
tree={source.pageTree}
>
{children}
</DocsLayout>
);
}
```

View File

@ -1,217 +0,0 @@
---
title: Docs Page
description: A page in your documentation
---
Page is the base element of a documentation, it includes Table of contents,
Footer, and Breadcrumb.
## Usage
```tsx title="page.tsx"
import {
DocsPage,
DocsDescription,
DocsTitle,
DocsBody,
} from 'fumadocs-ui/page';
<DocsPage>
<DocsTitle>title</DocsTitle>
<DocsDescription>description</DocsDescription>
<DocsBody>...</DocsBody>
</DocsPage>;
```
<Callout type='info' title='Good to know'>
Instead of rendering the title with `DocsTitle` in `page.tsx`, you can put the title into MDX file.
This will render the title in the MDX body.
</Callout>
### Body
It applies the [Typography](/docs/theme#typography) styles, wrap your content inside.
```tsx
import { DocsBody } from 'fumadocs-ui/page';
<DocsBody>
<h1>This heading looks good!</h1>
</DocsBody>;
```
### Category
Optional, link the other pages in its (page tree) folder with cards.
> You can use this component without `<DocsPage />`.
```tsx title="page.tsx"
import { source } from '@/lib/source';
import { DocsCategory } from 'fumadocs-ui/page';
const page = source.getPage(['...']);
<DocsCategory page={page} from={source} />;
```
**Demo:**
{/* DocsCategory is not supported */}
{/* <DocsCategory /> */}
## Configurations
### Full Mode
To extend the page to fill up all available space, pass `full` to the page component.
This will force TOC to be shown as a popover.
```tsx
import { DocsPage } from 'fumadocs-ui/page';
<DocsPage full>...</DocsPage>;
```
### Table of Contents
An overview of all the headings in your article, it requires an array of headings.
For Markdown and MDX documents, You can obtain it using the
[TOC Utility](/docs/headless/utils/get-toc). Content sources like Fumadocs MDX offer this out-of-the-box.
```tsx
import { DocsPage } from 'fumadocs-ui/page';
<DocsPage toc={headings}>...</DocsPage>;
```
Customise or disable TOC from your documentation with the `tableOfContent` option.
```tsx
import { DocsPage } from 'fumadocs-ui/page';
<DocsPage tableOfContent={options}>...</DocsPage>;
```
{/* <AutoTypeTable path="./content/docs/props.ts" name="TOCProps" /> */}
#### Style
You can choose another style for TOC, like `clerk` inspired by https://clerk.com:
```tsx
import { DocsPage } from 'fumadocs-ui/page';
<DocsPage
tableOfContent={{
style: 'clerk',
}}
>
...
</DocsPage>;
```
#### Popover Mode
On smaller devices, it is shown on a popover instead.
Customise it with the `tableOfContentPopover` option.
```tsx
import { DocsPage } from 'fumadocs-ui/page';
<DocsPage tableOfContentPopover={options}>...</DocsPage>;
```
{/* <AutoTypeTable path="./content/docs/props.ts" name="TOCPopoverProps" /> */}
### Last Updated Time
Display last updated time of the page.
```tsx
import { DocsPage } from 'fumadocs-ui/page';
<DocsPage lastUpdate={new Date(lastModifiedTime)} />;
```
Since you might have different version controls (e.g. Github) or it's from
remote sources like Sanity, Fumadocs UI doesn't display the last updated time by
default.
For Github hosted documents, you can use
the [`getGithubLastEdit`](/docs/headless/utils/git-last-edit) utility.
```tsx
import { DocsPage } from 'fumadocs-ui/page';
import { getGithubLastEdit } from 'fumadocs-core/server';
const time = await getGithubLastEdit({
owner: 'fuma-nama',
repo: 'fumadocs',
path: `content/docs/${page.file.path}`,
});
<DocsPage lastUpdate={new Date(time)} />;
```
<Callout type='info' title='Note'>
You can also specify the last updated time of documents (e.g. using frontmatter).
Don't forget to [update the schema type](/docs/mdx/collections#schema) on Fumadocs MDX first.
</Callout>
### Edit on GitHub
Add "Edit on GitHub" button to the page.
```tsx
import { DocsPage } from 'fumadocs-ui/page';
<DocsPage
editOnGithub={{
owner: 'fuma-nama',
repo: 'fumadocs',
sha: 'main',
// file path, make sure it's valid
path: `content/docs/${page.file.path}`,
}}
/>;
```
### Footer
Footer is a navigation element that has two buttons to jump to the next and previous pages. When not specified, it shows the neighbour pages found from page tree.
Customise the footer with the `footer` option.
```tsx
import { DocsPage, DocsBody } from 'fumadocs-ui/page';
<DocsPage footer={options}>
<DocsBody>...</DocsBody>
</DocsPage>;
```
{/* <AutoTypeTable path="./content/docs/props.ts" name="FooterProps" /> */}
### Breadcrumb
A navigation element, shown only when user is navigating in folders.
{/* <AutoTypeTable path="./content/docs/props.ts" name="BreadcrumbProps" /> */}
### MDX Page
In conjunction of Fumadocs MDX, you may create a `page.mdx` file and add the following.
```mdx
export { withArticle as default } from 'fumadocs-ui/page';
## Hello World
```
This creates a page with MDX, with proper typography styles applied.

View File

@ -1,238 +0,0 @@
---
title: 文档页面
description: 文档中的页面
---
可以渲染完整页面的组件(标题、目录等)。
## 正文
```tsx title="page.tsx"
import { DocsPage } from 'fumadocs-ui/page';
export default function Page({ params }: { params: { slug?: string[] } }) {
const page = getPage(params);
return (
<DocsPage
title={page.title}
description={page.description}
mdx={page.body}
toc={page.toc}
/>
);
}
```
{/* <AutoTypeTable
path="./content/docs/props.ts"
type="Omit<DocsPageProps, 'children'>"
/> */}
### SEO
为页面添加 SEO 优化,有几种方法。首先,允许文档生成器提供 `metadata` 帮助程序:
```tsx title="api.ts"
export { createMetadata } from 'fumadocs-core/docs';
```
默认值包括 **标题**、**描述**、**开放图形**Open Graph和 **Twitter** 图片、**规范**CanonicalURL 和 locale 元数据。
现在您可以直接使用它:
```tsx title="page.tsx"
import type { Metadata } from 'next';
import { createMetadata } from '@/app/api';
export async function generateMetadata({
params,
}: {
params: { slug?: string[] };
}): Promise<Metadata> {
const page = await getPage(params);
return createMetadata({
page,
params,
});
}
```
或者您可以手动构建它:
```tsx title="page.tsx"
import type { Metadata } from 'next';
import { absoluteUrl } from 'fumadocs-core/utils/absolute-url';
export const metadata: Metadata = {
title: 'My Page',
description: 'Page Description',
openGraph: {
title: 'My Page',
description: 'Page Description',
type: 'article',
url: absoluteUrl('/docs/my-page'),
},
twitter: {
title: 'My Page',
description: 'Page Description',
card: 'summary_large_image',
},
alternates: {
canonical: absoluteUrl('/docs/my-page'),
},
};
```
## 内容目录
支持无限级别的标题。从页面内容中提取,您应该通过 `toc` 字段传递它。
```tsx title="page.tsx"
import { DocsPage } from 'fumadocs-ui/page';
import { getToc } from 'fumadocs-core';
export default function Page() {
const toc = getToc(content);
return <DocsPage toc={toc} />;
}
```
{/* <AutoTypeTable path="./content/docs/props.ts" name="TOCItemProps[]" /> */}
### 自定义内容目录
可以定制 TOC目录的呈现方式但您仍然需要通过 `toc` 字段传递真实的 TOC 项目。
```tsx title="page.tsx"
import { DocsPage } from 'fumadocs-ui/page';
export default function Page() {
return (
<DocsPage tocClassName="hidden lg:block" toc={toc}>
<div>Custom TOC</div>
</DocsPage>
);
}
```
## 最后更新时间
```tsx title="page.tsx"
import { DocsPage } from 'fumadocs-ui/page';
export default function Page() {
return <DocsPage lastUpdatedAt={new Date()} />;
}
```
## 页脚
```tsx title="layout.tsx"
import { DocsPage } from 'fumadocs-ui/page';
import { baseOptions } from '@/app/layout.config';
export default function Page() {
return (
<DocsPage
footer={{
text: 'Built with Fumadocs',
}}
/>
);
}
```
### 使用基础配置
您可以创建一个 `baseOptions` 对象,用于所有页面和布局组件。
```tsx title="layout.config.ts"
import type { BasePageConfig } from 'fumadocs-ui/page';
export const baseOptions: BasePageConfig = {
githubUrl: 'https://github.com/fuma-nama/fumadocs',
footer: {
text: 'Built with Fumadocs',
},
};
```
```tsx title="page.tsx"
import { DocsPage } from 'fumadocs-ui/page';
import { baseOptions } from '@/app/layout.config';
export default function Page() {
return <DocsPage {...baseOptions} />;
}
```
### 编辑链接
```tsx
import { DocsPage } from 'fumadocs-ui/page';
export default function Page() {
return (
<DocsPage
gitTimestamp={true}
footer={{
// Edit Link
editLink: {
text: 'Edit this page',
url: 'https://github.com/username/repo/blob/main',
},
}}
/>
);
}
```
### 页面导航
```tsx
import { DocsPage } from 'fumadocs-ui/page';
import { getPagesPath } from 'fumadocs-core';
export default function Page({ params }: { params: { slug?: string[] } }) {
const pagePath = getPagesPath(params);
const prev = getAdjacentPages({ current: pagePath, dir: 'prev' });
const next = getAdjacentPages({ current: pagePath, dir: 'next' });
return (
<DocsPage
footer={{
navigation: {
prev: prev?.url
? {
title: prev.title,
href: prev.url,
}
: undefined,
next: next?.url
? {
title: next.title,
href: next.url,
}
: undefined,
},
}}
/>
);
}
```
#### 自定义获取相邻页面
您可以在 `createAdjacentPages` 方法中应用 `includeInPageNav` 过滤器,该方法由文档生成器创建:
```tsx title="api.ts"
import { createAdjacentPages } from 'fumadocs-core/docs';
import { tree } from '@/app/source';
export const getAdjacentPages = createAdjacentPages(tree, {
includeInPageNav: (page) => !page.data.preview,
});
```

View File

@ -1,54 +0,0 @@
---
title: Root Provider
description: The context provider of Fumadocs UI.
---
The context provider of all the components, including `next-themes` and context
for search dialog. It should be located at the root layout.
## Usage
```jsx
import { RootProvider } from 'fumadocs-ui/provider';
export default function Layout({ children }) {
return (
<html lang="en">
<body>
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}
```
### Search Dialog
Customize or disable the search dialog with `search` option.
```jsx
<RootProvider
search={{
enabled: false,
}}
>
{children}
</RootProvider>
```
Learn more from [Search](/docs/search).
### Theme Provider
Fumadocs supports light/dark modes with [`next-themes`](https://github.com/pacocoursey/next-themes).
Customise or disable it with `theme` option.
```jsx
<RootProvider
theme={{
enabled: false,
}}
>
{children}
</RootProvider>
```

View File

@ -1,53 +0,0 @@
---
title: 根提供者
description: Fumadocs UI 的上下文提供者
---
所有组件的上下文提供者,包括 `next-themes` 和搜索对话框的上下文。它应该位于根布局中。
## 使用方法
```jsx
import { RootProvider } from 'fumadocs-ui/provider';
export default function Layout({ children }) {
return (
<html lang="en">
<body>
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}
```
### 搜索对话框
使用 `search` 选项自定义或禁用搜索对话框。
```jsx
<RootProvider
search={{
enabled: false,
}}
>
{children}
</RootProvider>
```
从[搜索](/docs/search)了解更多信息。
### 主题提供者
Fumadocs 通过 [`next-themes`](https://github.com/pacocoursey/next-themes) 支持明/暗模式。
使用 `theme` 选项自定义或禁用它。
```jsx
<RootProvider
theme={{
enabled: false,
}}
>
{children}
</RootProvider>
```

View File

@ -1,193 +0,0 @@
---
title: Manual Installation
description: Create a new fumadocs project from scratch.
---
> Read the [Quick Start](/docs) guide first for basic concept.
## Getting Started
Create a new Next.js application with `create-next-app`, and install required packages.
```mdx
fumadocs-ui fumadocs-core
```
### Content Source
Fumadocs supports different content sources, you can choose one you prefer.
There is a list of officially supported sources:
- [Setup Fumadocs MDX](/docs/mdx)
- [Setup Content Collections](/docs/headless/content-collections)
Make sure to configure the library correctly following their setup guide before continuing, we will import the source adapter using `@/lib/source.ts` in this guide.
### Root Layout
Wrap the entire application inside [Root Provider](/docs/layouts/root-provider), and add required styles to `body`.
```tsx
import { RootProvider } from 'fumadocs-ui/provider';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body
// you can use Tailwind CSS too
style={{
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
}}
>
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}
```
### Styles
Setup Tailwind CSS v4 on your Next.js app, add the following to `global.css`.
```css title="Tailwind CSS"
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* path of `fumadocs-ui` relative to the CSS file */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
```
> It doesn't come with a default font, you may choose one from `next/font`.
### Layout
Create a `app/layout.config.tsx` file to put the shared options for our layouts.
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/layout.config.tsx",
"codeblock": {
"meta": "title=\"app/layout.config.tsx\""
}
}
```
Create a folder `/app/docs` for our docs, and give it a proper layout.
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/layout.tsx",
"codeblock": {
"meta": "title=\"app/docs/layout.tsx\""
}
}
```
> `pageTree` refers to Page Tree, it should be provided by your content source.
### Page
Create a catch-all route `/app/docs/[[...slug]]` for docs pages.
In the page, wrap your content in the [Page](/docs/layouts/page) component.
It may vary depending on your content source. You should configure static rendering with `generateStaticParams` and metadata with `generateMetadata`.
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
### Search
Use the default document search based on Orama.
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
Learn more about [Document Search](/docs/headless/search).
### Done
You can start the dev server and create MDX files.
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Introduction
I love Anime.
```
## Customise
You can use [Home Layout](/docs/layouts/home-layout) for other pages of the site, it includes a navbar with theme toggle.
## Deploying
It should work out-of-the-box with Vercel & Netlify.
### Docker Deployment
If you want to deploy your Fumadocs app using Docker with **Fumadocs MDX configured**, make sure to add the `source.config.ts` file to the `WORKDIR` in the Dockerfile.
The following snippet is taken from the official [Next.js Dockerfile Example](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile):
```zsh title="Dockerfile"
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* source.config.ts ./
```
This ensures Fumadocs MDX can access your configuration file during builds.

View File

@ -1,191 +0,0 @@
---
title: 手动安装
description: 从零开始创建一个新的 Fumadocs 项目
---
> 请先阅读[快速入门](/docs)指南了解基本概念。
## 入门
使用 `create-next-app` 创建一个新的 Next.js 应用程序,并安装所需的包。
```mdx
fumadocs-ui fumadocs-core
```
### 内容源
Fumadocs 支持不同的内容源,您可以选择您喜欢的一种。
以下是官方支持的源列表:
- [设置 Fumadocs MDX](/docs/mdx)
- [设置 Content Collections](/docs/headless/content-collections)
请确保在继续之前按照其设置指南正确配置库,我们将在本指南中使用 `@/lib/source.ts` 导入源适配器。
### 根布局
将整个应用程序包装在 [Root Provider](/docs/layouts/root-provider) 中,并为 `body` 添加所需的样式。
```tsx
import { RootProvider } from 'fumadocs-ui/provider';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body
// you can use Tailwind CSS too
style={{
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
}}
>
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}
```
### 样式
在您的 Next.js 应用程序上设置 Tailwind CSS v4将以下内容添加到 `global.css`。
```css title="Tailwind CSS"
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* path of `fumadocs-ui` relative to the CSS file */
@source '../node_modules/fumadocs-ui/dist/**/*.js';
```
> 它不附带默认字体,您可以从 `next/font` 中选择一个。
### 布局
创建一个 `app/layout.config.tsx` 文件,放置我们布局的共享选项。
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/layout.config.tsx",
"codeblock": {
"meta": "title=\"app/layout.config.tsx\""
}
}
```
为我们的文档创建一个文件夹 `/app/docs`,并给它一个适当的布局。
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/layout.tsx",
"codeblock": {
"meta": "title=\"app/docs/layout.tsx\""
}
}
```
> `pageTree` 指的是页面树,应该由您的内容源提供。
### 页面
为文档页面创建一个捕获所有路由 `/app/docs/[[...slug]]`。
在页面中,将您的内容包装在 [Page](/docs/layouts/page) 组件中。
这可能因您的内容源而异。您应该使用 `generateStaticParams` 配置静态渲染,并使用 `generateMetadata` 配置元数据。
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/docs/[[...slug]]/page.tsx",
"codeblock": {
"meta": "title=\"app/docs/[[...slug]]/page.tsx\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
### 搜索
使用基于 Orama 的默认文档搜索。
<Tabs items={['Fumadocs MDX', 'Content Collections']}>
<Tab value='Fumadocs MDX'>
```json doc-gen:file
{
"file": "../../examples/next-mdx/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Fumadocs MDX\""
}
}
```
</Tab>
<Tab value='Content Collections'>
```json doc-gen:file
{
"file": "../../examples/content-collections/app/api/search/route.ts",
"codeblock": {
"meta": "title=\"app/api/search/route.ts\" tab=\"Content Collections\""
}
}
```
</Tab>
</Tabs>
了解更多关于[文档搜索](/docs/headless/search)的信息。
### 完成
您可以启动开发服务器并创建 MDX 文件。
```mdx title="content/docs/index.mdx"
---
title: Hello World
---
## Introduction
I love Anime.
```
## 自定义
您可以为网站的其他页面使用 [Home Layout](/docs/layouts/home-layout),它包含一个带有主题切换的导航栏。
## 部署
它应该在 Vercel 和 Netlify 上开箱即用。
### Docker 部署
如果您想使用 Docker 部署您的 Fumadocs 应用程序,并且已**配置了 Fumadocs MDX**,请确保将 `source.config.ts` 文件添加到 Dockerfile 中的 `WORKDIR`。
以下片段取自官方 [Next.js Dockerfile 示例](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile)
```zsh title="Dockerfile"
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* source.config.ts ./
```
这确保 Fumadocs MDX 在构建期间可以访问您的配置文件。

View File

@ -1,380 +0,0 @@
---
title: Markdown
description: How to write documents
---
## Introduction
Fumadocs provides many useful extensions to MDX, a markup language. Here is a brief introduction to the default MDX syntax of Fumadocs UI.
> MDX is not the only supported format of Fumadocs. In fact, you can use any renderers such as `next-mdx-remote` or CMS.
## Markdown
We use GFM (GitHub Flavored Markdown), a superset of Markdown (CommonMark).
See [GFM Specification](https://github.github.com/gfm).
````md
# Heading
## Heading
### Heading
#### Heading
Hello World, **Bold**, _Italic_, ~~Hidden~~
```js
console.log('Hello World');
```
1. First
2. Second
3. Third
- Item 1
- Item 2
> Quote here
![alt](/image.png)
| Table | Description |
| ----- | ----------- |
| Hello | World |
````
### Auto Links
Internal links use the `next/link` component to allow prefetching and avoid hard-reload.
External links will get the default `rel="noreferrer noopener" target="_blank"` attributes for security.
```mdx
[My Link](https://github.github.com/gfm)
This also works: https://github.github.com/gfm.
```
## MDX
MDX is a superset of Markdown, with support of JSX syntax.
It allows you to import components, and use them right in the document, or even export values.
```mdx
import { Component } from './component';
<Component name="Hello" />
```
see [MDX Syntax](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) to learn more.
### Cards
Useful for adding links, it is included by default.
```mdx
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
```
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
#### Icon
You can specify an icon to cards.
```mdx
import { HomeIcon } from 'lucide-react';
<Cards>
<Card icon={<HomeIcon />} href="/" title="Home">
Go back to home
</Card>
</Cards>
```
<Cards>
<Card icon={<HomeIcon />} href="/" title="Go back to home">
The home page of Fumadocs.
</Card>
</Cards>
#### Without href
```mdx
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
```
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
### Callouts
Useful for adding tips/warnings, it is included by default.
```mdx
<Callout>Hello World</Callout>
```
<Callout>Hello World</Callout>
#### Title
Specify a callout title.
```mdx
<Callout title="Title">Hello World</Callout>
```
<Callout title="Title">Hello World</Callout>
#### Types
You can specify the type of callout.
- `info` (default)
- `warn`
- `error`
```mdx
<Callout title="Title" type="error">
Hello World
</Callout>
```
<Callout title="Title" type="error">
Hello World
</Callout>
### Customise Components
See [all MDX components and available options](/docs/mdx).
## Headings
An anchor is automatically applied to each heading, it sanitizes invalid characters like spaces. (e.g. `Hello World` to `hello-world`)
```md
# Hello `World`
```
### TOC Settings
The table of contents (TOC) will be generated based on headings, you can also customise the effects of headings:
```md
# Heading [!toc]
This heading will be hidden from TOC.
# Another Heading [toc]
This heading will **only** be visible in TOC, you can use it to add additional TOC items.
Like headings rendered in a React component:
<MyComp />
```
### Custom Anchor
You can add `[#slug]` to customise heading anchors.
```md
# heading [#my-heading-id]
```
You can also chain it with TOC settings like:
```md
# heading [toc] [#my-heading-id]
```
To link people to a specific heading, add the heading id to hash fragment: `/page#my-heading-id`.
## Frontmatter
We support YAML frontmatter. It is a way to specify common information of the document (e.g. title).
Place it at the top of document.
```mdx
---
title: Hello World
---
## Title
```
See [Page Conventions](/docs/page-conventions#frontmatter) for a list of properties available for frontmatter.
## Codeblock
Syntax Highlighting is supported by default using [Rehype Code](/docs/headless/mdx/rehype-code).
````mdx
```js
console.log('Hello World');
```
````
You can add a title to the codeblock.
````mdx
```js title="My Title"
console.log('Hello World');
```
````
### Highlight Lines
You can highlight specific lines by adding `[!code highlight]`.
````md
```tsx
<div>Hello World</div> // [\!code highlight]
<div>Hello World</div>
<div>Goodbye</div>
<div>Hello World</div>
```
````
### Highlight Words
You can highlight a specific word by adding `[!code word:<match>]`.
````md
```js
// [\!code word:config]
const config = {
reactStrictMode: true,
};
```
````
### Diffs
````mdx
```ts
console.log('hewwo'); // [\!code --]
console.log('hello'); // [\!code ++]
```
````
```ts
console.log('hewwo'); // [!code --]
console.log('hello'); // [!code ++]
```
### Tab Groups
You can use code blocks with the `<Tab />` component.
````mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
````
> Note that you can add MDX components instead of importing them in MDX files.
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
### Using Typescript Twoslash
Write Typescript codeblocks with hover type information and detected types errors.
Not enabled by default. See [Twoslash](/docs/twoslash).
## Images
All built-in content sources handle images properly.
Images are automatically optimized for `next/image`.
```mdx
![Image](/image.png)
```
![Image](/images/docs/notebook.png)
## Optional
Some optional plugins you can enable.
### Math Equations
Write math equations with TeX.
````md
```mdx
f(x) = x * e^{2 pi i \xi x}
```
````
```mdx
f(x) = x * e^{2 pi i \xi x}
```
To enable, see [Math Integration](/docs/math).
### Package Install
Generate code blocks for installing packages via package managers (JS/Node.js).
````md
```mdx
npm i next -D
```
````
```mdx
npm i next -D
```
To enable, see [Remark Install](/docs/headless/mdx/install).
### More
You can see [a list of plugins](/docs/headless/mdx) supported by Fumadocs.

View File

@ -1,342 +0,0 @@
---
title: Markdown
description: 如何撰写文档
---
## 介绍
Fumadocs 为 MDX一种标记语言提供了许多有用的扩展。以下是 Fumadocs UI 默认 MDX 语法的简要介绍。
> MDX 不是 Fumadocs 唯一支持的格式。实际上,您可以使用任何渲染器,如 `next-mdx-remote` 或 CMS。
## Markdown
我们使用 GFMGitHub 风格的 Markdown这是 MarkdownCommonMark的超集。
参见 [GFM 规范](https://github.github.com/gfm)。
````md
# Heading
## Heading
### Heading
#### Heading
Hello World, **Bold**, _Italic_, ~~Hidden~~
```js
console.log('Hello World');
```
1. First
2. Second
3. Third
- Item 1
- Item 2
> Quote here
![alt](/image.png)
| Table | Description |
| ----- | ----------- |
| Hello | World |
````
### 自动链接
内部链接使用 `next/link` 组件,允许预取并避免硬重载。
外部链接将获得默认的 `rel="noreferrer noopener" target="_blank"` 属性以增强安全性。
```mdx
[My Link](https://github.github.com/gfm)
This also works: https://github.github.com/gfm.
```
## MDX
MDX 是 Markdown 的超集,支持 JSX 语法。
它允许您导入组件,并直接在文档中使用它们,甚至导出值。
```mdx
import { Component } from './component';
<Component name="Hello" />
```
参见 [MDX 语法](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) 了解更多信息。
### 卡片
对于添加链接很有用,默认包含。
```mdx
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
```
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
>
Learn more about caching in Next.js
</Card>
</Cards>
#### 图标
您可以为卡片指定图标。
```mdx
import { HomeIcon } from 'lucide-react';
<Cards>
<Card icon={<HomeIcon />} href="/" title="Home">
Go back to home
</Card>
</Cards>
```
<Cards>
<Card icon={<HomeIcon />} href="/" title="Go back to home">
The home page of Fumadocs.
</Card>
</Cards>
#### 无 href
```mdx
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
```
<Cards>
<Card title="Fetching, Caching, and Revalidating">
Learn more about `fetch` in Next.js.
</Card>
</Cards>
### 提示框
对于添加提示/警告很有用,默认包含。
```mdx
<Callout>Hello World</Callout>
```
<Callout>Hello World</Callout>
#### 标题
指定提示框标题。
```mdx
<Callout title="Title">Hello World</Callout>
```
<Callout title="Title">Hello World</Callout>
#### 类型
您可以指定提示框的类型。
- `info`(默认)
- `warn`
- `error`
```mdx
<Callout title="Title" type="error">
Hello World
</Callout>
```
<Callout title="Title" type="error">
Hello World
</Callout>
### 自定义组件
参见[所有 MDX 组件和可用选项](/docs/mdx)。
## 标题
每个标题会自动应用锚点,它会清理空格等无效字符。(例如,`Hello World` 变为 `hello-world`
```md
# Hello `World`
```
### 目录设置
目录 (TOC) 将基于标题生成,您还可以自定义标题的效果:
```md
# Heading [!toc]
This heading will be hidden from TOC.
# Another Heading [toc]
This heading will **only** be visible in TOC, you can use it to add additional TOC items.
Like headings rendered in a React component:
<MyComp />
```
### 自定义锚点
您可以添加 `[#slug]` 来自定义标题锚点。
```md
# heading [#my-heading-id]
```
您也可以将其与目录设置链接起来,例如:
```md
# heading [toc] [#my-heading-id]
```
要将人们链接到特定标题,请将标题 ID 添加到哈希片段:`/page#my-heading-id`。
## 前言
我们支持 YAML 前言。这是一种指定文档常见信息(例如标题)的方式。
将其放在文档顶部。
```mdx
---
title: Hello World
---
## Title
```
有关前言可用属性的列表,请参见[页面约定](/docs/page-conventions#frontmatter)。
## 代码块
默认使用 [Rehype Code](/docs/headless/mdx/rehype-code) 支持语法高亮。
````mdx
```js
console.log('Hello World');
```
````
您可以为代码块添加标题。
````mdx
```js title="My Title"
console.log('Hello World');
```
````
### 高亮行
````md
```tsx
<div>Hello World</div> // [\!code highlight]
<div>Hello World</div>
<div>Goodbye</div>
<div>Hello World</div>
```
````
### 高亮单词
您可以通过添加 `[!code word:<match>]` 来高亮特定单词。
````md
```js
// [\!code word:config]
const config = {
reactStrictMode: true,
};
```
````
### 差异
````mdx
```ts
console.log('hewwo'); // [\!code --]
console.log('hello'); // [\!code ++]
```
````
```ts
console.log('hewwo'); // [!code --]
console.log('hello'); // [!code ++]
```
### 标签组
您可以使用 `<Tab />` 组件与代码块一起使用。
````mdx
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
````
> 注意,您可以在 MDX 文件中添加 MDX 组件,而不必导入它们。
<Tabs items={['Tab 1', 'Tab 2']}>
<Tab value='Tab 1'>
```ts
console.log('A');
```
</Tab>
<Tab value='Tab 2'>
```ts
console.log('B');
```
</Tab>
</Tabs>
### 使用 Typescript Twoslash
编写带有悬停类型信息和检测到类型错误的 Typescript 代码块。
默认情况下未启用。参见 [Twoslash](/docs/twoslash)。
## 图片
所有内置内容源都能正确处理图片。
图片会自动为 `next/image` 优化。
```mdx
![Image](/image.png)
```
![Image](/images/docs/notebook.png)
## 可选功能
一些您可以启用的可选插件。

View File

@ -1,25 +0,0 @@
---
title: Callout
description: Add callout to your docs
preview: callout
---
## Usage
Add it to your MDX components.
```tsx
import { Callout } from 'fumadocs-ui/components/callout';
<MDX
components={{
Callout,
}}
/>;
```
See [Markdown](/docs/markdown#callouts) for usages.
### Reference
{/* <AutoTypeTable path="./content/docs/props.ts" name="CalloutProps" /> */}

Some files were not shown because too many files have changed in this diff Show More