docs: ✏️ 文档侧边栏新增版本号显示

This commit is contained in:
不如摸鱼去 2025-07-08 17:50:28 +08:00
parent 372735a16a
commit 6c6d5c9ea3
39 changed files with 473 additions and 36 deletions

View File

@ -1,7 +1,7 @@
/* /*
* @Author: weisheng * @Author: weisheng
* @Date: 2023-07-27 10:26:09 * @Date: 2023-07-27 10:26:09
* @LastEditTime: 2025-07-07 20:46:21 * @LastEditTime: 2025-07-08 17:45:58
* @LastEditors: weisheng * @LastEditors: weisheng
* @Description: * @Description:
* @FilePath: /wot-design-uni/docs/.vitepress/config.mts * @FilePath: /wot-design-uni/docs/.vitepress/config.mts
@ -11,6 +11,7 @@ import { defineConfig } from 'vitepress';
import viteCompression from 'vite-plugin-compression' import viteCompression from 'vite-plugin-compression'
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from 'node:url'
import { MarkdownTransform } from './plugins/markdown-transform' import { MarkdownTransform } from './plugins/markdown-transform'
import { VersionBadgePlugin } from './plugins/version-badge'
import llmstxt from 'vitepress-plugin-llms' import llmstxt from 'vitepress-plugin-llms'
import enUS from './locales/en-US' import enUS from './locales/en-US'
import zhCN from './locales/zh-CN' import zhCN from './locales/zh-CN'
@ -22,6 +23,7 @@ export default defineConfig({
domain: 'https://wot-design-uni.cn', domain: 'https://wot-design-uni.cn',
}), }),
MarkdownTransform(), MarkdownTransform(),
VersionBadgePlugin(),
viteCompression({ viteCompression({
verbose: true, verbose: true,
disable: false, disable: false,
@ -62,6 +64,12 @@ export default defineConfig({
replacement: fileURLToPath( replacement: fileURLToPath(
new URL('./theme/components/VPNavBar.vue', import.meta.url) new URL('./theme/components/VPNavBar.vue', import.meta.url)
) )
},
{
find: /^.*\/VPSidebarItem\.vue$/,
replacement: fileURLToPath(
new URL('./theme/components/VPSidebarItem.vue', import.meta.url)
)
} }
] ]
} }

View File

@ -0,0 +1,10 @@
// 自动生成的版本数据
// 此文件由插件自动生成,请勿手动修改
// 如需修改版本信息,请在对应的 Markdown 文件 frontmatter 中修改
export const versionData = {
"/component/count-to": "1.3.8",
"/component/keyboard": "1.3.10",
"/component/root-portal": "$LOWEST_VERSION$",
"/component/signature": "1.6.0"
}

View File

@ -0,0 +1,87 @@
import type { Plugin } from 'vite'
import { readFileSync, existsSync, writeFileSync } from 'fs'
import { resolve } from 'path'
import fs from 'fs'
// 从 Markdown 文件中提取版本信息
function extractVersionFromMarkdown(filePath: string): string | null {
if (!existsSync(filePath)) return null
try {
const content = readFileSync(filePath, 'utf-8')
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/)
if (frontmatterMatch) {
const frontmatter = frontmatterMatch[1]
const versionMatch = frontmatter.match(/version:\s*(['"]?)([^'"\n]+)\1/)
if (versionMatch) {
return versionMatch[2].trim()
}
}
} catch (e) {
console.warn(`Failed to read file ${filePath}:`, e)
}
return null
}
// 扫描组件文档目录,提取版本信息
function scanComponentVersions(): Record<string, string> {
const versionData: Record<string, string> = {}
const componentDir = resolve(__dirname, '../../component')
if (!existsSync(componentDir)) {
console.warn('Component directory not found:', componentDir)
return versionData
}
try {
const files = fs.readdirSync(componentDir).filter((file: string) => file.endsWith('.md'))
files.forEach((filename: string) => {
const filePath = resolve(componentDir, filename)
const version = extractVersionFromMarkdown(filePath)
if (version) {
const path = `/component/${filename.replace('.md', '')}`
versionData[path] = version
console.log(`✅ Found version info in ${filename}:`, version)
}
})
} catch (e) {
console.warn('Failed to scan component directory:', e)
}
return versionData
}
// 生成版本数据文件
function generateVersionData(): string {
const versionData = scanComponentVersions()
return `// 自动生成的版本数据
// 此文件由插件自动生成,请勿手动修改
// 如需修改版本信息,请在对应的 Markdown 文件 frontmatter 中修改
export const versionData = ${JSON.stringify(versionData, null, 2)}
`
}
export function VersionBadgePlugin(): Plugin {
return {
name: 'version-badge',
configResolved() {
// 在配置解析后生成版本数据
try {
const versionDataContent = generateVersionData()
const outputPath = resolve(__dirname, '../config/version-data.ts')
writeFileSync(outputPath, versionDataContent, 'utf-8')
console.log('✅ Version data generated successfully')
} catch (e) {
console.error('❌ Failed to generate version data:', e)
}
}
}
}

View File

@ -0,0 +1,311 @@
<script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import { computed } from 'vue'
import { useSidebarControl } from 'vitepress/dist/client/theme-default/composables/sidebar.js'
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue'
import { versionData } from '../../config/version-data'
const props = defineProps<{
item: DefaultTheme.SidebarItem
depth: number
}>()
const {
collapsed,
collapsible,
isLink,
isActiveLink,
hasActiveLink,
hasChildren,
toggle
} = useSidebarControl(computed(() => props.item))
const sectionTag = computed(() => (hasChildren.value ? 'section' : `div`))
const linkTag = computed(() => (isLink.value ? 'a' : 'div'))
const textTag = computed(() => {
return !hasChildren.value
? 'p'
: props.depth + 2 === 7
? 'p'
: `h${props.depth + 2}`
})
const itemRole = computed(() => (isLink.value ? undefined : 'button'))
const classes = computed(() => [
[`level-${props.depth}`],
{ collapsible: collapsible.value },
{ collapsed: collapsed.value },
{ 'is-link': isLink.value },
{ 'is-active': isActiveLink.value },
{ 'has-active': hasActiveLink.value }
])
//
const versionInfo = computed(() => {
if (!props.item.link) return null
//
const path = props.item.link
const version = versionData[path]
if (!version) return null
return {
text: version,
type: 'warning' // 使warning
}
})
function onItemInteraction(e: MouseEvent | Event) {
if ('key' in e && e.key !== 'Enter') {
return
}
!props.item.link && toggle()
}
function onCaretClick() {
props.item.link && toggle()
}
</script>
<template>
<component :is="sectionTag" class="VPSidebarItem" :class="classes">
<div
v-if="item.text"
class="item"
:role="itemRole"
v-on="
item.items
? { click: onItemInteraction, keydown: onItemInteraction }
: {}
"
:tabindex="item.items && 0"
>
<div class="indicator" />
<VPLink
v-if="item.link"
:tag="linkTag"
class="link"
:href="item.link"
:rel="item.rel"
:target="item.target"
>
<component :is="textTag" class="text">
{{ item.text }}
<el-tag
v-if="versionInfo"
size="small"
effect="plain"
round
class="version-tag"
>
{{ versionInfo.text }}
</el-tag>
</component>
</VPLink>
<component v-else :is="textTag" class="text">
{{ item.text }}
<el-tag
v-if="versionInfo"
size="small"
effect="plain"
round
class="version-tag"
>
{{ versionInfo.text }}
</el-tag>
</component>
<div
v-if="item.collapsed != null && item.items && item.items.length"
class="caret"
role="button"
aria-label="toggle section"
@click="onCaretClick"
@keydown.enter="onCaretClick"
tabindex="0"
>
<span class="vpi-chevron-right caret-icon" />
</div>
</div>
<div v-if="item.items && item.items.length" class="items">
<template v-if="depth < 5">
<VPSidebarItem
v-for="i in item.items"
:key="i.text"
:item="i"
:depth="depth + 1"
/>
</template>
</div>
</component>
</template>
<style scoped>
.VPSidebarItem.level-0 {
padding-bottom: 24px;
}
.VPSidebarItem.collapsed.level-0 {
padding-bottom: 10px;
}
.item {
position: relative;
display: flex;
width: 100%;
}
.VPSidebarItem.collapsible > .item {
cursor: pointer;
}
.indicator {
position: absolute;
top: 6px;
bottom: 6px;
left: -17px;
width: 2px;
border-radius: 2px;
transition: background-color 0.25s;
}
.VPSidebarItem.level-2.is-active > .item > .indicator,
.VPSidebarItem.level-3.is-active > .item > .indicator,
.VPSidebarItem.level-4.is-active > .item > .indicator,
.VPSidebarItem.level-5.is-active > .item > .indicator {
background-color: var(--vp-c-brand-1);
}
.link {
display: flex;
align-items: center;
flex-grow: 1;
}
.text {
flex-grow: 1;
padding: 4px 0;
line-height: 24px;
font-size: 14px;
transition: color 0.25s;
display: flex;
align-items: center;
gap: 8px;
}
.VPSidebarItem.level-0 .text {
font-weight: 700;
color: var(--vp-c-text-1);
}
.VPSidebarItem.level-1 .text,
.VPSidebarItem.level-2 .text,
.VPSidebarItem.level-3 .text,
.VPSidebarItem.level-4 .text,
.VPSidebarItem.level-5 .text {
font-weight: 500;
color: var(--vp-c-text-2);
}
.VPSidebarItem.level-0.is-link > .item > .link:hover .text,
.VPSidebarItem.level-1.is-link > .item > .link:hover .text,
.VPSidebarItem.level-2.is-link > .item > .link:hover .text,
.VPSidebarItem.level-3.is-link > .item > .link:hover .text,
.VPSidebarItem.level-4.is-link > .item > .link:hover .text,
.VPSidebarItem.level-5.is-link > .item > .link:hover .text {
color: var(--vp-c-brand-1);
}
.VPSidebarItem.level-0.has-active > .item > .text,
.VPSidebarItem.level-1.has-active > .item > .text,
.VPSidebarItem.level-2.has-active > .item > .text,
.VPSidebarItem.level-3.has-active > .item > .text,
.VPSidebarItem.level-4.has-active > .item > .text,
.VPSidebarItem.level-5.has-active > .item > .text,
.VPSidebarItem.level-0.has-active > .item > .link > .text,
.VPSidebarItem.level-1.has-active > .item > .link > .text,
.VPSidebarItem.level-2.has-active > .item > .link > .text,
.VPSidebarItem.level-3.has-active > .item > .link > .text,
.VPSidebarItem.level-4.has-active > .item > .link > .text,
.VPSidebarItem.level-5.has-active > .item > .link > .text {
color: var(--vp-c-text-1);
}
.VPSidebarItem.level-0.is-active > .item .link > .text,
.VPSidebarItem.level-1.is-active > .item .link > .text,
.VPSidebarItem.level-2.is-active > .item .link > .text,
.VPSidebarItem.level-3.is-active > .item .link > .text,
.VPSidebarItem.level-4.is-active > .item .link > .text,
.VPSidebarItem.level-5.is-active > .item .link > .text {
color: var(--vp-c-brand-1);
}
.caret {
display: flex;
justify-content: center;
align-items: center;
margin-right: -7px;
width: 32px;
height: 32px;
color: var(--vp-c-text-3);
cursor: pointer;
transition: color 0.25s;
flex-shrink: 0;
}
.item:hover .caret {
color: var(--vp-c-text-2);
}
.item:hover .caret:hover {
color: var(--vp-c-text-1);
}
.caret-icon {
font-size: 18px;
/*rtl:ignore*/
transform: rotate(90deg);
transition: transform 0.25s;
}
.VPSidebarItem.collapsed .caret-icon {
transform: rotate(0)/*rtl:rotate(180deg)*/;
}
.VPSidebarItem.level-1 .items,
.VPSidebarItem.level-2 .items,
.VPSidebarItem.level-3 .items,
.VPSidebarItem.level-4 .items,
.VPSidebarItem.level-5 .items {
border-left: 1px solid var(--vp-c-divider);
padding-left: 16px;
}
.VPSidebarItem.collapsed .items {
display: none;
}
/* 版本标签样式 */
.version-tag {
margin-left: 4px;
flex-shrink: 0;
}
/* 深色模式适配 */
:root.dark .version-tag {
opacity: 0.9;
}
/* 响应式设计 */
@media (max-width: 960px) {
.version-tag {
font-size: 10px;
}
}
</style>

