mapcn-docs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

mapcn-docs

mapcn-docs

Build beautiful, interactive documentation sites with live component previews and copy-paste code examples.
构建美观、交互式的文档站点,支持组件实时预览和可复制粘贴的代码示例。

Overview

概述

This skill implements a documentation system featuring:
  • Live previews with tabbed preview/code views
  • Syntax-highlighted code using Shiki with light/dark theme support
  • Copy-to-clipboard functionality for all code examples
  • Responsive sidebar navigation with mobile support
  • Scroll-tracking TOC (Table of Contents)
  • Accessible design using shadcn/ui components
本方案实现的文档系统具备以下特性:
  • 实时预览:支持预览/代码标签页视图
  • 语法高亮代码:使用Shiki实现,支持亮色/暗色主题
  • 一键复制:所有代码示例均支持复制到剪贴板功能
  • 响应式侧边栏:支持移动端的导航侧边栏
  • 滚动跟踪目录(TOC)
  • 无障碍设计:基于shadcn/ui组件实现

When to Use

适用场景

Use this skill when:
  • Building a docs site for a component library or design system
  • Creating API reference pages with interactive examples
  • Need tabbed preview/code views like shadcn/ui docs
  • Want copy-paste ready code examples with syntax highlighting
Do NOT use when:
  • Simple static documentation (use MDX or plain markdown)
  • No need for live component previews
  • Not using Next.js App Router or React
Prerequisites:
  • Next.js 13+ with App Router (
    app/
    directory)
  • Tailwind CSS configured
  • shadcn/ui initialized (
    npx shadcn@latest init
    )
推荐使用本方案的场景:
  • 为组件库或设计系统构建文档站点
  • 创建带有交互式示例的API参考页面
  • 需要类似shadcn/ui文档的标签页式预览/代码视图
  • 希望提供可直接复制粘贴的语法高亮代码示例
不推荐使用的场景:
  • 简单的静态文档(建议使用MDX或纯Markdown)
  • 不需要组件实时预览的场景
  • 不使用Next.js App Router或React的项目
