191 lines
4.7 KiB
JavaScript
191 lines
4.7 KiB
JavaScript
import { useState, useEffect } from 'react'
|
||
import { Layout, Menu, Spin } from 'antd'
|
||
import { FileTextOutlined } from '@ant-design/icons'
|
||
import ReactMarkdown from 'react-markdown'
|
||
import remarkGfm from 'remark-gfm'
|
||
import rehypeRaw from 'rehype-raw'
|
||
import rehypeHighlight from 'rehype-highlight'
|
||
import 'highlight.js/styles/github.css'
|
||
import './DocsPage.css'
|
||
|
||
const { Sider, Content } = Layout
|
||
|
||
// 文档目录数据
|
||
const docsMenuData = [
|
||
{
|
||
key: 'design',
|
||
label: '设计规范',
|
||
children: [
|
||
{
|
||
key: 'design-cookbook',
|
||
label: '设计手册',
|
||
path: '/docs/DESIGN_COOKBOOK.md',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
key: 'components',
|
||
label: '组件文档',
|
||
children: [
|
||
{
|
||
key: 'components-overview',
|
||
label: '组件概览',
|
||
path: '/docs/components/README.md',
|
||
},
|
||
{
|
||
key: 'page-title-bar',
|
||
label: 'PageTitleBar',
|
||
path: '/docs/components/PageTitleBar.md',
|
||
},
|
||
{
|
||
key: 'list-action-bar',
|
||
label: 'ListActionBar',
|
||
path: '/docs/components/ListActionBar.md',
|
||
},
|
||
{
|
||
key: 'tree-filter-panel',
|
||
label: 'TreeFilterPanel',
|
||
path: '/docs/components/TreeFilterPanel.md',
|
||
},
|
||
{
|
||
key: 'list-table',
|
||
label: 'ListTable',
|
||
path: '/docs/components/ListTable.md',
|
||
},
|
||
{
|
||
key: 'detail-drawer',
|
||
label: 'DetailDrawer',
|
||
path: '/docs/components/DetailDrawer.md',
|
||
},
|
||
{
|
||
key: 'info-panel',
|
||
label: 'InfoPanel',
|
||
path: '/docs/components/InfoPanel.md',
|
||
},
|
||
{
|
||
key: 'confirm-dialog',
|
||
label: 'ConfirmDialog',
|
||
path: '/docs/components/ConfirmDialog.md',
|
||
},
|
||
{
|
||
key: 'toast',
|
||
label: 'Toast',
|
||
path: '/docs/components/Toast.md',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
key: 'pages',
|
||
label: '页面文档',
|
||
children: [
|
||
{
|
||
key: 'main-layout',
|
||
label: '主布局',
|
||
path: '/docs/pages/main-layout.md',
|
||
},
|
||
],
|
||
},
|
||
]
|
||
|
||
function DocsPage() {
|
||
const [selectedKey, setSelectedKey] = useState('design-cookbook')
|
||
const [markdownContent, setMarkdownContent] = useState('')
|
||
const [loading, setLoading] = useState(false)
|
||
|
||
// 构建菜单项
|
||
const menuItems = docsMenuData.map((group) => ({
|
||
key: group.key,
|
||
label: group.label,
|
||
icon: <FileTextOutlined />,
|
||
children: group.children.map((item) => ({
|
||
key: item.key,
|
||
label: item.label,
|
||
})),
|
||
}))
|
||
|
||
// 根据 key 查找文档路径
|
||
const findDocPath = (key) => {
|
||
for (const group of docsMenuData) {
|
||
const found = group.children.find((item) => item.key === key)
|
||
if (found) return found.path
|
||
}
|
||
return null
|
||
}
|
||
|
||
// 加载 markdown 文件
|
||
const loadMarkdown = async (key) => {
|
||
const path = findDocPath(key)
|
||
if (!path) return
|
||
|
||
setLoading(true)
|
||
try {
|
||
const response = await fetch(path)
|
||
if (response.ok) {
|
||
const text = await response.text()
|
||
setMarkdownContent(text)
|
||
} else {
|
||
setMarkdownContent('# 文档加载失败\n\n无法加载该文档,请稍后重试。')
|
||
}
|
||
} catch (error) {
|
||
console.error('Error loading markdown:', error)
|
||
setMarkdownContent('# 文档加载失败\n\n' + error.message)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
// 处理菜单点击
|
||
const handleMenuClick = ({ key }) => {
|
||
setSelectedKey(key)
|
||
loadMarkdown(key)
|
||
}
|
||
|
||
// 初始加载默认文档
|
||
useEffect(() => {
|
||
loadMarkdown(selectedKey)
|
||
}, [])
|
||
|
||
return (
|
||
<div className="docs-page">
|
||
<Layout className="docs-layout">
|
||
{/* 左侧目录 */}
|
||
<Sider width={280} className="docs-sider" theme="light">
|
||
<div className="docs-sider-header">
|
||
<h2>文档中心</h2>
|
||
</div>
|
||
<Menu
|
||
mode="inline"
|
||
selectedKeys={[selectedKey]}
|
||
defaultOpenKeys={['design', 'components', 'pages']}
|
||
items={menuItems}
|
||
onClick={handleMenuClick}
|
||
className="docs-menu"
|
||
/>
|
||
</Sider>
|
||
|
||
{/* 右侧内容 */}
|
||
<Content className="docs-content">
|
||
<div className="docs-content-wrapper">
|
||
{loading ? (
|
||
<div className="docs-loading">
|
||
<Spin size="large" tip="加载中..." />
|
||
</div>
|
||
) : (
|
||
<div className="markdown-body">
|
||
<ReactMarkdown
|
||
remarkPlugins={[remarkGfm]}
|
||
rehypePlugins={[rehypeRaw, rehypeHighlight]}
|
||
>
|
||
{markdownContent}
|
||
</ReactMarkdown>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</Content>
|
||
</Layout>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default DocsPage
|