1
docs/.vitepress/types/sidebar.d.ts vendored Normal file
View File

@ -0,0 +1 @@

View File

@ -1,4 +1,4 @@
# Circle 环形进度条 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.19</el-tag> # Circle 环形进度条
圆环形的进度条组件,支持进度渐变动画。 圆环形的进度条组件,支持进度渐变动画。

View File

@ -1,4 +1,4 @@
# CountDown 倒计时<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.58</el-tag> # CountDown 倒计时
用于实时展示倒计时数值,支持毫秒精度。 用于实时展示倒计时数值,支持毫秒精度。

View File

@ -1,4 +1,7 @@
# CountTo 数字滚动<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.3.8</el-tag> ---
version: 1.3.8
---
# CountTo 数字滚动
数字滚动组件。 数字滚动组件。

View File

@ -1,4 +1,4 @@
# Icon 图标 <el-tag text style="vertical-align: middle;margin-left:8px;" type="warning">0.1.27 更新</el-tag> # Icon 图标
基于字体的图标集。 基于字体的图标集。

View File

@ -1,4 +1,4 @@
# IndexBar 索引栏 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.2.21</el-tag> # IndexBar 索引栏
用于列表的索引分类显示和快速定位。 用于列表的索引分类显示和快速定位。

View File

@ -1,4 +1,7 @@
# Keyboard 虚拟键盘 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.3.10</el-tag> ---
version: 1.3.10
---
# Keyboard 虚拟键盘
虚拟数字键盘,用于输入数字、密码、身份证或车牌号等场景。 虚拟数字键盘,用于输入数字、密码、身份证或车牌号等场景。

