create-react-docs-ui 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README-zh.md +33 -85
  2. package/README.md +33 -85
  3. package/package.json +44 -42
  4. package/template/package.json +3 -3
  5. package/template/public/config/site.en.yaml +177 -155
  6. package/template/public/config/site.yaml +28 -13
  7. package/template/public/docs/en/{guide → docs/guide}/configuration.md +195 -149
  8. package/template/public/docs/en/{guide → docs/guide}/installation.md +2 -2
  9. package/template/public/docs/en/docs/guide/quick-start.md +96 -0
  10. package/template/public/docs/en/docs/guide.md +10 -0
  11. package/template/public/docs/en/docs/test/katex-test.md +258 -0
  12. package/template/public/docs/en/docs/test/mdx-test.mdx +136 -0
  13. package/template/public/docs/en/docs/test/test.md +212 -0
  14. package/template/public/docs/en/docs/test.md +9 -0
  15. package/template/public/docs/en/docs.md +16 -0
  16. package/template/public/docs/zh-cn/{guide → docs/guide}/configuration.md +196 -150
  17. package/template/public/docs/zh-cn/{guide → docs/guide}/installation.md +2 -2
  18. package/template/public/docs/zh-cn/{guide → docs/guide}/quick-start.md +13 -25
  19. package/template/public/docs/zh-cn/docs/guide.md +10 -0
  20. package/template/public/docs/zh-cn/docs/test/katex-test.md +260 -0
  21. package/template/public/docs/zh-cn/docs/test/mdx-test.mdx +139 -0
  22. package/template/public/docs/zh-cn/docs/test/test.md +215 -0
  23. package/template/public/docs/zh-cn/docs/test.md +9 -0
  24. package/template/public/docs/zh-cn/docs.md +16 -0
  25. package/template/public/images/yrzx.png +0 -0
  26. package/template/src/components/Alert.tsx +30 -0
  27. package/template/src/components/BadgeList.tsx +38 -0
  28. package/template/src/components/Callout.tsx +20 -0
  29. package/template/src/components/Feature.tsx +15 -0
  30. package/template/src/components/MyTip.tsx +19 -0
  31. package/template/src/components/StepList.tsx +62 -0
  32. package/template/tsconfig.app.json +24 -26
  33. package/template/vite-plugin-mdx-components.ts +169 -0
  34. package/template/vite.config.ts +13 -4
  35. package/template/public/docs/en/guide/quick-start.md +0 -108
  36. package/template/public/docs/en/guide.md +0 -10
  37. package/template/public/docs/zh-cn/guide.md +0 -10
  38. /package/template/public/docs/en/{guide → docs/guide}/introduction.md +0 -0
  39. /package/template/public/docs/zh-cn/{guide → docs/guide}/introduction.md +0 -0
