Skip to content

Commit 57d0e61

Browse files
committed
📦 Chore: from vuepress to vitepress
1 parent ae3b81b commit 57d0e61

File tree

22 files changed

+4416
-10283
lines changed

22 files changed

+4416
-10283
lines changed

.github/workflows/deploy.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Deploy Docs
2+
3+
on:
4+
push:
5+
branches: [master]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build-and-deploy:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: 20
22+
cache: yarn
23+
cache-dependency-path: yarn.lock
24+
25+
- name: Install dependencies
26+
run: yarn install --frozen-lockfile
27+
28+
- name: Build site
29+
run: yarn build
30+
31+
- name: Deploy to GitHub Pages
32+
uses: peaceiris/actions-gh-pages@v3
33+
with:
34+
github_token: ${{ secrets.GH_TOKEN }}
35+
publish_branch: gh-pages
36+
publish_dir: docs/.vitepress/dist

.github/workflows/main.yml

Lines changed: 0 additions & 53 deletions
This file was deleted.

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,8 @@ typings/
6161
.next
6262

6363
docs/.vuepress/dist
64-
.temp
64+
docs/.vitepress/dist
65+
docs/.vitepress/cache
66+
67+
.temp/
68+
.serena/

docs/.vitepress/config.mts

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { defineConfig, DefaultTheme } from 'vitepress'
2+
import { getNestedSidebarItems } from './utils/sidebar'
3+
4+
const EDIT_LINK_PATTERN = 'https://github.com/PicGo/PicGo-Core-Doc/edit/master/docs/:path'
5+
6+
const communityNavItems = [
7+
{
8+
text: 'PicGo',
9+
link: 'https://github.com/Molunerfinn/PicGo'
10+
},
11+
{
12+
text: 'Awesome-PicGo',
13+
link: 'https://github.com/PicGo/Awesome-PicGo'
14+
}
15+
]
16+
17+
const zhNav = [
18+
{
19+
text: '指南',
20+
link: '/guide/'
21+
},
22+
{
23+
text: '插件开发指南',
24+
items: [
25+
{ text: '插件开发', link: '/dev-guide/cli' },
26+
{ text: 'GUI 插件开发', link: '/dev-guide/gui' },
27+
{ text: '插件测试与发布', link: '/dev-guide/deploy' }
28+
]
29+
},
30+
{
31+
text: 'API 列表',
32+
link: '/api/'
33+
},
34+
...communityNavItems
35+
]
36+
37+
const zhGuideSidebar: DefaultTheme.SidebarItem[] = [
38+
{
39+
text: '指南',
40+
items: [
41+
{ text: '介绍', link: '/guide/', items: getNestedSidebarItems('/guide/'), collapsed: true },
42+
{ text: '快速开始', link: '/guide/getting-started', items: getNestedSidebarItems('/guide/getting-started'), collapsed: true },
43+
{ text: '配置文件', link: '/guide/config', items: getNestedSidebarItems('/guide/config'), collapsed: true },
44+
{ text: '命令列表', link: '/guide/commands', items: getNestedSidebarItems('/guide/commands'), collapsed: true },
45+
{ text: 'Node.js 使用', link: '/guide/use-in-node', items: getNestedSidebarItems('/guide/use-in-node'), collapsed: true }
46+
]
47+
}
48+
]
49+
50+
const zhDevSidebar: DefaultTheme.SidebarItem[] = [
51+
{
52+
text: '插件开发指南',
53+
items: [
54+
{ text: '插件开发', link: '/dev-guide/cli', items: getNestedSidebarItems('/dev-guide/cli'), collapsed: true },
55+
{ text: 'GUI 插件开发', link: '/dev-guide/gui', items: getNestedSidebarItems('/dev-guide/gui'), collapsed: true },
56+
{ text: '插件测试与发布', link: '/dev-guide/deploy', items: getNestedSidebarItems('/dev-guide/deploy'), collapsed: true }
57+
]
58+
}
59+
]
60+
61+
const zhApiSidebar: DefaultTheme.SidebarItem[] = [
62+
{
63+
text: 'API 列表',
64+
items: [
65+
{ text: 'API 列表', link: '/api/', items: getNestedSidebarItems('/api/'), collapsed: true }
66+
]
67+
}
68+
]
69+
70+
const zhThemeConfig = {
71+
nav: zhNav,
72+
sidebar: {
73+
'/guide/': zhGuideSidebar,
74+
'/dev-guide/': zhDevSidebar,
75+
'/api/': zhApiSidebar
76+
},
77+
editLink: {
78+
pattern: EDIT_LINK_PATTERN,
79+
text: '在 GitHub 上编辑此页'
80+
},
81+
outline: {
82+
label: '本页目录',
83+
level: 'deep'
84+
}
85+
} as const
86+
87+
export default defineConfig({
88+
title: 'PicGo-Core',
89+
description: 'PicGo 的核心组件',
90+
base: '/PicGo-Core-Doc/',
91+
head: [
92+
[
93+
'link',
94+
{
95+
rel: 'icon',
96+
href: 'https://pic.molunerfinn.com/picgo/docs/logo-150.png'
97+
}
98+
]
99+
],
100+
themeConfig: {
101+
logo: 'https://pic.molunerfinn.com/picgo/docs/picgo-logo.png',
102+
socialLinks: [
103+
{ icon: 'github', link: 'https://github.com/PicGo/PicGo-Core' }
104+
],
105+
search: {
106+
provider: 'local',
107+
options: {
108+
translations: {
109+
button: {
110+
buttonText: '搜索',
111+
buttonAriaLabel: '搜索'
112+
},
113+
modal: {
114+
displayDetails: '显示详细列表',
115+
resetButtonTitle: '重置搜索',
116+
backButtonTitle: '关闭搜索',
117+
noResultsText: '没有找到结果',
118+
footer: {
119+
selectText: '选择',
120+
selectKeyAriaLabel: '回车',
121+
navigateText: '导航',
122+
navigateUpKeyAriaLabel: '上箭头',
123+
navigateDownKeyAriaLabel: '下箭头',
124+
closeText: '关闭',
125+
closeKeyAriaLabel: 'Esc'
126+
}
127+
}
128+
}
129+
}
130+
},
131+
footer: {
132+
message: 'MIT Licensed',
133+
copyright: 'Copyright © 2018 - Now Molunerfinn'
134+
}
135+
},
136+
locales: {
137+
root: {
138+
label: '简体中文',
139+
lang: 'zh-CN',
140+
title: 'PicGo-Core',
141+
description: 'PicGo 的核心组件',
142+
link: '/',
143+
themeConfig: zhThemeConfig
144+
}
145+
}
146+
})