View File

@ -1,4 +1,4 @@
# Overlay 遮罩层 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.30</el-tag> # Overlay 遮罩层
创建一个遮罩层,用于强调特定的页面元素,并阻止用户进行其他操作。 创建一个遮罩层,用于强调特定的页面元素,并阻止用户进行其他操作。

View File

@ -1,4 +1,4 @@
# PasswordInput 密码输入框 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.2.0</el-tag> # PasswordInput 密码输入框
带网格的输入框组件,可以用于输入密码、短信验证码等场景,通常与[数字键盘](./number-keyboard.md)组件配合使用。 带网格的输入框组件,可以用于输入密码、短信验证码等场景,通常与[数字键盘](./number-keyboard.md)组件配合使用。

View File

@ -1,4 +1,7 @@
# Root Portal 根节点传送<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">$LOWEST_VERSION$</el-tag> ---
version: $LOWEST_VERSION$
---
# Root Portal 根节点传送
是否从页面中脱离出来,用于解决各种 fixed 失效问题,主要用于制作弹窗、弹出层等。 是否从页面中脱离出来,用于解决各种 fixed 失效问题,主要用于制作弹窗、弹出层等。

View File

@ -1,4 +1,4 @@
# Segmented 分段器 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.23</el-tag> # Segmented 分段器
分段器用于展示多个选项并允许用户选择其中单个选项。 分段器用于展示多个选项并允许用户选择其中单个选项。