前置要求:
  • 13+版本的Next.js,且启用App Router(
    app/
    目录)
  • 已配置Tailwind CSS
  • 已初始化shadcn/ui(执行
    npx shadcn@latest init

Quick Start

快速开始

1. Directory Structure

1. 目录结构

src/app/docs/
├── layout.tsx                    # Root docs layout
├── page.tsx                      # Introduction page
├── _components/
│   ├── docs.tsx                  # Core UI components
│   ├── docs-sidebar.tsx          # Navigation sidebar
│   ├── docs-toc.tsx              # Table of contents
│   ├── component-preview.tsx     # Server-side preview wrapper
│   ├── component-preview-client.tsx  # Client-side preview tabs
│   ├── code-block.tsx            # Code display
│   ├── copy-button.tsx           # Clipboard utility
│   └── examples/                 # Live example components
└── [route]/page.tsx              # Documentation pages
src/app/docs/
├── layout.tsx                    # 文档根布局
├── page.tsx                      # 介绍页
├── _components/
│   ├── docs.tsx                  # 核心UI组件
│   ├── docs-sidebar.tsx          # 导航侧边栏
│   ├── docs-toc.tsx              # 目录组件
│   ├── component-preview.tsx     # 服务端预览包装器
│   ├── component-preview-client.tsx  # 客户端预览标签页
│   ├── code-block.tsx            # 代码展示组件
│   ├── copy-button.tsx           # 剪贴板工具组件
│   └── examples/                 # 实时示例组件目录
└── [route]/page.tsx              # 文档页面

2. Install Dependencies

2. 安装依赖

bash
npm install shiki
npx shadcn@latest add sidebar table card tabs
bash
npm install shiki
npx shadcn@latest add sidebar table card tabs

3. Create Core Components

3. 创建核心组件

See references/COMPONENTS.md for complete component implementations.
完整的组件实现请参考references/COMPONENTS.md

Page Structure Pattern

页面结构模式

Every documentation page follows this structure:
tsx
import { Metadata } from "next";
import { DocsLayout, DocsSection, DocsPropTable } from "../_components/docs";
import { ComponentPreview } from "../_components/component-preview";
import { getExampleSource } from "@/lib/get-example-source";
import { MyExample } from "../_components/examples/my-example";

export const metadata: Metadata = { title: "Page Title" };

export default function PageName() {
  const exampleSource = getExampleSource("my-example.tsx");

  return (
    <DocsLayout
      title="Page Title"
      description="Brief description of this page"
      prev={{ title: "Previous", href: "/docs/previous" }}
      next={{ title: "Next", href: "/docs/next" }}
      toc={[
        { title: "Overview", slug: "overview" },
        { title: "Usage", slug: "usage" },
        { title: "API Reference", slug: "api-reference" },
      ]}
    >
      <DocsSection>
        <p>Introduction paragraph.</p>
      </DocsSection>

      <DocsSection title="Overview">
        <p>Section content here.</p>
      </DocsSection>

      <DocsSection title="Usage">
        <ComponentPreview code={exampleSource}>
          <MyExample />
        </ComponentPreview>
      </DocsSection>

      <DocsSection title="API Reference">
        <DocsPropTable
          props={[
            {
              name: "propName",
              type: "string",
              default: "undefined",
              description: "Description of the prop",
            },
          ]}
        />
      </DocsSection>
    </DocsLayout>
  );
}
所有文档页面遵循以下结构:
tsx
import { Metadata } from "next";
import { DocsLayout, DocsSection, DocsPropTable } from "../_components/docs";
import { ComponentPreview } from "../_components/component-preview";
import { getExampleSource } from "@/lib/get-example-source";
import { MyExample } from "../_components/examples/my-example";

export const metadata: Metadata = { title: "页面标题" };

export default function PageName() {
  const exampleSource = getExampleSource("my-example.tsx");

  return (
    <DocsLayout
      title="页面标题"
      description="本页面的简短描述"
      prev={{ title: "上一页", href: "/docs/previous" }}
      next={{ title: "下一页", href: "/docs/next" }}
      toc={[
        { title: "概述", slug: "overview" },
        { title: "使用方法", slug: "usage" },
        { title: "API参考", slug: "api-reference" },
      ]}
    >
      <DocsSection>
        <p>介绍段落。</p>
      </DocsSection>

      <DocsSection title="概述">
        <p>本节内容。</p>
      </DocsSection>

      <DocsSection title="使用方法">
        <ComponentPreview code={exampleSource}>
          <MyExample />
        </ComponentPreview>
      </DocsSection>

      <DocsSection title="API参考">
        <DocsPropTable
          props={[
            {
              name: "propName",
              type: "string",
              default: "undefined",
              description: "该属性的描述",
            },
          ]}
        />
      </DocsSection>
    </DocsLayout>
  );
}

Example Component Pattern

示例组件模式

Create example components in
_components/examples/
:
tsx
// Client-side example (with state)
"use client";

import { useState } from "react";
import { MyComponent } from "@/registry/my-component";

export function InteractiveExample() {
  const [value, setValue] = useState("initial");

  return (
    <div className="h-[400px] w-full">
      <MyComponent value={value} onChange={setValue} />
    </div>
  );
}
tsx
// Server-side example (no state)
import { MyComponent } from "@/registry/my-component";

export function SimpleExample() {
  return (
    <div className="h-[400px] w-full">
      <MyComponent />
    </div>
  );
}
Key pattern: Always wrap examples in a fixed-height container (
h-[400px]
) for consistent preview rendering.
_components/examples/
目录下创建示例组件:
tsx
// 客户端示例(带状态)
"use client";

import { useState } from "react";
import { MyComponent } from "@/registry/my-component";

export function InteractiveExample() {
  const [value, setValue] = useState("initial");

  return (
    <div className="h-[400px] w-full">
      <MyComponent value={value} onChange={setValue} />
    </div>
  );
}
tsx
// 服务端示例(无状态)
import { MyComponent } from "@/registry/my-component";

export function SimpleExample() {
  return (
    <div className="h-[400px] w-full">
      <MyComponent />
    </div>
  );
}
关键模式:始终使用固定高度容器(
h-[400px]
)包裹示例,以保证预览渲染的一致性。

Navigation Configuration

导航配置

Define navigation in
docs-navigation.ts
:
tsx
import { BookOpen, Code, Settings } from "lucide-react";

export const docsNavigation = {
  groups: [
    {
      title: "Getting Started",
      items: [
        { title: "Introduction", href: "/docs", icon: BookOpen },
        { title: "Installation", href: "/docs/installation", icon: Code },
      ],
    },
    {
      title: "Components",
      items: [
        { title: "Button", href: "/docs/button", icon: Settings },
        // Add more components...
      ],
    },
  ],
};
docs-navigation.ts
中定义导航:
tsx
import { BookOpen, Code, Settings } from "lucide-react";

export const docsNavigation = {
  groups: [
    {
      title: "快速开始",
      items: [
        { title: "介绍", href: "/docs", icon: BookOpen },
        { title: "安装", href: "/docs/installation", icon: Code },
      ],
    },
    {
      title: "组件",
      items: [
        { title: "Button", href: "/docs/button", icon: Settings },
        // 添加更多组件...
      ],
    },
  ],
};

Code Highlighting Setup

代码高亮设置

Create
lib/highlight.ts
:
tsx
import { codeToHtml } from "shiki";

export async function highlightCode(code: string, lang = "tsx") {
  return codeToHtml(code, {
    lang,
    themes: {
      light: "github-light",
      dark: "github-dark",
    },
  });
}
Create
lib/get-example-source.ts
:
tsx
import fs from "fs";
import path from "path";

export function getExampleSource(filename: string): string {
  const filePath = path.join(
    process.cwd(),
    "src/app/docs/_components/examples",
    filename
  );

  let content = fs.readFileSync(filePath, "utf-8");

  // Transform import paths for user copy-paste
  content = content.replace(
    /@\/registry\//g,
    "@/components/ui/"
  );

  return content;
}
创建
lib/highlight.ts
tsx
import { codeToHtml } from "shiki";

export async function highlightCode(code: string, lang = "tsx") {
  return codeToHtml(code, {
    lang,
    themes: {
      light: "github-light",
      dark: "github-dark",
    },
  });
}
创建
lib/get-example-source.ts
tsx
import fs from "fs";
import path from "path";

export function getExampleSource(filename: string): string {
  const filePath = path.join(
    process.cwd(),
    "src/app/docs/_components/examples",
    filename
  );

  let content = fs.readFileSync(filePath, "utf-8");

  // 转换导入路径,方便用户复制粘贴
  content = content.replace(
    /@\/registry\//g,
    "@/components/ui/"
  );

  return content;
}

UI Components

UI组件

The docs system uses these core components:
ComponentPurpose
DocsLayout
Page wrapper with prev/next nav and TOC
DocsSection
Content section with auto-generated slug IDs
DocsHeader
Page title and description
DocsNote
Highlighted callout boxes
DocsCode
Inline code styling
DocsLink
Styled links with external support
DocsPropTable
API reference tables
ComponentPreview
Live preview with code tab
CodeBlock
Standalone code display
本文档系统使用以下核心组件:
组件用途
DocsLayout
页面包装器,包含上一页/下一页导航和目录
DocsSection
内容区块,自动生成锚点ID
DocsHeader
页面标题和描述
DocsNote
高亮提示框
DocsCode
行内代码样式
DocsLink
带外部链接支持的样式化链接
DocsPropTable
API参考表格
ComponentPreview
带代码标签页的实时预览组件
CodeBlock
独立代码展示组件

Preview System Architecture

预览系统架构

┌─────────────────────────────────────────────┐
│ ComponentPreview (Server Component)          │
│ - Receives code string                       │
│ - Calls highlightCode() with Shiki           │
│ - Passes highlighted HTML to client          │
└──────────────────┬──────────────────────────┘
┌─────────────────────────────────────────────┐
│ ComponentPreviewClient (Client Component)    │
│ - Renders tabs: Preview | Code               │
│ - Preview tab: renders children              │
│ - Code tab: shows highlighted code           │
│ - Copy button for code                       │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ ComponentPreview (Server Component)          │
│ - 接收代码字符串                             │
│ - 调用Shiki的highlightCode()方法             │
│ - 将高亮后的HTML传递给客户端                 │
└──────────────────┬──────────────────────────┘
┌─────────────────────────────────────────────┐
│ ComponentPreviewClient (Client Component)    │
│ - 渲染标签页:预览 | 代码                   │
│ - 预览标签页:渲染子组件                    │
│ - 代码标签页:展示高亮后的代码              │
│ - 代码复制按钮                              │
└─────────────────────────────────────────────┘

Adding a New Documentation Page

添加新文档页面

  1. Create route directory:
    src/app/docs/[page-name]/page.tsx
  2. Create example component if needed:
    _components/examples/[name]-example.tsx
  3. Add to navigation in
    docs-navigation.ts
  4. Update prev/next links on adjacent pages
  1. 创建路由目录:
    src/app/docs/[page-name]/page.tsx
  2. 若需要,创建示例组件:
    _components/examples/[name]-example.tsx
  3. docs-navigation.ts
    中添加导航项
  4. 更新相邻页面的上一页/下一页链接

Best Practices

最佳实践

  1. Keep examples focused - One concept per example
  2. Use fixed heights -
    h-[400px]
    for consistent previews
  3. Transform imports - Change internal paths for user copy-paste
  4. Include API tables - Document all props with types and defaults
  5. Add TOC items - List all major sections for scroll tracking
  6. Mobile-first - Test sidebar collapse and responsive layouts
  1. 示例聚焦:每个示例只展示一个核心概念
  2. 使用固定高度:用
    h-[400px]
    保证预览一致性
  3. 转换导入路径:修改内部路径以便用户直接复制使用
  4. 包含API表格:记录所有属性的类型和默认值
  5. 添加目录项:列出所有主要章节以支持滚动跟踪
  6. 移动端优先:测试侧边栏折叠和响应式布局

Common Mistakes

常见错误

MistakeFix
Calling
highlightCode
in Client Component
Move to Server Component - Shiki requires server-side execution
Missing fixed height on examplesAdd
h-[400px]
wrapper for consistent preview rendering
Using internal import paths in examplesUse
getExampleSource()
to transform
@/registry/
to
@/components/ui/
Forgetting to update navigationAlways add new pages to
docs-navigation.ts
Not updating prev/next linksCheck adjacent pages when adding/removing docs
错误修复方案
在客户端组件中调用
highlightCode
移至服务端组件 - Shiki需要在服务端执行
示例缺少固定高度添加
h-[400px]
包装容器以保证预览渲染一致
示例中使用内部导入路径使用
getExampleSource()
@/registry/
转换为
@/components/ui/
忘记更新导航配置务必在
docs-navigation.ts
中添加新页面
未更新上一页/下一页链接添加或删除文档时检查相邻页面的链接

Troubleshooting

故障排除

ProblemSolution
shadcn/ui not installedRun
npx shadcn@latest init
first, then add components
Shiki SSR errorsEnsure
highlightCode
is only called in Server Components
Dark mode not workingAdd
defaultColor: false
to Shiki config and use CSS
[data-theme]
selectors
Preview height inconsistentAlways use fixed height (
h-[400px]
) on example wrappers
Copy button not workingEnsure HTTPS or localhost (clipboard API requirement)
问题解决方案
shadcn/ui未安装先执行
npx shadcn@latest init
,再添加组件
Shiki SSR错误确保
highlightCode
仅在服务端组件中调用
暗色主题不生效在Shiki配置中添加
defaultColor: false
,并使用CSS的
[data-theme]
选择器
预览高度不一致始终为示例添加固定高度(
h-[400px]
)包装器
复制按钮无法工作确保使用HTTPS或localhost(剪贴板API的要求)

Prerequisites Check

前置要求检查

Before using this skill, verify:
  1. Next.js 13+ with App Router (
    app/
    directory)
  2. Tailwind CSS configured
  3. cn()
    utility from shadcn/ui (
    lib/utils.ts
    )
If missing shadcn/ui:
bash
npx shadcn@latest init
使用本方案前,请确认:
  1. 已安装13+版本的Next.js并启用App Router(
    app/
    目录)
  2. 已配置Tailwind CSS
  3. 已具备shadcn/ui的
    cn()
    工具函数(
    lib/utils.ts
若未安装shadcn/ui:
bash
npx shadcn@latest init

File Reference

文件参考

  • references/COMPONENTS.md - Complete component implementations
  • references/LAYOUT.md - Layout and sidebar setup
  • scripts/create-doc-page.sh - Generate new doc pages
  • references/COMPONENTS.md - 完整的组件实现
  • references/LAYOUT.md - 布局和侧边栏设置
  • scripts/create-doc-page.sh - 生成新文档页面的脚本