@@ -0,0 +1,20 @@
1
+ import * as React from 'react'
2
+
3
+ interface CalloutProps {
4
+ variant?: 'default' | 'primary' | 'secondary'
5
+ children: React.ReactNode
6
+ }
7
+
8
+ export function Callout({ variant = 'default', children }: CalloutProps) {
9
+ const styles = {
10
+ default: 'border-l-4 border-gray-500 bg-gray-50 dark:bg-gray-800',
11
+ primary: 'border-l-4 border-blue-500 bg-blue-50 dark:bg-blue-950',
12
+ secondary: 'border-l-4 border-purple-500 bg-purple-50 dark:bg-purple-950'
13
+ }
14
+
15
+ return (
16
+ <div className={`my-4 rounded-r-lg p-4 ${styles[variant]}`}>
17
+ {children}
18
+ </div>
19
+ )
20
+ }
@@ -0,0 +1,15 @@
1
+ interface FeatureProps {
2
+ icon?: string
3
+ title: string
4
+ description: string
5
+ }
6
+
7
+ export function Feature({ icon = '🚀', title, description }: FeatureProps) {
8
+ return (
9
+ <div className="my-4 rounded-lg border border-gray-200 p-6 shadow-sm hover:shadow-md transition-shadow dark:border-gray-700">
10
+ <div className="mb-3 text-4xl">{icon}</div>
11
+ <h3 className="mb-2 text-lg font-semibold">{title}</h3>
12
+ <p className="text-gray-600 dark:text-gray-300">{description}</p>
13
+ </div>
14
+ )
15
+ }
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+
3
+ interface MyTipProps {
4
+ title?: string
5
+ children: React.ReactNode
6
+ }
7
+
8
+ export function MyTip({ title, children }: MyTipProps) {
9
+ return (
10
+ <div className="my-4 rounded-lg border border-green-200 bg-green-50 p-4 dark:border-green-800 dark:bg-green-950">
11
+ {title && (
12
+ <div className="mb-2 font-semibold text-green-900 dark:text-green-100">
13
+ 💡 {title}
14
+ </div>
15
+ )}
16
+ <div className="text-green-800 dark:text-green-200">{children}</div>
17
+ </div>
18
+ )
19
+ }
@@ -0,0 +1,62 @@
1
+ import * as React from 'react'
2
+
3
+ interface StepProps {
4
+ step: number
5
+ title: string
6
+ children: React.ReactNode
7
+ }
8
+
9
+ interface StepListProps {
10
+ children: React.ReactNode
11
+ }
12
+
13
+ function Step({ step, title, 'data-title': dataTitle, children }: StepProps & { 'data-title'?: string }) {
14
+ // 优先使用 title,如果没有则使用 data-title
15
+ const displayTitle = title || dataTitle
16
+
17
+ return (
18
+ <div className="relative pb-8 last:pb-0">
19
+ <div className="absolute left-0 top-0 flex h-8 w-8 items-center justify-center rounded-full bg-blue-500 text-sm font-bold text-white">
20
+ {step}
21
+ </div>
22
+ <div className="ml-12">
23
+ <h4 className="mb-2 font-semibold">{displayTitle}</h4>
24
+ <div className="text-gray-600 dark:text-gray-300">{children}</div>
25
+ </div>
26
+ </div>
27
+ )
28
+ }
29
+
30
+ export function StepList({ children }: StepListProps) {
31
+ const steps = React.Children.toArray(children).filter(
32
+ (child): child is React.ReactElement<StepProps> => {
33
+ if (!React.isValidElement(child)) return false
34
+
35
+ const childProps = child.props as any
36
+
37
+ // 检查 props 中是否有 data-title 属性(通过我们的转换,title 变成了 data-title)
38
+ if (childProps && Object.prototype.hasOwnProperty.call(childProps, 'data-title')) return true
39
+
40
+ // 检查 props 中是否有 node.tagName === 'steplist-step'
41
+ if (childProps?.node?.tagName === 'steplist-step') return true
42
+
43
+ // 检查 props 中是否有 title 属性(直接使用的情况)
44
+ if (childProps && Object.prototype.hasOwnProperty.call(childProps, 'title')) return true
45
+
46
+ return false
47
+ }
48
+ )
49
+
50
+ return (
51
+ <div className="my-4 rounded-lg border border-gray-200 p-6 dark:border-gray-700">
52
+ {steps.map((step, index) =>
53
+ React.cloneElement(step, {
54
+ key: index,
55
+ step: index + 1
56
+ })
57
+ )}
58
+ </div>
59
+ )
60
+ }
61
+
62
+ StepList.Step = Step
@@ -1,26 +1,24 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "useDefineForClassFields": true,
5
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
6
- "module": "ESNext",
7
- "skipLibCheck": true,
8
- "moduleResolution": "bundler",
9
- "allowImportingTsExtensions": true,
10
- "verbatimModuleSyntax": true,
11
- "moduleDetection": "force",
12
- "noEmit": true,
13
- "jsx": "react-jsx",
14
- "strict": true,
15
- "noUnusedLocals": true,
16
- "noUnusedParameters": true,
17
- "noFallthroughCasesInSwitch": true,
18
- "baseUrl": ".",
19
- "paths": {
20
- "@/*": ["./src/*"]
21
- }
22
- },
23
- "include": ["src"]
24
- }
25
-
26
-
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "bundler",
9
+ "allowImportingTsExtensions": true,
10
+ "verbatimModuleSyntax": true,
11
+ "moduleDetection": "force",
12
+ "noEmit": true,
13
+ "jsx": "react-jsx",
14
+ "strict": true,
15
+ "noUnusedLocals": true,
16
+ "noUnusedParameters": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "baseUrl": ".",
19
+ "paths": {
20
+ "@/*": ["./src/*"],
21
+ },
22
+ },
23
+ "include": ["src"],
24
+ }
@@ -0,0 +1,169 @@
1
+ import type { Plugin } from 'vite'
2
+ import fs from 'fs'
3
+ import path from 'path'
4
+
5
+ /**
6
+ * 从组件文件内容中提取复合组件的子组件
7
+ * 例如:从 StepList 组件中提取 StepList.Step
8
+ */
9
+ function extractSubComponents(fileContent: string, componentName: string): string[] {
10
+ const subComponents: string[] = []
11
+
12
+ // 匹配模式:ComponentName.SubComponent = SubComponent
13
+ const pattern1 = new RegExp(`${componentName}\\.(\\w+)\\s*=\\s*(\\w+)`, 'g')
14
+ let match
15
+ while ((match = pattern1.exec(fileContent)) !== null) {
16
+ const subComponentName = match[1]
17
+ if (!subComponents.includes(subComponentName)) {
18
+ subComponents.push(subComponentName)
19
+ }
20
+ }
21
+
22
+ // 匹配模式:ComponentName.SubComponent = function SubComponent
23
+ const pattern2 = new RegExp(`${componentName}\\.(\\w+)\\s*=\\s*(?:function|const)\\s+(\\w+)`, 'g')
24
+ while ((match = pattern2.exec(fileContent)) !== null) {
25
+ const subComponentName = match[1]
26
+ if (!subComponents.includes(subComponentName)) {
27
+ subComponents.push(subComponentName)
28
+ }
29
+ }
30
+
31
+ return subComponents
32
+ }
33
+
34
+ /**
35
+ * 创建一个 Vite 插件,用于自动扫描和注册 MDX 组件
36
+ * 这个插件会在构建时扫描 src/components 目录,并生成组件索引文件
37
+ */
38
+ export function mdxComponentsPlugin(options: {
39
+ componentsPath?: string
40
+ outputPath?: string
41
+ }): Plugin {
42
+ const {
43
+ componentsPath = './src/components',
44
+ outputPath = './src/generated/mdx-components.ts'
45
+ } = options
46
+
47
+ return {
48
+ name: 'mdx-components-scanner',
49
+ enforce: 'post',
50
+ buildStart() {
51
+ // 构建开始时,扫描组件并生成索引文件
52
+ try {
53
+ const componentsDir = path.resolve(process.cwd(), componentsPath)
54
+
55
+ if (!fs.existsSync(componentsDir)) {
56
+ console.log(`[MDX] 组件目录不存在: ${componentsDir}`)
57
+ return
58
+ }
59
+
60
+ // 递归扫描所有 .tsx 和 .ts 文件
61
+ const scanDirectory = (dir: string, baseDir: string = dir): string[] => {
62
+ const files: string[] = []
63
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
64
+
65
+ for (const entry of entries) {
66
+ const fullPath = path.join(dir, entry.name)
67
+ const relativePath = path.relative(baseDir, fullPath).replace(/\\/g, '/')
68
+
69
+ if (entry.isDirectory()) {
70
+ files.push(...scanDirectory(fullPath, baseDir))
71
+ } else if (entry.isFile() && /\.(tsx?|jsx?)$/.test(entry.name)) {
72
+ const componentName = entry.name.replace(/\.(tsx?|jsx?)$/, '')
73
+ if (componentName !== 'index' && !componentName.startsWith('.')) {
74
+ files.push(relativePath)
75
+ }
76
+ }
77
+ }
78
+
79
+ return files
80
+ }
81
+
82
+ const componentFiles = scanDirectory(componentsDir)
83
+
84
+ if (componentFiles.length === 0) {
85
+ console.log(`[MDX] 未找到任何组件文件`)
86
+ return
87
+ }
88
+
89
+ console.log(`[MDX] 扫描到 ${componentFiles.length} 个组件:`)
90
+ componentFiles.forEach(file => console.log(` - ${file}`))
91
+
92
+ // 分析每个组件文件,提取子组件信息
93
+ const componentInfo: Array<{
94
+ file: string
95
+ componentName: string
96
+ subComponents: string[]
97
+ }> = []
98
+
99
+ for (const file of componentFiles) {
100
+ const fullPath = path.join(componentsDir, file)
101
+ const componentName = path.basename(file).replace(/\.(tsx?|jsx?)$/, '')
102
+ const fileContent = fs.readFileSync(fullPath, 'utf-8')
103
+ const subComponents = extractSubComponents(fileContent, componentName)
104
+
105
+ componentInfo.push({
106
+ file,
107
+ componentName,
108
+ subComponents
109
+ })
110
+
111
+ if (subComponents.length > 0) {
112
+ console.log(`[MDX] 发现 ${componentName} 的子组件: ${subComponents.join(', ')}`)
113
+ }
114
+ }
115
+
116
+ // 生成组件索引文件
117
+ const imports: string[] = []
118
+ const exports: string[] = []
119
+ const configEntries: string[] = []
120
+
121
+ for (const info of componentInfo) {
122
+ const { file, componentName, subComponents } = info
123
+ const importPath = `../components/${file.replace(/\.(tsx?|jsx?)$/, '')}`
124
+
125
+ // 导入主组件
126
+ imports.push(`import { ${componentName} } from '${importPath}'`)
127
+ exports.push(` ${componentName},`)
128
+ configEntries.push(` ${componentName}: '${importPath}'`)
129
+
130
+ // 如果有子组件,也需要注册它们
131
+ for (const subComponent of subComponents) {
132
+ const subComponentKey = `${componentName}.${subComponent}`
133
+ exports.push(` "${subComponentKey}": ${componentName}.${subComponent},`)
134
+ // 注意:子组件的配置指向父组件
135
+ configEntries.push(` "${subComponentKey}": '${importPath}'`)
136
+ }
137
+ }
138
+
139
+ const content = `// 自动生成的 MDX 组件索引文件
140
+ // 请勿手动编辑此文件
141
+
142
+ ${imports.join('\n')}
143
+
144
+ export const MDX_COMPONENTS = {
145
+ ${exports.join('\n')}
146
+ }
147
+
148
+ // 导出默认配置对象
149
+ export const mdxComponentsConfig = {
150
+ ${configEntries.join(',\n')}
151
+ }
152
+ `
153
+
154
+ // 确保输出目录存在
155
+ const outputDir = path.dirname(outputPath)
156
+ if (!fs.existsSync(outputDir)) {
157
+ fs.mkdirSync(outputDir, { recursive: true })
158
+ }
159
+
160
+ // 写入文件
161
+ fs.writeFileSync(outputPath, content, 'utf-8')
162
+ console.log(`[MDX] 组件索引文件已生成: ${outputPath}`)
163
+
164
+ } catch (error) {
165
+ console.error('[MDX] 扫描组件失败:', error)
166
+ }
167
+ }
168
+ }
169
+ }
@@ -1,9 +1,16 @@
1
1
  // @ts-nocheck
