Skip to content

Commit 96c2eee

Browse files
authored
fix: 修复gitignore忽略问题 (#1874)
* fix(.gitignore): 更新VitePress忽略目录配置 * feat(docs): 初始化 VitePress 文档站点并集成 H5 演示功能 * chore(docs): 更新H5演示路径并添加调试日志
1 parent 0cb81b1 commit 96c2eee

6 files changed

Lines changed: 547 additions & 1 deletion

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ coverage
3939
.mino
4040
.playwright-mcp/
4141

42-
.vitepress/
42+
.vitepress/cache
43+
.vitepress/dist
4344
sessions/
4445
statuses/
4546

docs/.vitepress/config.mts

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import { defineConfig } from 'vitepress'
2+
import fs from 'node:fs'
3+
import path from 'node:path'
4+
import { fileURLToPath } from 'node:url'
5+
6+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
7+
8+
const h5Path = path.resolve(__dirname, '../../examples/demo/dist')
9+
10+
function h5DemoMiddleware() {
11+
const mimeTypes: Record<string, string> = {
12+
'.html': 'text/html',
13+
'.js': 'application/javascript',
14+
'.css': 'text/css',
15+
'.png': 'image/png',
16+
'.jpg': 'image/jpeg',
17+
'.jpeg': 'image/jpeg',
18+
'.svg': 'image/svg+xml',
19+
'.json': 'application/json',
20+
'.woff2': 'font/woff2',
21+
'.woff': 'font/woff',
22+
'.ttf': 'font/ttf',
23+
}
24+
25+
return (req: any, res: any, next: any) => {
26+
if (!req.url?.startsWith('/taro-ui/h5/')) return next()
27+
const relPath = decodeURIComponent(req.url.slice('/taro-ui/h5/'.length).split('?')[0])
28+
const filePath = path.join(h5Path, relPath)
29+
if (!filePath.startsWith(h5Path + path.sep)) return next()
30+
fs.readFile(filePath, (err, data) => {
31+
if (err) return next()
32+
const ext = path.extname(filePath)
33+
res.setHeader('Content-Type', mimeTypes[ext] || 'application/octet-stream')
34+
res.end(data)
35+
})
36+
}
37+
}
38+
39+
export default defineConfig({
40+
srcDir: 'docs',
41+
lang: 'zh-CN',
42+
title: 'Taro UI',
43+
description: '一套基于 Taro 框架开发的多端 UI 组件库',
44+
base: '/taro-ui/',
45+
lastUpdated: true,
46+
head: [
47+
['link', { rel: 'icon', href: '/taro-ui/favicon.png' }]
48+
],
49+
themeConfig: {
50+
logo: '/navbar-logo.png',
51+
nav: [
52+
{ text: '首页', link: '/' },
53+
{ text: '文档', link: '/guide/introduction' },
54+
{ text: '组件', link: '/components/icon' },
55+
{ text: 'GitHub', link: 'https://github.com/NervJS/taro-ui' }
56+
],
57+
sidebar: {
58+
'/guide/': [
59+
{
60+
text: '综述',
61+
items: [
62+
{ text: '介绍', link: '/guide/introduction' },
63+
{ text: '快速上手', link: '/guide/quickstart' },
64+
{ text: '自定义主题', link: '/guide/customize-theme' },
65+
{ text: '常见问题', link: '/guide/questions' },
66+
{ text: '更新日志', link: '/guide/changelog' },
67+
{ text: '设计资源', link: '/guide/resource' }
68+
]
69+
}
70+
],
71+
'/components/': [
72+
{
73+
text: '基础组件',
74+
items: [
75+
{ text: '图标', link: '/components/icon' },
76+
{ text: '按钮', link: '/components/button' },
77+
{ text: '浮动按钮', link: '/components/fab' }
78+
]
79+
},
80+
{
81+
text: '视图组件',
82+
items: [
83+
{ text: '头像', link: '/components/avatar' },
84+
{ text: '文章样式', link: '/components/article' },
85+
{ text: '徽标', link: '/components/badge' },
86+
{ text: '倒计时', link: '/components/countdown' },
87+
{ text: '幕帘', link: '/components/curtain' },
88+
{ text: '页面提示', link: '/components/load-more' },
89+
{ text: '通告栏', link: '/components/noticebar' },
90+
{ text: '标签', link: '/components/tag' },
91+
{ text: '时间轴', link: '/components/timeline' },
92+
{ text: '滑动视图容器', link: '/components/swiper' },
93+
{ text: '分隔符', link: '/components/divider' },
94+
{ text: '步骤条', link: '/components/steps' }
95+
]
96+
},
97+
{
98+
text: '操作反馈',
99+
items: [
100+
{ text: '动作面板', link: '/components/action-sheet' },
101+
{ text: '活动指示器', link: '/components/activity-indicator' },
102+
{ text: '模态框', link: '/components/modal' },
103+
{ text: '进度条', link: '/components/progress' },
104+
{ text: '轻提示', link: '/components/toast' },
105+
{ text: '滑动操作', link: '/components/swipe-action' },
106+
{ text: '消息通知', link: '/components/message' }
107+
]
108+
},
109+
{
110+
text: '表单组件',
111+
items: [
112+
{ text: '表单', link: '/components/form' },
113+
{ text: '输入框', link: '/components/input' },
114+
{ text: '数字输入框', link: '/components/input-number' },
115+
{ text: '单选按钮', link: '/components/radio' },
116+
{ text: '多选框', link: '/components/checkbox' },
117+
{ text: '评分', link: '/components/rate' },
118+
{ text: '开关', link: '/components/switch' },
119+
{ text: '多行文本框', link: '/components/textarea' },
120+
{ text: '选择器', link: '/components/picker' },
121+
{ text: '搜索栏', link: '/components/search-bar' },
122+
{ text: '滑动条', link: '/components/slider' },
123+
{ text: '图片选择器', link: '/components/image-picker' },
124+
{ text: '范围选择器', link: '/components/range' }
125+
]
126+
},
127+
{
128+
text: '布局组件',
129+
items: [
130+
{ text: '弹性布局', link: '/components/flex' },
131+
{ text: '栅格布局', link: '/components/grid' },
132+
{ text: '列表', link: '/components/list' },
133+
{ text: '卡片', link: '/components/card' },
134+
{ text: '浮动弹层', link: '/components/float-layout' },
135+
{ text: '手风琴', link: '/components/accordion' }
136+
]
137+
},
138+
{
139+
text: '导航组件',
140+
items: [
141+
{ text: '导航栏', link: '/components/navbar' },
142+
{ text: '标签栏', link: '/components/tabbar' },
143+
{ text: '标签页', link: '/components/tabs' },
144+
{ text: '分段器', link: '/components/segmented-control' },
145+
{ text: '分页器', link: '/components/pagination' },
146+
{ text: '抽屉', link: '/components/drawer' },
147+
{ text: '索引选择器', link: '/components/indexes' }
148+
]
149+
},
150+
{
151+
text: '高阶组件',
152+
items: [
153+
{ text: '日历', link: '/components/calendar' }
154+
]
155+
}
156+
]
157+
},
158+
socialLinks: [
159+
{ icon: 'github', link: 'https://github.com/NervJS/taro-ui' }
160+
],
161+
footer: {
162+
message: 'Released under the MIT License.',
163+
copyright: 'Copyright © 京东·凹凸实验室'
164+
},
165+
search: {
166+
provider: 'local'
167+
}
168+
},
169+
markdown: {
170+
container: {
171+
warningLabel: '警告'
172+
}
173+
},
174+
vite: {
175+
publicDir: path.resolve(__dirname, '../assets'),
176+
server: {
177+
port: 3000
178+
},
179+
plugins: [
180+
{
181+
name: 'h5-demo-dev-server',
182+
configureServer(server) {
183+
server.middlewares.use(h5DemoMiddleware())
184+
}
185+
}
186+
]
187+
}
188+
})

docs/.vitepress/theme/Layout.vue

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
<script setup lang="ts">
3+
import { useRoute, useData } from 'vitepress'
4+
import { computed, onMounted, ref } from 'vue'
5+
import DefaultTheme from 'vitepress/theme'
6+
import pageRoute from '../../page-route'
7+
8+
const { Layout } = DefaultTheme
9+
const route = useRoute()
10+
const { site } = useData()
11+
const base = computed(() => site.value.base || '/')
12+
13+
const nameToRoute: Record<string, string> = {
14+
'input-number': 'inputnumber',
15+
'search-bar': 'searchbar',
16+
'image-picker': 'imagepicker',
17+
'float-layout': 'floatlayout',
18+
'swipe-action': 'swipeaction',
19+
'segmented-control': 'segmentedcontrol',
20+
'load-more': 'loadmore',
21+
'activity-indicator': 'activityindicator',
22+
'action-sheet': 'actionsheet'
23+
}
24+
25+
const demoPath = computed(() => {
26+
const path = route.path
27+
const match = path.match(/\/components\/([\w-]+)/)
28+
if (!match) return ''
29+
const fileName = match[1].toLowerCase()
30+
const routeKey = nameToRoute[fileName] || fileName
31+
const routeMap: Record<string, string> = pageRoute
32+
return routeMap[routeKey] || ''
33+
})
34+
35+
const iframeSrc = computed(() => {
36+
if (!demoPath.value) return ''
37+
return `${base.value}h5/index.html#/pages/${demoPath.value}/index`
38+
})
39+
40+
const iframeBg = computed(() => {
41+
return `${base.value}iframe_iphonex.png`
42+
})
43+
44+
const hasH5Demo = ref(!import.meta.env.DEV)
45+
46+
onMounted(() => {
47+
if (!demoPath.value || !import.meta.env.DEV) return
48+
fetch(`${base.value}h5/index.html`)
49+
.then(async r => {
50+
if (!r.ok) {
51+
hasH5Demo.value = false
52+
return
53+
}
54+
// VitePress dev server SPA fallback returns docs index.html,
55+
// which does not contain H5 demo's app.js reference.
56+
const text = await r.text()
57+
hasH5Demo.value = text.includes('src="./js/app.js"')
58+
})
59+
.catch(() => { hasH5Demo.value = false })
60+
})
61+
</script>
62+
63+
<template>
64+
<Layout>
65+
<template #doc-top>
66+
<div v-if="demoPath && hasH5Demo" class="demo-iframe-wrapper" :style="{ backgroundImage: `url('${iframeBg}')` }">
67+
<iframe :src="iframeSrc" frameborder="0"></iframe>
68+
</div>
69+
</template>
70+
</Layout>
71+
</template>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script setup lang="ts">
2+
import ICONS from '../../../components/iconlist/icons.js'
3+
4+
interface Props {
5+
type?: string
6+
}
7+
8+
const props = withDefaults(defineProps<Props>(), {
9+
type: 'main'
10+
})
11+
12+
const iconList = ICONS[props.type as keyof typeof ICONS] || []
13+
</script>
14+
15+
<template>
16+
<div class="icon-list">
17+
<div v-for="icon in iconList" :key="icon" class="icon-list-item">
18+
<i :class="`at-icon at-icon-${icon}`"></i>
19+
<span>{{ icon }}</span>
20+
</div>
21+
</div>
22+
</template>

docs/.vitepress/theme/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { Theme } from 'vitepress'
2+
import DefaultTheme from 'vitepress/theme'
3+
import './style.css'
4+
import IconList from './components/IconList.vue'
5+
import Layout from './Layout.vue'
6+
7+
export default {
8+
extends: DefaultTheme,
9+
Layout,
10+
enhanceApp({ app }) {
11+
app.component('IconList', IconList)
12+
}
13+
} satisfies Theme

0 commit comments

Comments
 (0)