docs/.vitepress/theme/custom.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:root {
2+
--vp-c-brand-1: #62A0DD;
3+
--vp-button-brand-bg: var(--vp-c-brand-1);
4+
}

docs/.vitepress/theme/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import DefaultTheme from 'vitepress/theme'
2+
import './custom.css'
3+
4+
export default DefaultTheme

docs/.vitepress/utils/sidebar.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import type { DefaultTheme } from 'vitepress'
4+
5+
const ROOT_DIR = path.resolve(__dirname, '../..')
6+
const MARKDOWN_FENCE_RE = /^(~~~|```)/
7+
const HEADING_RE = /^(#{2,3})\s+(.+)$/
8+
const CUSTOM_ANCHOR_RE = /\s*{#([^}]+)}\s*$/
9+
10+
const sanitizeHeadingText = (raw: string): { text: string; slugHint?: string } => {
11+
const anchorMatch = raw.match(CUSTOM_ANCHOR_RE)
12+
const slugHint = anchorMatch?.[1]
13+
const withoutAnchor = anchorMatch ? raw.replace(CUSTOM_ANCHOR_RE, '') : raw
14+
15+
const text = withoutAnchor
16+
.replace(/!\[[^\]]*]\([^)]*\)/g, '')
17+
.replace(/\[([^\]]+)]\([^)]*\)/g, '$1')
18+
.replace(/`([^`]+)`/g, '$1')
19+
.replace(/\*\*([^*]+)\*\*/g, '$1')
20+
.replace(/\*([^*]+)\*/g, '$1')
21+
.replace(/~~([^~]+)~~/g, '$1')
22+
.replace(/<[^>]+>/g, '')
23+
.replace(/&lt;/g, '<')
24+
.replace(/&gt;/g, '>')
25+
.trim()
26+
27+
return { text, slugHint }
28+
}
29+
30+
const slugifyHeading = (text: string, slugHint?: string): string => {
31+
if (slugHint?.trim()) {
32+
return slugHint.trim()
33+
}
34+
35+
const normalized = text
36+
.trim()
37+
.toLowerCase()
38+
.replace(/[^\p{Letter}\p{Number}\u4e00-\u9fff\-\s]/gu, '')
39+
.replace(/\s+/g, '-')
40+
41+
return normalized || encodeURIComponent(text.trim()).replace(/%/g, '').toLowerCase()
42+
}
43+
44+
const buildMarkdownFilePath = (pageLink: string): string => {
45+
const normalized = pageLink.replace(/^\/+/, '')
46+
if (!normalized) {
47+
return path.join(ROOT_DIR, 'index.md')
48+
}
49+
const isEndWithSlash = normalized.endsWith('/')
50+
return isEndWithSlash
51+
? path.join(ROOT_DIR, normalized, 'index.md')
52+
: path.join(ROOT_DIR, `${normalized}.md`)
53+
}
54+
55+
const resolvePageLink = (pageLink: string): string =>
56+
pageLink.startsWith('/') ? pageLink : `/${pageLink}`
57+
58+
export const getNestedSidebarItems = (pageLink: string): DefaultTheme.SidebarItem[] => {
59+
const markdownFilePath = buildMarkdownFilePath(pageLink)
60+
61+
if (!fs.existsSync(markdownFilePath)) {
62+
console.warn(`[getNestedSidebarItems] markdown file not found: ${markdownFilePath}`)
63+
return []
64+
}
65+
66+
const fileContent = fs.readFileSync(markdownFilePath, 'utf-8')
67+
const lines = fileContent.split(/\r?\n/)
68+
69+
const items: DefaultTheme.SidebarItem[] = []
70+
let currentGroup: DefaultTheme.SidebarItem | null = null
71+
let insideFence = false
72+
73+
for (const line of lines) {
74+
const trimmed = line.trim()
75+
76+
if (MARKDOWN_FENCE_RE.test(trimmed)) {
77+
insideFence = !insideFence
78+
continue
79+
}
80+
81+
if (insideFence) continue
82+
83+
const headingMatch = trimmed.match(HEADING_RE)
84+
if (!headingMatch) continue
85+
86+
const level = headingMatch[1].length
87+
if (level !== 2 && level !== 3) continue
88+
89+
const { text, slugHint } = sanitizeHeadingText(headingMatch[2])
90+
if (!text) continue
91+
92+
const slug = slugifyHeading(text, slugHint)
93+
const link = `${resolvePageLink(pageLink)}#${slug}`
94+
95+
if (level === 2) {
96+
const groupItem: DefaultTheme.SidebarItem = {
97+
text,
98+
link,
99+
collapsed: true
100+
}
101+
currentGroup = groupItem
102+
items.push(groupItem)
103+
continue
104+
}
105+
106+
if (!currentGroup) {
107+
currentGroup = {
108+
text,
109+
link,
110+
collapsed: true,
111+
items: []
112+
}
113+
items.push(currentGroup)
114+
}
115+
116+
if (!currentGroup.items) {
117+
currentGroup.items = []
118+
}
119+
120+
currentGroup.items.push({ text, link })
121+
}
122+
123+
return items.map(item => {
124+
if (item.items && item.items.length === 0) {
125+
const { items: _empty, ...rest } = item
126+
return rest
127+
}
128+
return item
129+
})
130+
}

0 commit comments

Comments
 (0)