2
2
  import react from "@vitejs/plugin-react"
3
3
  import { defineConfig } from "vite"
4
+ import { mdxComponentsPlugin } from "./vite-plugin-mdx-components"
4
5
 
5
6
  export default defineConfig({
6
- plugins: [react()],
7
+ plugins: [
8
+ react(),
9
+ mdxComponentsPlugin({
10
+ componentsPath: './src/components',
11
+ outputPath: './src/generated/mdx-components.ts'
12
+ })
13
+ ],
7
14
  resolve: {
8
15
  alias: {
9
16
  "@": "src",
@@ -14,6 +21,8 @@ export default defineConfig({
14
21
  host: "0.0.0.0",
15
22
  port: 5173,
16
23
  },
17
- })
18
-
19
-
24
+ build: {
25
+ // 提高 chunk 大小警告的阈值到 2000 kB
26
+ chunkSizeWarningLimit: 2000
27
+ }
28
+ })
@@ -1,108 +0,0 @@
1
- # Quick Start
2
-
3
- This guide will walk you through creating, configuring, and running your own React documentation website from scratch in 5 minutes.
4
-
5
- ## 1. Create the Project
6
-
7
- Using the official scaffolding tool is the most efficient way. Open your terminal and run the following command:
8
-
9
- ```bash
10
- # This creates a project named "my-awesome-docs"
11
- npx create-react-docs-ui@latest my-awesome-docs
12
- ```
13
-
14
- Next, enter the project directory and install the dependencies:
15
-
16
- ```bash
17
- cd my-awesome-docs
18
- npm install
19
- ```
20
-
21
- ## 2. Organize Your Documents
22
-
23
- All your documentation content is stored as Markdown files in the `public/docs/` directory.
24
-
25
- - Open the `public/docs/en/` directory.
26
- - You can modify the existing `index.md` and files under the `guide` directory, or create new `.md` files.
27
-
28
- For example, let's create a new page. Create a new file named `about.md` in `public/docs/en/`:
29
-
30
- ```markdown
31
- ---
32
- title: About Us
33
- description: This is a page about our team.
34
- ---
35
-
36
- # About Us
37
-
38
- We love open source and creation!
39
- ```
40
-
41
-
42
- ## 3. Configure the Website
43
-
44
- Now, let's display the newly created page by modifying the configuration file.
45
-
46
- Open the core configuration file `public/config/site.yaml`.
47
-
48
- ### a. Modify Site Information
49
-
50
- Update the `site` section to give your website a new title and logo.
51
-
52
- ```yaml
53
- site:
54
- title: "My Awesome Docs"
55
- description: "A website built with React Docs UI"
56
- logo: "🚀" # You can use an emoji or an image path
57
- ```
58
-
59
- ### b. Add to the Navbar
60
-
61
- In the `navbar.items` array, add a link for the "About" page. Remember to update the links for the English version.
62
-
63
- ```yaml
64
- navbar:
65
- items:
66
- - title: "Home"
67
- link: "/en/"
68
- - title: "Guide"
69
- link: "/en/guide/introduction"
70
- - title: "About" # New
71
- link: "/en/about" # New
72
- ```
73
-
74
- ### c. Add to the Sidebar
75
-
76
- To make the "About" page visible in the sidebar, we'll add a new entry in `sidebar.collections.guide.sections`. Make sure to use English paths.
77
-
78
- ```yaml
79
- sidebar:
80
- collections:
81
- guide:
82
- sections:
83
- - title: "Getting Started"
84
- path: "/en/guide"
85
- children:
86
- - title: "Introduction"
87
- path: "/en/guide/introduction"
88
- - title: "Installation"
89
- path: "/en/guide/installation"
90
- - title: "Quick Start"
91
- path: "/en/guide/quick-start"
92
- # You can create a new section for the "About" page
93
- - title: "About Us"
94
- path: "/en/about"
95
- children:
96
- - title: "About"
97
- path: "/en/about"
98
- ```
99
-
100
- ## 4. Launch the Website
101
-
102
- Save all your changes and run the following command in your terminal:
103
-
104
- ```bash
105
- npm run dev
106
- ```
107
-
108
- Your website should now be running at `http://localhost:5173`. Visit it, and you will see the updated title, logo, and the new "About" link in the navbar and sidebar. Congratulations, you have successfully mastered the basic workflow of React Docs UI!
@@ -1,10 +0,0 @@
1
- # Guide
2
-
3
- This guide will help you fully understand and master all the features of React Docs UI. Whether you are a beginner or looking for in-depth customization, you will find the information you need here.
4
-
5
- ## Table of Contents
6
-
7
- - **[Introduction](/guide/introduction)**: Learn about the core philosophy and main advantages of React Docs UI.
8
- - **[Installation](/guide/installation)**: Learn how to install via the scaffolding tool or manually.
9
- - **[Quick Start](/guide/quick-start)**: Create and run your first documentation website in 5 minutes.
10
- - **[Configuration (`site.yaml`)](/guide/configuration)**: Dive deep into each configuration option to take full control of your site.
@@ -1,10 +0,0 @@
1
- # 指南
2
-
3
- 本指南将帮助你全面了解并掌握 React Docs UI 的各项功能。无论你是初学者还是希望进行深度定制,都能在这里找到所需的信息。
4
-
5
- ## 目录
6
-
7
- - **[介绍](/guide/introduction)**: 了解 React Docs UI 的核心理念和主要优势。
8
- - **[安装](/guide/installation)**: 学习如何通过脚手架或手动方式安装。
9
- - **[快速上手](/guide/quick-start)**: 在 5 分钟内创建并运行你的第一个文档网站。
10
- - **[配置说明 (`site.yaml`)](/guide/configuration)**: 深入了解每个配置项,完全掌控你的网站。