View File

@ -1,4 +1,4 @@
# SelectPicker 单复选选择器 <el-tag text style="vertical-align: middle;margin-left:8px;" type="warning">0.1.34 更新</el-tag> # SelectPicker 单复选选择器
用于从一组选项中进行单选或多选。 用于从一组选项中进行单选或多选。

View File

@ -1,4 +1,4 @@
# Sidebar 侧边导航 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.49</el-tag> # Sidebar 侧边导航
垂直展示的导航栏,用于在不同的内容区域之间进行切换。 垂直展示的导航栏,用于在不同的内容区域之间进行切换。

View File

@ -1,4 +1,7 @@
# Signature 签名 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.6.0</el-tag> ---
version: 1.6.0
---
# Signature 签名
用于签名场景,基于 Canvas 实现的签名组件。提供了基础签名、历史记录、笔锋效果等功能。 用于签名场景,基于 Canvas 实现的签名组件。提供了基础签名、历史记录、笔锋效果等功能。

View File

@ -1,4 +1,4 @@
# Table 表格 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.39</el-tag> # Table 表格
用于展示多条结构类似的数据, 可对数据进行排序等操作。 用于展示多条结构类似的数据, 可对数据进行排序等操作。

View File

@ -1,4 +1,4 @@
# Textarea 文本域 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.2.0</el-tag> # Textarea 文本域
用于输入多行文本信息。 用于输入多行文本信息。

View File

@ -1,5 +1,4 @@
# Watermark 水印
# Watermark 水印 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.16</el-tag>
在页面或组件上添加指定的图片或文字,可用于版权保护、品牌宣传等场景。 在页面或组件上添加指定的图片或文字,可用于版权保护、品牌宣传等场景。

View File

@ -1,4 +1,4 @@
# Circle Progress Bar <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.19</el-tag> # Circle Progress Bar
A circular progress bar component that supports progress gradient animation. A circular progress bar component that supports progress gradient animation.

View File

@ -1,4 +1,4 @@
# CountDown<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.58</el-tag> # CountDown
Used to display countdown values in real-time, supporting millisecond precision. Used to display countdown values in real-time, supporting millisecond precision.

View File

@ -1,4 +1,4 @@
# CountTo Number Animation<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.3.8</el-tag> # CountTo Number Animation
Number animation component. Number animation component.

View File

@ -1,4 +1,4 @@
# IndexBar <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.2.21</el-tag> # IndexBar
Used for displaying index classification and quick positioning of lists. Used for displaying index classification and quick positioning of lists.

View File

@ -1,4 +1,7 @@
# Keyboard <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.3.10</el-tag> ---
version: 1.3.10
---
# Keyboard
Virtual keyboard for inputting numbers, passwords, ID cards, or license plate numbers. Virtual keyboard for inputting numbers, passwords, ID cards, or license plate numbers.

View File

@ -1,4 +1,4 @@
# MessageBox <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.3.10</el-tag> # MessageBox
A dialog box that pops up, commonly used for message prompts, message confirmation, etc., supports function calls. A dialog box that pops up, commonly used for message prompts, message confirmation, etc., supports function calls.

View File

@ -1,4 +1,4 @@
# Overlay <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.30</el-tag> # Overlay
Create a mask layer to emphasize specific page elements and prevent users from performing other operations. Create a mask layer to emphasize specific page elements and prevent users from performing other operations.

View File

@ -1,4 +1,4 @@
# PasswordInput <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.2.0</el-tag> # PasswordInput
A grid input box component that can be used for inputting passwords, SMS verification codes, and other scenarios. Usually used in conjunction with the [number keyboard](./number-keyboard.md) component. A grid input box component that can be used for inputting passwords, SMS verification codes, and other scenarios. Usually used in conjunction with the [number keyboard](./number-keyboard.md) component.

View File

@ -1,4 +1,7 @@
# Root Portal<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">$LOWEST_VERSION$</el-tag> ---
version: $LOWEST_VERSION$
---
# Root Portal
Whether to break out of the page, used to solve various fixed positioning issues, mainly used for making popups and overlays. Whether to break out of the page, used to solve various fixed positioning issues, mainly used for making popups and overlays.

View File

@ -1,4 +1,4 @@
# Segmented <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.23</el-tag> # Segmented
Segmented is used to display multiple options and allow users to select a single option. Segmented is used to display multiple options and allow users to select a single option.

View File

@ -1,4 +1,4 @@
# SelectPicker <el-tag text style="vertical-align: middle;margin-left:8px;" type="warning">0.1.34 Update</el-tag> # SelectPicker
Used for single or multiple selection from a set of options. Used for single or multiple selection from a set of options.

View File

@ -1,4 +1,4 @@
# Sidebar <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.49</el-tag> # Sidebar
A vertical navigation bar used to switch between different content areas. A vertical navigation bar used to switch between different content areas.

View File

@ -1,4 +1,7 @@
# Signature <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.6.0</el-tag> ---
version: 1.6.0
---
# Signature
A signature component based on Canvas for signature scenarios. Provides basic signature, history record, and pressure effect features. A signature component based on Canvas for signature scenarios. Provides basic signature, history record, and pressure effect features.

View File

@ -1,4 +1,4 @@
# Table <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.39</el-tag> # Table
Used to display multiple pieces of data with similar structures, allowing operations such as sorting. Used to display multiple pieces of data with similar structures, allowing operations such as sorting.

View File

@ -1,4 +1,4 @@
'# Textarea <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.2.0</el-tag> # Textarea
Used for inputting multi-line text information. Used for inputting multi-line text information.

View File

@ -1,4 +1,4 @@
# Watermark <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.1.16</el-tag> # Watermark
Add specified images or text on pages or components, which can be used for copyright protection, brand promotion, and other scenarios. Add specified images or text on pages or components, which can be used for copyright protection, brand promotion, and other scenarios.

View File

@ -1,4 +1,4 @@
# Internationalization<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.2.20</el-tag> # Internationalization
Wot UI uses Chinese by default and supports multi-language switching. If you want to use other languages, you can refer to the solutions below. Wot UI uses Chinese by default and supports multi-language switching. If you want to use other languages, you can refer to the solutions below.

View File

@ -1,4 +1,4 @@
# 国际化<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.2.20</el-tag> # 国际化
Wot UI 默认使用中文语言,同时支持多语言切换,如果你希望使用其他语言,你可以参考下面的方案。 Wot UI 默认使用中文语言,同时支持多语言切换,如果你希望使用其他语言,你可以参考下面的方案。