├── test
├── resources
│ ├── empty
│ │ └── .gitkeep
│ ├── folder-within-md
│ │ ├── README
│ │ ├── README.txt
│ │ └── not-markdown.md.txt
│ ├── numeric-prefix
│ │ ├── 1-one-file.md
│ │ ├── 2-two-file.md
│ │ ├── 1-1-1-one-file.md
│ │ ├── 1-three-file.md
│ │ ├── 1.1.1-four-file.md
│ │ └── 1-folder
│ │ │ └── 11-file.md
│ ├── recursive
│ │ ├── folderC
│ │ │ └── .gitkeep
│ │ ├── folderA
│ │ │ ├── a.md
│ │ │ └── folderAA
│ │ │ │ ├── aa.md
│ │ │ │ └── folderAAA
│ │ │ │ └── folderAAAA
│ │ │ │ └── folderAAAAA
│ │ │ │ └── aaaaa.md
│ │ └── folderB
│ │ │ └── folderBB
│ │ │ └── folderBBB
│ │ │ └── bbb.md
│ ├── same-name-path
│ │ ├── a.md
│ │ └── test
│ │ │ └── resources
│ │ │ └── same-name-path
│ │ │ └── b.md
│ ├── symlinks
│ │ ├── scan
│ │ │ ├── c
│ │ │ ├── a.md
│ │ │ └── b.md
│ │ └── not-scan
│ │ │ ├── b.md
│ │ │ └── c
│ │ │ ├── d.md
│ │ │ └── e.md
│ ├── general
│ │ ├── a.md
│ │ ├── b.md
│ │ ├── c.md
│ │ ├── folder
│ │ │ ├── subFolder
│ │ │ │ ├── empty
│ │ │ │ │ └── .gitkeep
│ │ │ │ ├── .hidden.md
│ │ │ │ ├── .dot-directory
│ │ │ │ │ └── hidden.md
│ │ │ │ └── sub-folder-test.md
│ │ │ ├── folder-test.md
│ │ │ └── folder-test-2.md
│ │ ├── test.md
│ │ ├── folder-2
│ │ │ ├── folder2.md
│ │ │ └── index.md
│ │ └── .vitepress
│ │ │ └── do-not-include.md
│ ├── sort-by-name
│ │ ├── aaa.md
│ │ ├── aab.md
│ │ ├── bdd.md
│ │ ├── ccc.md
│ │ ├── bbb.md
│ │ └── bcc.md
│ ├── capitalize
│ │ ├── 1-abc-def.md
│ │ ├── abc1def2g.md
│ │ └── 2.md
│ ├── folder-with-index
│ │ ├── index.md
│ │ ├── 1-a
│ │ │ └── index.md
│ │ ├── 10-a
│ │ │ └── index.md
│ │ └── 2-a
│ │ │ └── index.md
│ ├── .dot-directory
│ │ ├── .dot-file.md
│ │ └── normal-file.md
│ ├── index-files
│ │ ├── d
│ │ │ └── index
│ │ ├── index
│ │ │ └── b.md
│ │ ├── c
│ │ │ └── index.md
│ │ └── a
│ │ │ └── testindex.md
│ ├── format-folder
│ │ ├── folder text hello
│ │ │ └── file.md
│ │ └── folder-text_sample
│ │ │ └── file.md
│ ├── folder-with-same-name-file
│ │ ├── index.md
│ │ └── folder-name
│ │ │ ├── index.md
│ │ │ └── folder-name.md
│ ├── numeric-title
│ │ ├── 0-file.md
│ │ ├── 1-file.md
│ │ ├── 10-file.md
│ │ ├── 11-file.md
│ │ ├── 2-file.md
│ │ ├── 100-file.md
│ │ ├── 3-afile.md
│ │ └── 3-bfile.md
│ ├── folder-with-special-char-file
│ │ ├── hypen-doc.md
│ │ ├── underscore_doc.md
│ │ └── special@#$characters.md
│ ├── title-with-date-header
│ │ ├── 2024-01-01-hello
│ │ │ ├── 2024-01-02-hi.md
│ │ │ ├── 2024-01-01-hello.md
│ │ │ └── 2024-02-01-hello.md
│ │ └── 2024-02-01-test
│ │ │ ├── 2024-02-02-hi.md
│ │ │ ├── 2024-03-01-hi.md
│ │ │ └── 2024-02-01-hello.md
│ ├── number-title-and-filename
│ │ ├── 2-how-to-use.md
│ │ └── 1-introduction.md
│ ├── format-title
│ │ ├── test.md
│ │ ├── test3.md
│ │ └── test2.md
│ ├── special-markdown
│ │ └── special-markdown.md
│ ├── frontmatter-basic
│ │ ├── c.md
│ │ ├── a.md
│ │ ├── b.md
│ │ └── d.md
│ ├── frontmatter-order-with-decimal
│ │ ├── c.md
│ │ ├── d.md
│ │ ├── e.md
│ │ ├── a.md
│ │ └── b.md
│ └── frontmatter-custom-title-field
│ │ ├── b.md
│ │ └── a.md
└── specs
│ ├── multiple-sidebar.test.ts
│ └── base.test.ts
├── docs
├── ko
│ ├── guide
│ │ ├── index.md
│ │ └── getting-started.md
│ ├── advanced-usage
│ │ ├── index.md
│ │ ├── multi-level-sidebar-with-indents.md
│ │ ├── multiple-sidebars-how-to.md
│ │ └── internationalization.md
│ ├── troubleshooting
│ │ ├── index.md
│ │ └── err-require-esm.md
│ ├── introduction.md
│ └── index.md
├── en
│ ├── guide
│ │ ├── index.md
│ │ └── getting-started.md
│ ├── advanced-usage
│ │ ├── index.md
│ │ ├── multi-level-sidebar-with-indents.md
│ │ ├── multiple-sidebars-how-to.md
│ │ └── internationalization.md
│ ├── troubleshooting
│ │ ├── index.md
│ │ └── err-require-esm.md
│ ├── introduction.md
│ └── index.md
├── zhHans
│ ├── guide
│ │ ├── index.md
│ │ ├── getting-started.md
│ │ └── options.md
│ ├── advanced-usage
│ │ ├── index.md
│ │ ├── multi-level-sidebar-with-indents.md
│ │ ├── multiple-sidebars-how-to.md
│ │ └── internationalization.md
│ ├── troubleshooting
│ │ ├── index.md
│ │ └── err-require-esm.md
│ ├── introduction.md
│ └── index.md
├── public
│ ├── favicon.ico
│ ├── logo-16.png
│ ├── logo-32.png
│ ├── sidebar.png
│ ├── doc-collapsed-example.png
│ ├── doc-multi-level-docs-after.png
│ └── doc-multi-level-docs-before.png
└── .vitepress
│ ├── theme
│ ├── custom.css
│ └── index.js
│ └── config.ts
├── pnpm-workspace.yaml
├── lib
├── index.ts
├── types.ts
└── helper.ts
├── .vscode
├── extensions.json
└── settings.json
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── fix_typo.yml
│ ├── feature_request.yml
│ └── bug_report.yml
├── workflows
│ ├── pkg-pr-new.yml
│ ├── run-test.yml
│ └── publish-documentation.yml
└── pull_request_template.md
├── .prettierignore
├── tsconfig.prod.json
├── terser.config.json
├── .editorconfig
├── .prettierrc
├── .npmignore
├── tsconfig.json
├── SECURITY.md
├── .gitignore
├── LICENSE
├── eslint.config.ts
├── package.json
├── CONTRIBUTING.md
├── README.md
└── CODE_OF_CONDUCT.md
/test/resources/empty/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/folder-within-md/README:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/folder-within-md/README.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/numeric-prefix/1-one-file.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/numeric-prefix/2-two-file.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/recursive/folderC/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/same-name-path/a.md:
--------------------------------------------------------------------------------
1 | # a
2 |
--------------------------------------------------------------------------------
/test/resources/symlinks/scan/c:
--------------------------------------------------------------------------------
1 | ../not-scan/c
--------------------------------------------------------------------------------
/test/resources/general/a.md:
--------------------------------------------------------------------------------
1 | # A
2 |
3 | A
4 |
--------------------------------------------------------------------------------
/test/resources/general/b.md:
--------------------------------------------------------------------------------
1 | # B
2 |
3 | B
4 |
--------------------------------------------------------------------------------
/test/resources/general/c.md:
--------------------------------------------------------------------------------
1 | # C
2 |
3 | C
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-prefix/1-1-1-one-file.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/numeric-prefix/1-three-file.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/numeric-prefix/1.1.1-four-file.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/sort-by-name/aaa.md:
--------------------------------------------------------------------------------
1 | # AAA
2 |
--------------------------------------------------------------------------------
/test/resources/sort-by-name/aab.md:
--------------------------------------------------------------------------------
1 | # AAB
2 |
--------------------------------------------------------------------------------
/test/resources/sort-by-name/bdd.md:
--------------------------------------------------------------------------------
1 | # BDD
2 |
--------------------------------------------------------------------------------
/test/resources/sort-by-name/ccc.md:
--------------------------------------------------------------------------------
1 | # CCC
2 |
--------------------------------------------------------------------------------
/docs/ko/guide/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 가이드
3 | ---
4 |
--------------------------------------------------------------------------------
/test/resources/capitalize/1-abc-def.md:
--------------------------------------------------------------------------------
1 | empty file
2 |
--------------------------------------------------------------------------------
/test/resources/capitalize/abc1def2g.md:
--------------------------------------------------------------------------------
1 | empty file
2 |
--------------------------------------------------------------------------------
/test/resources/folder-with-index/index.md:
--------------------------------------------------------------------------------
1 | # Root
2 |
--------------------------------------------------------------------------------
/test/resources/folder-within-md/not-markdown.md.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/numeric-prefix/1-folder/11-file.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/recursive/folderA/a.md:
--------------------------------------------------------------------------------
1 | # A File
2 |
--------------------------------------------------------------------------------
/test/resources/symlinks/scan/a.md:
--------------------------------------------------------------------------------
1 | # A
2 |
3 | a
4 |
--------------------------------------------------------------------------------
/test/resources/symlinks/scan/b.md:
--------------------------------------------------------------------------------
1 | ../not-scan/b.md
--------------------------------------------------------------------------------
/docs/en/guide/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Guide
3 | ---
4 |
--------------------------------------------------------------------------------
/docs/zhHans/guide/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 指南
3 | ---
4 |
--------------------------------------------------------------------------------
/test/resources/.dot-directory/.dot-file.md:
--------------------------------------------------------------------------------
1 | # DotFile
2 |
--------------------------------------------------------------------------------
/test/resources/.dot-directory/normal-file.md:
--------------------------------------------------------------------------------
1 | # File
2 |
--------------------------------------------------------------------------------
/test/resources/capitalize/2.md:
--------------------------------------------------------------------------------
1 | # a hello world abc-def
2 |
--------------------------------------------------------------------------------
/test/resources/folder-with-index/1-a/index.md:
--------------------------------------------------------------------------------
1 | # One
2 |
--------------------------------------------------------------------------------
/test/resources/folder-with-index/10-a/index.md:
--------------------------------------------------------------------------------
1 | # Ten
2 |
--------------------------------------------------------------------------------
/test/resources/folder-with-index/2-a/index.md:
--------------------------------------------------------------------------------
1 | # Two
2 |
--------------------------------------------------------------------------------
/test/resources/general/folder/subFolder/empty/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/resources/general/test.md:
--------------------------------------------------------------------------------
1 | # TestFile
2 |
3 | AAA
4 |
--------------------------------------------------------------------------------
/test/resources/symlinks/not-scan/b.md:
--------------------------------------------------------------------------------
1 | # B
2 |
3 | B
4 |
--------------------------------------------------------------------------------
/test/resources/symlinks/not-scan/c/d.md:
--------------------------------------------------------------------------------
1 | # D
2 |
3 | D
4 |
--------------------------------------------------------------------------------
/test/resources/symlinks/not-scan/c/e.md:
--------------------------------------------------------------------------------
1 | # E
2 |
3 | E
4 |
--------------------------------------------------------------------------------
/docs/ko/advanced-usage/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 고급
3 | ---
4 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | onlyBuiltDependencies:
2 | - esbuild
3 |
--------------------------------------------------------------------------------
/test/resources/index-files/d/index:
--------------------------------------------------------------------------------
1 | # D
2 |
3 | content
4 |
--------------------------------------------------------------------------------
/test/resources/index-files/index/b.md:
--------------------------------------------------------------------------------
1 | # B
2 |
3 | content
4 |
--------------------------------------------------------------------------------
/test/resources/recursive/folderA/folderAA/aa.md:
--------------------------------------------------------------------------------
1 | # AA File
2 |
--------------------------------------------------------------------------------
/docs/ko/troubleshooting/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 문제 해결
3 | ---
4 |
--------------------------------------------------------------------------------
/docs/zhHans/advanced-usage/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 高级使用
3 | ---
4 |
--------------------------------------------------------------------------------
/docs/zhHans/troubleshooting/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 故障排除
3 | ---
4 |
--------------------------------------------------------------------------------
/test/resources/format-folder/folder text hello/file.md:
--------------------------------------------------------------------------------
1 | # Hello
2 |
--------------------------------------------------------------------------------
/test/resources/format-folder/folder-text_sample/file.md:
--------------------------------------------------------------------------------
1 | # Hello
2 |
--------------------------------------------------------------------------------
/test/resources/general/folder/subFolder/.hidden.md:
--------------------------------------------------------------------------------
1 | # HiddenFile
2 |
--------------------------------------------------------------------------------
/test/resources/index-files/c/index.md:
--------------------------------------------------------------------------------
1 | # Index
2 |
3 | content
4 |
--------------------------------------------------------------------------------
/docs/en/advanced-usage/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Advanced Usage
3 | ---
4 |
--------------------------------------------------------------------------------
/test/resources/folder-with-same-name-file/index.md:
--------------------------------------------------------------------------------
1 | # Root Index File
2 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/0-file.md:
--------------------------------------------------------------------------------
1 | # 0. Hello
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/1-file.md:
--------------------------------------------------------------------------------
1 | # 1. Hello
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/10-file.md:
--------------------------------------------------------------------------------
1 | # 10. Hello
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/11-file.md:
--------------------------------------------------------------------------------
1 | # 11. Hello
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/2-file.md:
--------------------------------------------------------------------------------
1 | # 2. Hello
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/recursive/folderB/folderBB/folderBBB/bbb.md:
--------------------------------------------------------------------------------
1 | # BBB File
2 |
--------------------------------------------------------------------------------
/test/resources/same-name-path/test/resources/same-name-path/b.md:
--------------------------------------------------------------------------------
1 | # b
2 |
--------------------------------------------------------------------------------
/docs/en/troubleshooting/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Troubleshooting
3 | ---
4 |
--------------------------------------------------------------------------------
/lib/index.ts:
--------------------------------------------------------------------------------
1 | export { withSidebar, generateSidebar } from './sidebar.js';
2 |
--------------------------------------------------------------------------------
/test/resources/folder-with-special-char-file/hypen-doc.md:
--------------------------------------------------------------------------------
1 | # Hypen Doc File
2 |
--------------------------------------------------------------------------------
/test/resources/general/folder-2/folder2.md:
--------------------------------------------------------------------------------
1 | # Folder2 File
2 |
3 | DDD
4 |
--------------------------------------------------------------------------------
/test/resources/general/folder/folder-test.md:
--------------------------------------------------------------------------------
1 | # FolderTestFile
2 |
3 | BBB
4 |
--------------------------------------------------------------------------------
/test/resources/index-files/a/testindex.md:
--------------------------------------------------------------------------------
1 | # Test Index
2 |
3 | content
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/100-file.md:
--------------------------------------------------------------------------------
1 | # 100. Hello
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/3-afile.md:
--------------------------------------------------------------------------------
1 | # 3. Hello (A)
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/numeric-title/3-bfile.md:
--------------------------------------------------------------------------------
1 | # 3. Hello (B)
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/folder-with-same-name-file/folder-name/index.md:
--------------------------------------------------------------------------------
1 | # Index File
2 |
--------------------------------------------------------------------------------
/test/resources/general/folder-2/index.md:
--------------------------------------------------------------------------------
1 | # Folder2 Index File
2 |
3 | Index
4 |
--------------------------------------------------------------------------------
/test/resources/sort-by-name/bbb.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: BBB
3 | ---
4 |
5 | # BBB
6 |
--------------------------------------------------------------------------------
/test/resources/sort-by-name/bcc.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: bcc
3 | ---
4 |
5 | # BCC
6 |
--------------------------------------------------------------------------------
/test/resources/title-with-date-header/2024-01-01-hello/2024-01-02-hi.md:
--------------------------------------------------------------------------------
1 | # File
2 |
--------------------------------------------------------------------------------
/test/resources/title-with-date-header/2024-02-01-test/2024-02-02-hi.md:
--------------------------------------------------------------------------------
1 | # File
2 |
--------------------------------------------------------------------------------
/test/resources/title-with-date-header/2024-02-01-test/2024-03-01-hi.md:
--------------------------------------------------------------------------------
1 | # File
2 |
--------------------------------------------------------------------------------
/test/resources/folder-with-special-char-file/underscore_doc.md:
--------------------------------------------------------------------------------
1 | # Underscore Doc File
2 |
--------------------------------------------------------------------------------
/test/resources/general/folder/folder-test-2.md:
--------------------------------------------------------------------------------
1 | ## FolderTestFile 2
2 |
3 | BBBBBB
4 |
--------------------------------------------------------------------------------
/test/resources/general/folder/subFolder/.dot-directory/hidden.md:
--------------------------------------------------------------------------------
1 | # HiddenDirectory
2 |
--------------------------------------------------------------------------------
/test/resources/title-with-date-header/2024-01-01-hello/2024-01-01-hello.md:
--------------------------------------------------------------------------------
1 | # File
2 |
--------------------------------------------------------------------------------
/test/resources/title-with-date-header/2024-01-01-hello/2024-02-01-hello.md:
--------------------------------------------------------------------------------
1 | # File
2 |
--------------------------------------------------------------------------------
/test/resources/title-with-date-header/2024-02-01-test/2024-02-01-hello.md:
--------------------------------------------------------------------------------
1 | # File
2 |
--------------------------------------------------------------------------------
/test/resources/number-title-and-filename/2-how-to-use.md:
--------------------------------------------------------------------------------
1 | # 2. How-to-use
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/folder-with-special-char-file/special@#$characters.md:
--------------------------------------------------------------------------------
1 | # Special Characters File
2 |
--------------------------------------------------------------------------------
/test/resources/format-title/test.md:
--------------------------------------------------------------------------------
1 | # html-format-title[link-title](https://github.com)
2 |
--------------------------------------------------------------------------------
/test/resources/general/folder/subFolder/sub-folder-test.md:
--------------------------------------------------------------------------------
1 | # SubFolderTestFile
2 |
3 | CCC
4 |
--------------------------------------------------------------------------------
/test/resources/number-title-and-filename/1-introduction.md:
--------------------------------------------------------------------------------
1 | # 1. Introduction
2 |
3 | Content
4 |
--------------------------------------------------------------------------------
/test/resources/special-markdown/special-markdown.md:
--------------------------------------------------------------------------------
1 | # **[Test](https://github.com)** ~~Page~~
2 |
--------------------------------------------------------------------------------
/test/resources/general/.vitepress/do-not-include.md:
--------------------------------------------------------------------------------
1 | # Do not include this file
2 |
3 | content
4 |
--------------------------------------------------------------------------------
/test/resources/recursive/folderA/folderAA/folderAAA/folderAAAA/folderAAAAA/aaaaa.md:
--------------------------------------------------------------------------------
1 | # AAAAA File
2 |
--------------------------------------------------------------------------------
/docs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jooy2/vitepress-sidebar/HEAD/docs/public/favicon.ico
--------------------------------------------------------------------------------
/docs/public/logo-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jooy2/vitepress-sidebar/HEAD/docs/public/logo-16.png
--------------------------------------------------------------------------------
/docs/public/logo-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jooy2/vitepress-sidebar/HEAD/docs/public/logo-32.png
--------------------------------------------------------------------------------
/docs/public/sidebar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jooy2/vitepress-sidebar/HEAD/docs/public/sidebar.png
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
3 | }
4 |
--------------------------------------------------------------------------------
/test/resources/folder-with-same-name-file/folder-name/folder-name.md:
--------------------------------------------------------------------------------
1 | # Folder Text
2 |
3 | Folder Content
4 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/custom.css:
--------------------------------------------------------------------------------
1 | /* .vitepress/theme/custom.css */
2 | :root {
3 | --vp-sidebar-width: 350px;
4 | }
5 |
--------------------------------------------------------------------------------
/test/resources/format-title/test3.md:
--------------------------------------------------------------------------------
1 | #
abc-def_g
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: jooy2
4 | custom: ['https://cdget.com/donate']
5 |
--------------------------------------------------------------------------------
/docs/public/doc-collapsed-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jooy2/vitepress-sidebar/HEAD/docs/public/doc-collapsed-example.png
--------------------------------------------------------------------------------
/test/resources/format-title/test2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: ~~hello-world_1~~ hello-world_2 hello-world_4
3 | ---
4 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.js:
--------------------------------------------------------------------------------
1 | import DefaultTheme from 'vitepress/theme';
2 | import './custom.css';
3 |
4 | export default DefaultTheme;
5 |
--------------------------------------------------------------------------------
/docs/public/doc-multi-level-docs-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jooy2/vitepress-sidebar/HEAD/docs/public/doc-multi-level-docs-after.png
--------------------------------------------------------------------------------
/docs/public/doc-multi-level-docs-before.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jooy2/vitepress-sidebar/HEAD/docs/public/doc-multi-level-docs-before.png
--------------------------------------------------------------------------------
/test/resources/frontmatter-basic/c.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: C Frontmatter
3 | order: 3
4 | date: 2023-02-15
5 | author: cdget.com
6 | ---
7 |
8 | # C File
9 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist/
2 | docs-dist/
3 | .idea/
4 | .vscode/
5 | docs/.vitepress/cache
6 | node_modules/
7 |
8 | *-lock.json
9 | *-lock.yaml
10 |
--------------------------------------------------------------------------------
/tsconfig.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["test/**/*.test.ts", "docs-dist/*", "docs/.vitepress/*", "eslint.config.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-order-with-decimal/c.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: C Frontmatter
3 | order: 2
4 | date: 2023-02-15
5 | author: cdget.com
6 | ---
7 |
8 | # C File
9 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-basic/a.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: A Frontmatter
3 | order: 10
4 | date: 2023-01-05
5 | author: cdget.com
6 | exclude: true
7 | ---
8 |
9 | # A File
10 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-basic/b.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: B Frontmatter
3 | order: 2
4 | date: 2023-01-01
5 | author: cdget.com
6 | exclude: false
7 | ---
8 |
9 | # B File
10 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-basic/d.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: D Frontmatter
3 | order: 1
4 | date: 2024-01-01
5 | author: cdget.com
6 | exclude: true
7 | ---
8 |
9 | # D File
10 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-order-with-decimal/d.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: D Frontmatter
3 | order: 1
4 | date: 2024-01-01
5 | author: cdget.com
6 | exclude: true
7 | ---
8 |
9 | # D File
10 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-order-with-decimal/e.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: D Frontmatter
3 | order: 3
4 | date: 2024-01-01
5 | author: cdget.com
6 | exclude: true
7 | ---
8 |
9 | # D File
10 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-custom-title-field/b.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: B Frontmatter
3 | order: 1
4 | date: 2024-07-05
5 | author: liudonghua
6 | exclude: true
7 | ---
8 |
9 | # A File
10 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-order-with-decimal/a.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: A Frontmatter
3 | order: 2.2
4 | date: 2023-01-05
5 | author: cdget.com
6 | exclude: true
7 | ---
8 |
9 | # A File
10 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-order-with-decimal/b.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: B Frontmatter
3 | order: 2.3
4 | date: 2023-01-01
5 | author: cdget.com
6 | exclude: false
7 | ---
8 |
9 | # B File
10 |
--------------------------------------------------------------------------------
/terser.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "module": true,
3 | "compress": true,
4 | "ie8": false,
5 | "safari10": false,
6 | "mangle": {},
7 | "output": {},
8 | "parse": {},
9 | "rename": {}
10 | }
11 |
--------------------------------------------------------------------------------
/test/resources/frontmatter-custom-title-field/a.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: A Frontmatter
3 | sidebar_title: A Frontmatter Customized
4 | order: 1
5 | date: 2024-07-05
6 | author: liudonghua
7 | exclude: true
8 | ---
9 |
10 | # A File
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | end_of_line = lf
7 | indent_style = space
8 | indent_size = 2
9 | insert_final_newline = true
10 | max_line_length = 100
11 | trim_trailing_whitespace = true
12 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "quoteProps": "as-needed",
4 | "trailingComma": "none",
5 | "bracketSpacing": true,
6 | "bracketSameLine": false,
7 | "arrowParens": "always",
8 | "insertPragma": false,
9 | "requirePragma": false,
10 | "proseWrap": "never",
11 | "htmlWhitespaceSensitivity": "strict",
12 | "endOfLine": "lf"
13 | }
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | #contact_links:
3 | # - name: GitHub Community Support
4 | # url: https://github.com/orgs/community/discussions
5 | # about: Please ask and answer questions here.
6 | # - name: GitHub Security Bug Bounty
7 | # url: https://bounty.github.com/
8 | # about: Please report security vulnerabilities here.
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # System files
2 | .DS_Store
3 | Thumbs.db
4 | *.log
5 |
6 | # IDEs
7 | .idea/
8 | .vscode/
9 |
10 | # Project files
11 | lib/
12 | test/
13 | docs/
14 | docs-dist/
15 | CHANGELOG.md
16 | CODE_OF_CONDUCT.md
17 | SECURITY.md
18 | CONTRIBUTING.md
19 |
20 | # For development
21 | .git*
22 | .eslintignore
23 | eslint.config.ts
24 | .prettierignore
25 | .prettierrc
26 | .editorconfig
27 | terser.config.json
28 | tsconfig.json
29 | tsconfig.prod.json
30 |
--------------------------------------------------------------------------------
/.github/workflows/pkg-pr-new.yml:
--------------------------------------------------------------------------------
1 | name: Publish any commit to pkg.pr.new
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - name: Checkout code
9 | uses: actions/checkout@v4
10 | - run: |
11 | corepack enable pnpm
12 | corepack use pnpm@latest
13 | - uses: actions/setup-node@v4
14 | with:
15 | node-version: 24
16 | cache: 'pnpm'
17 | - name: Install dependencies
18 | run: pnpm install
19 | - name: Build
20 | run: pnpm build
21 | - run: pnpm dlx pkg-pr-new publish
22 |
--------------------------------------------------------------------------------
/docs/zhHans/introduction.md:
--------------------------------------------------------------------------------
1 | # 导言
2 |
3 | **VitePress Sidebar**是 **[VitePress](https://vitepress.dev/zh/)** 的一个插件,可通过简单的设置自动配置和管理页面的侧边栏。
4 |
5 | - ⚡️ 针对最新版**VitePress**进行了优化
6 | - ⚡️ 易于使用,有很多选项可根据自己的喜好进行定制
7 | - ⚡️ 轻量级捆绑文件大小
8 | - ⚡️ 支持 [多个侧边栏](https://vitepress.dev/zh/reference/default-theme-sidebar#multiple-sidebars)
9 | - ⚡️ 支持[Frontmatter](https://vitepress.dev/zh/guide/frontmatter)
10 | - ⚡️ 支持[TypeScript](https://www.typescriptlang.org/zh/)
11 | - ⚡️ 自定义分类、特殊字符转换、文件和文件夹过滤器等菜单!
12 |
13 | ## 实际用途
14 |
15 | **VitePress侧边栏**用于各种项目环境,包括我自己的网络服务。
16 |
17 | - 探索使用的包: https://github.com/jooy2/vitepress-sidebar/network/dependents
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "lib",
4 | "target": "esnext",
5 | "module": "Preserve",
6 | "moduleDetection": "force",
7 | "lib": ["esnext"],
8 | "esModuleInterop": true,
9 | "isolatedModules": true,
10 | "resolveJsonModule": true,
11 | "allowJs": true,
12 | "allowSyntheticDefaultImports": true,
13 | "skipLibCheck": true,
14 | "declaration": true,
15 | "outDir": "./dist",
16 | "strict": true,
17 | "newLine": "lf"
18 | },
19 | "include": [
20 | "lib/**/*.ts",
21 | "lib/**/*.d.ts",
22 | "test/**/*.test.ts",
23 | "docs/.vitepress/config.ts",
24 | "eslint.config.ts"
25 | ],
26 | "exclude": ["node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/docs/ko/introduction.md:
--------------------------------------------------------------------------------
1 | # 소개
2 |
3 | **VitePress Sidebar**는 번거로운 작업 없이 한번의 설정만으로 사이드바 메뉴를 자동으로 생성하는 **[VitePress](https://vitepress.dev/ko/)** 플러그인입니다. 수많은 문서에 대한 분류를 손쉽게 만들어 시간을 절약하세요.
4 |
5 | - ⚡️ 최신 버전의 **VitePress**을 지원합니다.
6 | - ⚡️ 간편하게 사용하고, 원하는 대로 사용자 지정할 수 있습니다.
7 | - ⚡️ 가벼운 번들 파일 크기
8 | - ⚡️ [다중 사이드바](https://vitepress.dev/ko/reference/default-theme-sidebar#multiple-sidebars) 지원
9 | - ⚡️ [Frontmatter](https://vitepress.dev/ko/guide/frontmatter) 지원
10 | - ⚡️ [TypeScript](https://www.typescriptlang.org) 지원
11 | - ⚡️ 정렬, 특수 문자 변환, 파일 및 폴더 필터 등을 위한 메뉴를 사용자 지정하세요!
12 |
13 | ## 어디에서 사용되나요?
14 |
15 | **VitePress Sidebar**는 다양한 프로젝트 환경에서 활용되고 있습니다.
16 |
17 | - GitHub 프로젝트에서 현재 활용 중인 패키지를 살펴보세요: https://github.com/jooy2/vitepress-sidebar/network/dependents
18 |
--------------------------------------------------------------------------------
/docs/zhHans/troubleshooting/err-require-esm.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'CommonJS: ERR_REQUIRE_ESM'
3 | ---
4 |
5 | # `CommonJS: ERR_REQUIRE_ESM`
6 |
7 | `vitepress-sidebar`是一个**ESM**模块。如果您的项目使用**CJS**,则需要将其转换为**ESM**模块。
8 |
9 | 如需了解**ESM**模块的更多信息,请参阅以下内容:https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
10 |
11 | 为解决这些问题,有以下几种解决方案:
12 |
13 | ### 解决方案 A
14 |
15 | 如果您想在 CJS 项目中使用该模块,请将文件扩展名从`.js` 改为 `.mjs`,然后再试一次。您可以为特定文件定义模块脚本。
16 |
17 | ### 解决方案 B
18 |
19 | 在`package.json`文件中,添加`"type":"module"`行。这可能需要将项目转换为 ESM 项目。
20 |
21 | ```json5
22 | {
23 | name: 'docs',
24 | type: 'module', // <-- 添加此内容
25 | version: '1.0.0',
26 | scripts: {
27 | dev: 'vitepress dev src',
28 | build: 'vitepress build src',
29 | serve: 'vitepress serve src'
30 | }
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "workbench.settings.useSplitJSON": true,
3 | "eslint.format.enable": true,
4 | "eslint.lintTask.enable": false,
5 | "eslint.codeActionsOnSave.rules": null,
6 | "editor.codeActionsOnSave": {
7 | "source.fixAll.eslint": "explicit"
8 | },
9 | "eslint.validate": ["javascript"],
10 | "files.autoSave": "afterDelay",
11 | "editor.formatOnSave": true,
12 | "editor.wordWrap": "on",
13 | "editor.defaultFormatter": "esbenp.prettier-vscode",
14 | "[javascript]": {
15 | "editor.defaultFormatter": "esbenp.prettier-vscode"
16 | },
17 | "editor.tabSize": 2,
18 | "prettier.embeddedLanguageFormatting": "off",
19 | "prettier.enable": true,
20 | "files.associations": {
21 | "*.mjs": "javascript",
22 | "*.cjs": "javascript",
23 | "*.mts": "typescript"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/fix_typo.yml:
--------------------------------------------------------------------------------
1 | name: 'Fix typo request'
2 | description: Request to fix a typo or bad translation in this project
3 | labels: ['typo']
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Before creating an issue, please read the following:
9 |
10 | - Search to see if the same issue already exists, and keep the title concise and accurate so that it's easy for others to understand and search for.
11 | - Please create a separate issue for each type of issue.
12 | - Please be as detailed as possible and write in English so that we can handle your issue quickly.
13 | - type: textarea
14 | attributes:
15 | label: Describe the issue
16 | description: Please describe where the typo occurs and a list of text that needs to be corrected.
17 | validations:
18 | required: true
19 |
--------------------------------------------------------------------------------
/docs/ko/troubleshooting/err-require-esm.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'CommonJS: ERR_REQUIRE_ESM'
3 | ---
4 |
5 | # `CommonJS: ERR_REQUIRE_ESM`
6 |
7 | `vitepress-sidebar`는 **ESM** 모듈입니다. 프로젝트에서 **CJS**를 사용하는 경우 **ESM** 모듈로 변환해야 합니다.
8 |
9 | **ESM** 모듈에 대한 자세한 내용은 아래를 참조하세요: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
10 |
11 | 이러한 문제를 해결하기 위한 몇 가지 해결책이 아래에 나와 있습니다:
12 |
13 | ### 해결책 A
14 |
15 | CJS 프로젝트에 사용하려는 경우 파일 확장자를 `.js`에서 `.mjs`로 변경한 후 다시 시도하세요. 특정 파일에 모듈 스크립트를 사용하도록 정의할 수 있습니다.
16 |
17 | ### 해결책 B
18 |
19 | `package.json` 파일에 `"type": "module"` 줄을 추가합니다. 이 경우 프로젝트를 ESM 프로젝트로 변환해야 할 수도 있습니다.
20 |
21 | ```json5
22 | {
23 | name: 'docs',
24 | type: 'module', // <-- 이 부분을 추가하세요.
25 | version: '1.0.0',
26 | scripts: {
27 | dev: 'vitepress dev src',
28 | build: 'vitepress build src',
29 | serve: 'vitepress serve src'
30 | }
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Reporting Security Issues
4 |
5 | To report a security vulnerability, create an issue on GitHub on the "Open a draft security advisory " page on GitHub: https://github.com/jooy2/vitepress-sidebar/security/advisories/new
6 |
7 | Also, send private instructions in advance via maintainer email. Do not submit vulnerability-related content as a general issue.
8 |
9 | ## Security compliance
10 |
11 | Project maintainers are quickly addressing reported security vulnerabilities in the project and providing relevant patches.
12 |
13 | We report these to the relevant users and handle the correspondence to prevent the issue from recurring.
14 |
15 | ## Security recommendations
16 |
17 | We recommend that users of project sources use the latest version, which addresses possible security vulnerabilities.
18 |
19 | ## Contact
20 |
21 | - Administrator: jooy2.contact@gmail.com
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: 'Feature request'
2 | description: Report a feature request in this project.
3 | labels: ['enhancement']
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Before creating an issue, please read the following:
9 |
10 | - Search to see if the same issue already exists, and keep the title concise and accurate so that it's easy for others to understand and search for.
11 | - Please create a separate issue for each type of issue.
12 | - Please be as detailed as possible and write in English so that we can handle your issue quickly.
13 | - type: textarea
14 | attributes:
15 | label: Describe the feature
16 | description: Feel free to describe any features or improvements you would like to see. You can attach text or images of examples, behavior, etc. from other projects to elaborate.
17 | validations:
18 | required: true
19 |
--------------------------------------------------------------------------------
/docs/en/introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | **VitePress Sidebar** is a plugin for **[VitePress](https://vitepress.dev)** that automatically configures and manages the sidebar of your page with simple settings.
4 |
5 | - ⚡️ Optimized for the latest version of **VitePress**
6 | - ⚡️ Easy to use, lots of options to customize to your liking
7 | - ⚡️ Lightweight bundle file size, zero dependencies
8 | - ⚡️ [Multiple Sidebars](https://vitepress.dev/reference/default-theme-sidebar#multiple-sidebars) support
9 | - ⚡️ [Frontmatter](https://vitepress.dev/guide/frontmatter) support
10 | - ⚡️ [TypeScript](https://www.typescriptlang.org) support
11 | - ⚡️ Customize menus for sorting, special character conversion, file and folder filters, and more!
12 |
13 | ## Real-world Uses
14 |
15 | **VitePress Sidebar** is utilized in a variety of project environments, including my own web services.
16 |
17 | - To explore packages used other than: https://github.com/jooy2/vitepress-sidebar/network/dependents
18 |
--------------------------------------------------------------------------------
/docs/en/troubleshooting/err-require-esm.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'CommonJS: ERR_REQUIRE_ESM'
3 | ---
4 |
5 | # `CommonJS: ERR_REQUIRE_ESM`
6 |
7 | `vitepress-sidebar` is an **ESM** module. If your project is using **CJS**, you will need to convert it to an **ESM** module.
8 |
9 | For more information about the **ESM** module, see below: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
10 |
11 | To address these issues, there are several solutions below:
12 |
13 | ### Solution A
14 |
15 | If you are trying to use it with a CJS project, change the file extension from `.js` to `.mjs` and try again. You can define that you want to use the module script for a specific file.
16 |
17 | ### Solution B
18 |
19 | in the `package.json` file, add the line `"type": "module"` line. This may require the project to be converted to an ESM project.
20 |
21 | ```json5
22 | {
23 | name: 'docs',
24 | type: 'module', // <-- Add this
25 | version: '1.0.0',
26 | scripts: {
27 | dev: 'vitepress dev src',
28 | build: 'vitepress build src',
29 | serve: 'vitepress serve src'
30 | }
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # .gitignore for NodeJS Projects
2 | # ---------- Start of common ignore files
3 |
4 | # Node artifact files
5 | node_modules/
6 |
7 | # Log files
8 | *.log
9 |
10 | # dotenv environment variables file
11 | .env
12 |
13 | # JetBrains IDEs
14 | .idea/
15 | *.iml
16 |
17 | # Visual Studio Code IDE
18 | .vscode/*
19 | !.vscode/settings.json
20 | !.vscode/tasks.json
21 | !.vscode/launch.json
22 | !.vscode/extensions.json
23 | !.vscode/*.code-snippets
24 |
25 | # Local History for Visual Studio Code
26 | .history/
27 |
28 | # Built Visual Studio Code Extensions
29 | *.vsix
30 |
31 | # Generated by MacOS
32 | .DS_Store
33 | .AppleDouble
34 | .LSOverride
35 |
36 | # Generated by Windows
37 | Thumbs.db
38 | [Dd]esktop.ini
39 | $RECYCLE.BIN/
40 |
41 | # Applications
42 | *.app
43 | *.pkg
44 | *.dmg
45 | *.exe
46 | *.war
47 | *.deb
48 |
49 | # Large media files
50 | *.mp4
51 | *.tiff
52 | *.avi
53 | *.flv
54 | *.mov
55 | *.wmv
56 |
57 | # ---------- End of common ignore files
58 |
59 | # Project files
60 | dist/
61 | docs-dist/
62 |
63 | # VitePress files
64 | docs/.vitepress/.temp
65 | docs/.vitepress/.temp/*
66 | docs/.vitepress/cache
67 | docs/.vitepress/cache/*
68 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022-2025 CDGet (https://cdget.com).
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/.github/workflows/run-test.yml:
--------------------------------------------------------------------------------
1 | name: run-test
2 |
3 | on:
4 | pull_request:
5 | branches: [main]
6 | push:
7 | paths:
8 | - '**'
9 | - '!LICENSE'
10 | - '!*.md'
11 | - '!.github/**'
12 | - '!.vscode/**'
13 | - '!docs/**'
14 | - '.github/workflows/run-test.yml'
15 | # trigger deployment manually
16 | workflow_dispatch:
17 |
18 | jobs:
19 | build-and-run-test:
20 | runs-on: ${{ matrix.os }}
21 | name: Test module from Node.js ${{ matrix.node_version }} on ${{ matrix.os }}
22 | strategy:
23 | fail-fast: false
24 | matrix:
25 | node_version: ['20', '22', '24']
26 | os: [ubuntu-latest, windows-latest, macos-latest]
27 |
28 | steps:
29 | - uses: actions/checkout@v4
30 | name: Setup Node.js ${{ matrix.node_version }}
31 | with:
32 | # fetch all commits to get last updated time or other git log info
33 | fetch-depth: 0
34 | - uses: actions/setup-node@v4
35 | with:
36 | node-version: ${{ matrix.node_version }}
37 | cache: npm
38 | cache-dependency-path: '**/package-lock.json'
39 | - run: npm ci && npm run test
40 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
6 |
7 | ## Pull request checklist
8 |
9 | You should familiarize yourself with the files `README.md`, `CONTRIBUTING.md`, and `CODE_OF_CONDUCT.md` in the root of your project.
10 |
11 | - If an issue has been created for this, add `(fixes #{ISSUE_NUMBER})` to the end of the commit description. In `{ISSUE_NUMBER}`, please include the relevant issue number.
12 | - If you need to update or add to the article, please update the relevant content. If a multilingual article exists, you should update all relevant content in your own language, except for translations.
13 | - Add or update test code if it exists and is needed. Also, verify that the tests pass.
14 | - If this PR is not yet complete, keep the PR in draft status. If it's no longer valid, close the PR with an explanation.
15 |
16 |
19 |
20 | ### What did you change?
21 |
22 | ### Why did you make the change?
23 |
24 | ### How does this work?
25 |
--------------------------------------------------------------------------------
/docs/zhHans/advanced-usage/multi-level-sidebar-with-indents.md:
--------------------------------------------------------------------------------
1 | # 带缩进的多级侧边栏
2 |
3 | 在多层侧边栏中,菜单显示时每层都会缩进。不过,VitePress 默认从第二层开始缩进。例如
4 |
5 | 
6 |
7 | 上面,`directory-level-2`是`directory-level-1`的子文件,但看起来处于相同的层级。
8 |
9 | 这不是VitePress侧边栏的问题,要解决这个问题,您需要通过**[VitePress的自定义CSS](https://vitepress.dev/zh/guide/extending-default-theme#customizing-css)**自定义现有主题的样式。
10 |
11 | 在`.vitepress`目录下创建一个`theme`目录,以覆盖现有样式所需的样式。然后在`theme`目录下创建一个`index.js`文件(如果您使用的是Typescript,请使用`index.ts`而不是`index.js`)和一个`custom.css`文件。
12 |
13 | ```text
14 | /
15 | ├─ package.json
16 | ├─ src/
17 | ├─ docs/
18 | │ ├─ .vitepress/
19 | │ │ └─ theme/ <------------ Add this
20 | │ │ ├─ custom.css <------------ Add this
21 | │ │ └─ index.js <------------ Add this
22 | │ ├─ example.md
23 | │ └─ index.md
24 | └─ ...
25 | ```
26 |
27 | 然后在 `index.js` 文件中添加以下内容:
28 |
29 | ```javascript
30 | import DefaultTheme from 'vitepress/theme';
31 | import './custom.css';
32 |
33 | export default DefaultTheme;
34 | ```
35 |
36 | 接下来,在 `custom.css` 文件中添加以下内容:
37 |
38 | ```css
39 | .group:has([role='button']) .VPSidebarItem.level-0 .items {
40 | padding-left: 16px !important;
41 | border-left: 1px solid var(--vp-c-divider);
42 | border-radius: 2px;
43 | transition: background-color 0.25s;
44 | }
45 | ```
46 |
47 | 现在启动 VitePress 服务器。这样就能更容易地看到子内容所在组的第一级层次结构。
48 |
49 | 
50 |
51 | 需要注意的是,这里看到的垂直分隔线只是用CSS创建的;它应该创建为一个带有CSS类名为`indicator`的`div`,所以你应该知道,当你以后创建动态页面时,垂直分隔线可能不会被选中。
52 |
--------------------------------------------------------------------------------
/eslint.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, globalIgnores } from 'eslint/config';
2 | import pluginJs from '@eslint/js';
3 | import pluginTypeScriptESLint from 'typescript-eslint';
4 | import parserTypeScript from '@typescript-eslint/parser';
5 | import pluginNode from 'eslint-plugin-n';
6 | import configPrettier from 'eslint-config-prettier';
7 |
8 | import globals from 'globals';
9 |
10 | export default defineConfig(
11 | pluginJs.configs.recommended,
12 | pluginTypeScriptESLint.configs.recommended,
13 | pluginNode.configs['flat/recommended-script'],
14 | globalIgnores([
15 | '**/.idea',
16 | '**/.vscode',
17 | '**/node_modules',
18 | '**/dist',
19 | '**/docs/.vitepress/cache',
20 | '**/docs-dist',
21 | '**/*-lock.json',
22 | '**/*-lock.yaml'
23 | ]),
24 | {
25 | files: ['**/*.{js,mjs,cjs,ts}'],
26 | languageOptions: {
27 | ecmaVersion: 'latest',
28 | sourceType: 'module',
29 | globals: {
30 | ...globals.node
31 | },
32 | parserOptions: {
33 | parser: parserTypeScript,
34 | ecmaVersion: 2022,
35 | requireConfigFile: false
36 | }
37 | },
38 | rules: {
39 | eqeqeq: 'error',
40 | 'no-unused-vars': 'off',
41 | 'no-case-declarations': 'off',
42 | 'no-trailing-spaces': 'error',
43 | 'no-unsafe-optional-chaining': 'off',
44 | 'no-control-regex': 'off',
45 | 'n/no-missing-import': 'off',
46 | 'n/no-unpublished-import': 'off',
47 | 'n/no-unsupported-features/node-builtins': 'off',
48 | '@typescript-eslint/no-explicit-any': 'off'
49 | }
50 | },
51 | configPrettier
52 | );
53 |
--------------------------------------------------------------------------------
/docs/ko/advanced-usage/multi-level-sidebar-with-indents.md:
--------------------------------------------------------------------------------
1 | # 다중 레벨 사이드바의 들여쓰기
2 |
3 | 다중 사이드바에서는 메뉴가 각 계층마다 들여쓰기로 표시됩니다. 그러나 VitePress는 기본적으로 두 번째 계층부터 들여쓰기를 시작합니다. 예를 들어:
4 |
5 | 
6 |
7 | 위의 `directory-level-2`는 `directory-level-1`의 하위 파일이지만 같은 계층 구조에 있는 것으로 보입니다.
8 |
9 | 이 문제는 VitePress 사이드바의 문제가 아니므로 이 문제를 해결하려면 **[VitePress의 사용자 정의 CSS](https://vitepress.dev/ko/guide/extending-default-theme#customizing-css)** 기능을 사용하여 기존 테마의 스타일을 사용자 정의해야 합니다.
10 |
11 | `.vitepress` 디렉토리에 `theme` 디렉토리를 만들어 기존 스타일에 필요한 스타일을 재정의합니다. 그런 다음 `theme` 디렉토리 안에 `index.js` 파일(타입스크립트를 사용하는 경우 `index.js` 대신 `index.ts`를 사용)과 `custom.css` 파일을 만듭니다.
12 |
13 | ```text
14 | /
15 | ├─ package.json
16 | ├─ src/
17 | ├─ docs/
18 | │ ├─ .vitepress/
19 | │ │ └─ theme/ <------------ 이 줄 추가
20 | │ │ ├─ custom.css <------------ 이 줄 추가
21 | │ │ └─ index.js <------------ 이 줄 추가
22 | │ ├─ example.md
23 | │ └─ index.md
24 | └─ ...
25 | ```
26 |
27 | 그런 다음 `index.js` 파일에 다음을 추가합니다:
28 |
29 | ```javascript
30 | import DefaultTheme from 'vitepress/theme';
31 | import './custom.css';
32 |
33 | export default DefaultTheme;
34 | ```
35 |
36 | 다음으로 `custom.css` 파일에 다음을 추가합니다:
37 |
38 | ```css
39 | .group:has([role='button']) .VPSidebarItem.level-0 .items {
40 | padding-left: 16px !important;
41 | border-left: 1px solid var(--vp-c-divider);
42 | border-radius: 2px;
43 | transition: background-color 0.25s;
44 | }
45 | ```
46 |
47 | 이제 VitePress 서버를 시작합니다. 이렇게 하면 하위 콘텐츠가 존재하는 그룹의 첫 번째 레벨의 계층 구조를 더 쉽게 확인할 수 있습니다.
48 |
49 | 
50 |
51 | 여기에서 보이는 세로선은 CSS로만 생성된 것으로, `indicator`라는 CSS 클래스가 있는 `div`로 생성되어야 하므로 향후 동적 페이지를 작성할 때 세로선이 선택되지 않을 수 있다는 점에 유의해야 합니다.
52 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: 'Bug report'
2 | description: Report a bug in this project.
3 | labels: ['bug']
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Before creating an issue, please read the following:
9 |
10 | - Read the `README.md` file on the project page or the documentation file and compare your code to the intent of the project.
11 | - Search to see if the same issue already exists, and keep the title concise and accurate so that it's easy for others to understand and search for.
12 | - Please create a separate issue for each type of issue.
13 | - For modular projects, make sure you're using the latest version of the module.
14 | - Please be as detailed as possible and write in English so that we can handle your issue quickly.
15 | - type: textarea
16 | attributes:
17 | label: Describe the bug
18 | description: |
19 | For the issue you are experiencing, please describe in detail what you are seeing, the error message, and the impact of the issue. If you are able to reproduce the issue, please list the steps in order. You can attach an image or video if necessary.
20 | validations:
21 | required: true
22 | - type: textarea
23 | attributes:
24 | label: Expected behavior
25 | description: Describe how it should be handled when it's normal behavior or what needs to be fixed.
26 | validations:
27 | - type: input
28 | attributes:
29 | label: Your environment - System OS
30 | description: Please describe the full range of OSes you are experiencing the issue with, preferably including the version.
31 | placeholder: Windows 11, macOS 15.x, Linux Ubuntu 24.04, Android 15, iOS 16...
32 | validations:
33 | - type: input
34 | attributes:
35 | label: Your environment - Web Browser
36 | description: If relevant, please describe the web browser you are currently using.
37 | placeholder: Google Chrome, Microsoft Edge, Mozilla Firefox...
38 | validations:
39 |
--------------------------------------------------------------------------------
/docs/en/advanced-usage/multi-level-sidebar-with-indents.md:
--------------------------------------------------------------------------------
1 | # Multi-level-sidebar with indents
2 |
3 | In a multi-level sidebar, the menu is displayed with indentation for each tier. However, VitePress starts indenting from the second tier by default. For example:
4 |
5 | 
6 |
7 | Above, `directory-level-2` is a subfile of `directory-level-1`, but it appears to be in the same hierarchy.
8 |
9 | This is not an issue with VitePress Sidebar, so to fix it, you'll need to customize the styling of your existing theme via **[VitePress' Custom CSS](https://vitepress.dev/guide/extending-default-theme#customizing-css)**.
10 |
11 | Create a `theme` directory in the `.vitepress` directory to override the styles required by the existing styles. Then, inside the `theme` directory, create an `index.js` file (If you're using Typescript, use `index.ts` instead of `index.js`) and a `custom.css` file.
12 |
13 | ```text
14 | /
15 | ├─ package.json
16 | ├─ src/
17 | ├─ docs/
18 | │ ├─ .vitepress/
19 | │ │ └─ theme/ <------------ Add this
20 | │ │ ├─ custom.css <------------ Add this
21 | │ │ └─ index.js <------------ Add this
22 | │ ├─ example.md
23 | │ └─ index.md
24 | └─ ...
25 | ```
26 |
27 | Then add the following to the `index.js` file:
28 |
29 | ```javascript
30 | import DefaultTheme from 'vitepress/theme';
31 | import './custom.css';
32 |
33 | export default DefaultTheme;
34 | ```
35 |
36 | Next, add the following to the `custom.css` file:
37 |
38 | ```css
39 | .group:has([role='button']) .VPSidebarItem.level-0 .items {
40 | padding-left: 16px !important;
41 | border-left: 1px solid var(--vp-c-divider);
42 | border-radius: 2px;
43 | transition: background-color 0.25s;
44 | }
45 | ```
46 |
47 | Now start the VitePress server. This will make it easier to see the hierarchy of the first level of the group where the child content exists.
48 |
49 | 
50 |
51 | It's important to note that the vertical divider you see here was only created with CSS; it should have been created as a `div` with a CSS class called `indicator`, so you should be aware that the vertical divider may not be selected when you build dynamic pages in the future.
52 |
--------------------------------------------------------------------------------
/.github/workflows/publish-documentation.yml:
--------------------------------------------------------------------------------
1 | name: publish-documentation
2 |
3 | on:
4 | # run every time a push occurs in the docs folder
5 | push:
6 | branches: [main]
7 | paths:
8 | - docs/**
9 | - .github/workflows/documents.yml
10 | - package.json
11 | - CHANGELOG.md
12 | - package-lock.json
13 | # trigger deployment manually
14 | workflow_dispatch:
15 |
16 | jobs:
17 | publish-documentation:
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 | - uses: actions/checkout@v4
22 | with:
23 | # fetch all commits to get last updated time or other git log info
24 | fetch-depth: 0
25 |
26 | - name: Setup Node.js
27 | uses: actions/setup-node@v4
28 | with:
29 | node-version: '24'
30 |
31 | # cache node_modules
32 | - name: Cache dependencies
33 | uses: actions/cache@v4
34 | id: npm-cache
35 | with:
36 | path: |
37 | **/node_modules
38 | key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
39 | restore-keys: |
40 | ${{ runner.os }}-npm-
41 |
42 | # copy changelog.md file
43 | - name: Copy CHANGELOG.md file
44 | run: |
45 | cp CHANGELOG.md ./docs/en/changelog.md
46 | cp CHANGELOG.md ./docs/ko/changelog.md
47 | cp CHANGELOG.md ./docs/zhHans/changelog.md
48 |
49 | # install dependencies if the cache did not hit
50 | - name: Install dependencies
51 | if: steps.npm-cache.outputs.cache-hit != 'true'
52 | run: npm install
53 |
54 | # run build script
55 | - name: Build VitePress site
56 | run: npm run docs:build
57 |
58 | # please check out the docs of the workflow for more details
59 | # @see https://github.com/crazy-max/ghaction-github-pages
60 | - name: Deploy to GitHub Pages
61 | uses: crazy-max/ghaction-github-pages@v4
62 | with:
63 | # deploy to gh-pages branch
64 | target_branch: gh-pages
65 | # deploy the default output dir of VitePress
66 | build_dir: docs-dist
67 | jekyll: false
68 | fqdn: 'vitepress-sidebar.cdget.com'
69 | env:
70 | # @see https://docs.github.com/en/actions/reference/authentication-in-a-workflow#about-the-github_token-secret
71 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
72 |
--------------------------------------------------------------------------------
/lib/types.ts:
--------------------------------------------------------------------------------
1 | export declare interface VitePressSidebarOptions {
2 | documentRootPath?: string;
3 | scanStartPath?: string;
4 | resolvePath?: string;
5 | basePath?: string;
6 | collapsed?: boolean | null | undefined;
7 | collapseDepth?: number;
8 | hyphenToSpace?: boolean;
9 | underscoreToSpace?: boolean;
10 | capitalizeFirst?: boolean;
11 | capitalizeEachWords?: boolean;
12 | includeRootIndexFile?: boolean;
13 | includeFolderIndexFile?: boolean;
14 | useTitleFromFileHeading?: boolean;
15 | useTitleFromFrontmatter?: boolean;
16 | useFolderTitleFromIndexFile?: boolean;
17 | useFolderLinkFromIndexFile?: boolean;
18 | useFolderLinkFromSameNameSubFile?: boolean;
19 | includeDotFiles?: boolean;
20 | folderLinkNotIncludesFileName?: boolean;
21 | includeEmptyFolder?: boolean;
22 | sortMenusByName?: boolean;
23 | sortMenusByFrontmatterOrder?: boolean;
24 | sortMenusByFrontmatterDate?: boolean;
25 | sortMenusByFileDatePrefix?: boolean;
26 | sortMenusOrderByDescending?: boolean;
27 | sortMenusOrderNumericallyFromTitle?: boolean;
28 | sortMenusOrderNumericallyFromLink?: boolean;
29 | sortFolderTo?: null | undefined | 'top' | 'bottom';
30 | keepMarkdownSyntaxFromTitle?: boolean;
31 | debugPrint?: boolean;
32 | manualSortFileNameByPriority?: string[];
33 | excludeByFolderDepth?: number;
34 | excludeByGlobPattern?: string[];
35 | excludeFilesByFrontmatterFieldName?: string;
36 | followSymlinks?: boolean;
37 | removePrefixAfterOrdering?: boolean;
38 | prefixSeparator?: string | RegExp;
39 | rootGroupText?: string;
40 | rootGroupLink?: string;
41 | rootGroupCollapsed?: boolean | null | undefined;
42 | frontmatterOrderDefaultValue?: number;
43 | frontmatterTitleFieldName?: string;
44 | /**
45 | * @deprecated `excludePattern` has renamed `excludeByGlobPattern`. This option will be removed in a future version.
46 | */
47 | excludePattern?: string[];
48 | }
49 |
50 | export declare interface SidebarListItem {
51 | [key: string]: any;
52 | }
53 |
54 | export declare interface SortByObjectKeyOptions {
55 | arr: SidebarListItem;
56 | key: string;
57 | desc?: boolean;
58 | numerically?: boolean;
59 | datePrefixSeparator?: string | RegExp;
60 | dateSortFromFrontmatter?: boolean;
61 | dateSortFromTextWithPrefix?: boolean;
62 | }
63 |
64 | export declare type AnyValueObject = { [key: string]: any };
65 |
66 | /*
67 | * Types from: `vitepress/types/default-theme.d.ts`
68 | */
69 | export type SidebarItem = {
70 | text?: string;
71 | link?: string;
72 | items?: SidebarItem[];
73 | collapsed?: boolean;
74 | };
75 |
76 | export interface SidebarMultiItem {
77 | base: string;
78 | items: SidebarItem[];
79 | }
80 |
81 | export interface SidebarMulti {
82 | [path: string]: SidebarMultiItem;
83 | }
84 |
85 | export type Sidebar = SidebarItem[] | SidebarMulti;
86 | /*
87 | * END
88 | */
89 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vitepress-sidebar",
3 | "version": "1.33.1",
4 | "description": "A VitePress auto sidebar plugin that automatically creates a simple configuration.",
5 | "type": "module",
6 | "types": "dist/index.d.ts",
7 | "author": "CDGet ",
8 | "license": "MIT",
9 | "homepage": "https://vitepress-sidebar.cdget.com",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/jooy2/vitepress-sidebar"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/jooy2/vitepress-sidebar/issues"
16 | },
17 | "scripts": {
18 | "build": "npm run format:fix && tsc --project tsconfig.prod.json && npm run minify",
19 | "test": "npm run build && glob -c \"tsx --test\" \"./test/**/*.test.ts\"",
20 | "lint": "eslint . --ext .js,.ts .",
21 | "lint:fix": "eslint . --ext .js,.ts --fix .",
22 | "minify": "terser-glob 'dist/**/*.js' --config-file terser.config.json",
23 | "prepare": "npm run build",
24 | "format": "prettier .",
25 | "format:fix": "prettier . --write",
26 | "docs:dev": "npm run build && vitepress dev docs",
27 | "docs:build": "npm run build && vitepress build docs",
28 | "docs:serve": "npm run build && npm run docs:build && vitepress serve docs"
29 | },
30 | "engines": {
31 | "node": ">=18.0.0"
32 | },
33 | "main": "dist/index.js",
34 | "exports": {
35 | ".": {
36 | "types": "./dist/index.d.ts",
37 | "module": "./dist/index.js",
38 | "default": "./dist/index.js"
39 | },
40 | "./types": {
41 | "types": "./dist/types.d.ts",
42 | "module": "./dist/types.js",
43 | "default": "./dist/types.js"
44 | }
45 | },
46 | "typesVersions": {
47 | "*": {
48 | "index.d.ts": [
49 | "dist/index.d.ts"
50 | ]
51 | }
52 | },
53 | "keywords": [
54 | "vitepress",
55 | "vitepress-plugin",
56 | "vitepress-plugin-sidebar",
57 | "vitepress-sidebar",
58 | "vitepress-auto-sidebar",
59 | "vitepress-plugin-auto-sidebar",
60 | "vitepress-menu",
61 | "vitepress-sidemenu",
62 | "util",
63 | "utility",
64 | "sidebar",
65 | "sidebar-generator",
66 | "generator",
67 | "plugin",
68 | "sidemenu",
69 | "submenu",
70 | "menu",
71 | "autosidebar"
72 | ],
73 | "devDependencies": {
74 | "@eslint/js": "^9.39.1",
75 | "@types/node": "^24.10.1",
76 | "@typescript-eslint/parser": "^8.48.0",
77 | "eslint": "^9.39.1",
78 | "eslint-config-prettier": "^10.1.8",
79 | "eslint-plugin-n": "^17.23.1",
80 | "globals": "^16.5.0",
81 | "jiti": "^2.6.1",
82 | "prettier": "^3.7.2",
83 | "terser-glob": "^1.1.0",
84 | "tsx": "^4.20.6",
85 | "typescript": "^5.9.3",
86 | "typescript-eslint": "^8.48.0",
87 | "vitepress": "^1.6.4",
88 | "vitepress-i18n": "^1.3.4"
89 | },
90 | "dependencies": {
91 | "glob": "11.1.0",
92 | "gray-matter": "4.0.3",
93 | "qsu": "^1.10.4"
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Project
2 |
3 | Thank you for contributing to the project. Your contributions will help us take the project to the next level.
4 |
5 | This project adheres to the Contributor Covenant code of conduct. Your contribution implies that you have read and agree to this policy. Any behavior that undermines the quality of the project community, including this policy, will be warned or restricted by the maintainers.
6 |
7 | ## Issues
8 |
9 | Issues can be created on the following page: https://github.com/jooy2/vitepress-sidebar/issues
10 |
11 | Alternatively, you can email the package maintainer. However, we prefer to track progress via GitHub Issues.
12 |
13 | When creating an issue, keep the following in mind:
14 |
15 | - Please specify the correct category selection based on the format of the issue (e.g., bug report, feature request).
16 | - Check to see if there are duplicate issues.
17 | - Describe in detail what is happening and what needs to be fixed. You may need additional materials such as images or video.
18 | - Use appropriate keyword titles to make it easy for others to search and understand.
19 | - Please use English in all content.
20 | - You may need to describe the environment in which the issue occurs.
21 |
22 | ## How to contribute (Pull Requests)
23 |
24 | ### Write the code you want to change
25 |
26 | Here's the process for contributing to the project:
27 |
28 | 1. Clone the project (or rebase to the latest commit in the main branch)
29 | 2. Install the package (if the package manager exists)
30 | 3. Setting up lint or code formatter in the IDE (if your project includes a linter) and installing the relevant plugins. Some projects may use specific commands to check rules and perform formatting after module installation and before committing.
31 | 4. Write the code that needs to be fixed
32 | 5. Update the documentation (if it exists) or create a new one. If your project supports multilingual documentation, update the documentation for all languages. You can fill in the content in your own language and not translate it.
33 | 6. Add or modify tests as needed (if test code exists). You should also verify that existing tests pass.
34 |
35 | ### Write a commit message
36 |
37 | While we don't have strict restrictions on commit messages, we recommend that you follow the recommendations below whenever possible:
38 |
39 | - Write in English.
40 | - Use the ` symbol to name functions, variables, or folders and files.
41 | - Use a format like `xxx: message (fixes #1)`. The content in parentheses is optional.
42 | - The message includes a summary of what was modified.
43 | - It's a good idea to separate multiple modifications into their own commit messages.
44 |
45 | It is recommended that you include a tag at the beginning of the commit message. Between the tag and the message, use `: ` between the tag and the message.
46 |
47 | tags conform to the ["Udacity Git Commit Message Style Guide"](https://udacity.github.io/git-styleguide). However, you are welcome to use tags not listed here for additional situations.
48 |
49 | - `feat`: A new feature
50 | - `fix`: A bug fix
51 | - `docs`: Changes to documentation
52 | - `style`: Formatting, missing semicolons, etc.; no code change
53 | - `refactor`: Refactoring production code
54 | - `test`: Adding tests, refactoring test; no production code change
55 | - `chore`: Updating build tasks, package manager configs, etc.; no production code change
56 |
57 | Informal tags:
58 |
59 | - `package`: Modifications to package settings, modules, or GitHub projects
60 | - `typo`: Fix typos
61 |
62 | ### Create a pull request
63 |
64 | When creating a pull request, keep the following in mind:
65 |
66 | - Include a specific description of what the modification is, why it needs to be made, and how it works.
67 | - Check to see if there are duplicate pull requests.
68 | - Please use English in all content.
69 |
70 | Typically, a project maintainer will review and test your code before merging it into the project. This process can take some time, and they may ask you for further edits or clarifications in the comments.
71 |
--------------------------------------------------------------------------------
/docs/.vitepress/config.ts:
--------------------------------------------------------------------------------
1 | import { withSidebar } from '../../dist/index.js';
2 | import packageJson from '../../package.json' with { type: 'json' };
3 | import { defineConfig, UserConfig } from 'vitepress';
4 | import { withI18n } from 'vitepress-i18n';
5 | import type { VitePressI18nOptions } from 'vitepress-i18n/types';
6 | import type { VitePressSidebarOptions } from '../../dist/types.js';
7 |
8 | const defaultLocale: string = 'en';
9 | const supportLocales: string[] = [defaultLocale, 'ko', 'zhHans'];
10 | const editLinkPattern = `${packageJson.repository.url}/edit/main/docs/:path`;
11 |
12 | const commonSidebarConfig: VitePressSidebarOptions = {
13 | debugPrint: true,
14 | manualSortFileNameByPriority: ['introduction.md', 'guide', 'advanced-usage'],
15 | excludeByGlobPattern: ['changelog.md'],
16 | collapsed: false,
17 | capitalizeFirst: true,
18 | useTitleFromFileHeading: true,
19 | useTitleFromFrontmatter: true,
20 | useFolderTitleFromIndexFile: true,
21 | frontmatterOrderDefaultValue: 9, // For 'CHANGELOG.md'
22 | sortMenusByFrontmatterOrder: true
23 | };
24 |
25 | const vitePressSidebarConfig = [
26 | ...supportLocales.map((lang) => {
27 | return {
28 | ...commonSidebarConfig,
29 | documentRootPath: `/docs/${lang}`,
30 | resolvePath: defaultLocale === lang ? '/' : `/${lang}/`,
31 | ...(defaultLocale === lang ? {} : { basePath: `/${lang}/` })
32 | };
33 | })
34 | ];
35 |
36 | const vitePressI18nConfig: VitePressI18nOptions = {
37 | locales: supportLocales,
38 | debugPrint: true,
39 | rootLocale: defaultLocale,
40 | searchProvider: 'local',
41 | description: {
42 | en: 'VitePress Sidebar is a VitePress plugin that automatically generates sidebar menus with one setup and no hassle. Save time by easily creating taxonomies for tons of articles.',
43 | ko: 'VitePress Sidebar는 번거로운 작업 없이 한번의 설정만으로 사이드바 메뉴를 자동으로 생성하는 VitePress 플러그인입니다. 수많은 문서에 대한 분류를 손쉽게 만들어 시간을 절약하세요.',
44 | zhHans:
45 | 'VitePress Sidebar是一款VitePress插件,只需一次设置即可自动生成侧边栏菜单,无需任何麻烦。轻松为大量文章创建分类,节省时间。'
46 | },
47 | themeConfig: {
48 | en: {
49 | nav: [
50 | {
51 | text: 'Installation',
52 | link: '/guide/getting-started'
53 | },
54 | {
55 | text: 'Options',
56 | link: '/guide/options'
57 | },
58 | {
59 | text: 'Changelog',
60 | link: 'changelog'
61 | }
62 | ]
63 | },
64 | ko: {
65 | nav: [
66 | {
67 | text: '설치',
68 | link: '/ko/guide/getting-started'
69 | },
70 | {
71 | text: '옵션',
72 | link: '/ko/guide/options'
73 | },
74 | {
75 | text: '변경사항',
76 | link: '/ko/changelog'
77 | }
78 | ]
79 | },
80 | zhHans: {
81 | nav: [
82 | {
83 | text: '安装',
84 | link: '/zhHans/guide/getting-started'
85 | },
86 | {
87 | text: '选项',
88 | link: '/zhHans/guide/options'
89 | },
90 | {
91 | text: '变化',
92 | link: '/zhHans/changelog'
93 | }
94 | ]
95 | }
96 | }
97 | };
98 |
99 | // Ref: https://vitepress.dev/reference/site-config
100 | const vitePressConfig: UserConfig = {
101 | title: 'VitePress Sidebar',
102 | lastUpdated: true,
103 | outDir: '../docs-dist',
104 | cleanUrls: true,
105 | metaChunk: true,
106 | rewrites: {
107 | 'en/:rest*': ':rest*'
108 | },
109 | head: [
110 | ['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/logo-32.png' }],
111 | ['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/logo-16.png' }],
112 | ['link', { rel: 'shortcut icon', href: '/favicon.ico' }]
113 | ],
114 | sitemap: {
115 | hostname: packageJson.homepage
116 | },
117 | themeConfig: {
118 | logo: { src: '/logo-32.png', width: 24, height: 24 },
119 | editLink: {
120 | pattern: editLinkPattern
121 | },
122 | socialLinks: [
123 | { icon: 'npm', link: 'https://www.npmjs.com/package/vitepress-sidebar' },
124 | { icon: 'github', link: packageJson.repository.url.replace('.git', '') }
125 | ],
126 | footer: {
127 | message: 'Released under the MIT License',
128 | copyright: '© CDGet'
129 | }
130 | }
131 | };
132 |
133 | export default defineConfig(
134 | withSidebar(withI18n(vitePressConfig, vitePressI18nConfig), vitePressSidebarConfig)
135 | );
136 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🔌 VitePress Sidebar
2 |
3 | [](https://github.com/logicspark/awesome-vitepress-v1) [](https://github.com/jooy2/vitepress-sidebar/blob/main/LICENSE)   [](https://www.npmjs.com/package/vitepress-sidebar) [](https://www.npmjs.com/package/vitepress-sidebar)  [](https://github.com/jooy2) 
4 |
5 | **VitePress Sidebar** is a plugin for **[VitePress](https://vitepress.dev)** that automatically configures and manages the sidebar of your page with simple settings.
6 |
7 | - ⚡️ Optimized for the latest version of **VitePress**
8 | - ⚡️ Easy to use, lots of options to customize to your liking
9 | - ⚡️ Lightweight bundle file size
10 | - ⚡️ [Multiple Sidebars](https://vitepress.dev/reference/default-theme-sidebar#multiple-sidebars) support
11 | - ⚡️ [Frontmatter](https://vitepress.dev/guide/frontmatter) support
12 | - ⚡️ [TypeScript](https://www.typescriptlang.org) support
13 | - ⚡️ Customize menus for sorting, special character conversion, file and folder filters, and more!
14 |
15 | ## [Documentation (Getting Started & All option lists)](https://vitepress-sidebar.cdget.com/guide/getting-started)
16 |
17 | Installing and using the package and defining all the utility methods can be found on the documentation page below: https://vitepress-sidebar.cdget.com/guide/getting-started
18 |
19 | ```javascript
20 | import { withSidebar } from 'vitepress-sidebar';
21 |
22 | const vitePressConfigs = {
23 | title: 'VitePress Sidebar',
24 | themeConfig: {
25 | // ...
26 | }
27 | };
28 |
29 | export default defineConfig(
30 | withSidebar(vitePressConfigs, {
31 | /*
32 | * For detailed instructions, see the links below:
33 | * https://vitepress-sidebar.cdget.com/guide/options
34 | */
35 | //
36 | // ============ [ RESOLVING PATHS ] ============
37 | // documentRootPath: '/',
38 | // scanStartPath: null,
39 | // resolvePath: null,
40 | // basePath: null,
41 | // followSymlinks: false,
42 | //
43 | // ============ [ GROUPING ] ============
44 | // collapsed: true,
45 | // collapseDepth: 2,
46 | // rootGroupText: 'Contents',
47 | // rootGroupLink: 'https://github.com/jooy2',
48 | // rootGroupCollapsed: false,
49 | //
50 | // ============ [ GETTING MENU TITLE ] ============
51 | // useTitleFromFileHeading: true,
52 | // useTitleFromFrontmatter: true,
53 | // useFolderLinkFromIndexFile: false,
54 | // useFolderTitleFromIndexFile: false,
55 | // frontmatterTitleFieldName: 'title',
56 | //
57 | // ============ [ GETTING MENU LINK ] ============
58 | // useFolderLinkFromSameNameSubFile: false,
59 | // useFolderLinkFromIndexFile: false,
60 | // folderLinkNotIncludesFileName: false,
61 | //
62 | // ============ [ INCLUDE / EXCLUDE ] ============
63 | // excludeByGlobPattern: ['README.md', 'folder/'],
64 | // excludeFilesByFrontmatterFieldName: 'exclude',
65 | // excludeByFolderDepth: undefined,
66 | // includeDotFiles: false,
67 | // includeEmptyFolder: false,
68 | // includeRootIndexFile: false,
69 | // includeFolderIndexFile: false,
70 | //
71 | // ============ [ STYLING MENU TITLE ] ============
72 | // hyphenToSpace: true,
73 | // underscoreToSpace: true,
74 | // capitalizeFirst: false,
75 | // capitalizeEachWords: false,
76 | // keepMarkdownSyntaxFromTitle: false,
77 | // removePrefixAfterOrdering: false,
78 | // prefixSeparator: '.',
79 | //
80 | // ============ [ SORTING ] ============
81 | // manualSortFileNameByPriority: ['first.md', 'second', 'third.md'],
82 | // sortFolderTo: null,
83 | // sortMenusByName: false,
84 | // sortMenusByFileDatePrefix: false,
85 | // sortMenusByFrontmatterOrder: false,
86 | // frontmatterOrderDefaultValue: 0,
87 | // sortMenusByFrontmatterDate: false,
88 | // sortMenusOrderByDescending: false,
89 | // sortMenusOrderNumericallyFromTitle: false,
90 | // sortMenusOrderNumericallyFromLink: false,
91 | //
92 | // ============ [ MISC ] ============
93 | // debugPrint: false,
94 | })
95 | );
96 | ```
97 |
98 | ## Real-world Uses
99 |
100 | **VitePress Sidebar** is utilized in a variety of project environments, including my own web services.
101 |
102 | - To explore packages used other than: https://github.com/jooy2/vitepress-sidebar/network/dependents
103 |
104 | ## Contributing
105 |
106 | Anyone can contribute to the project by reporting new issues or submitting a pull request. For more information, please see [CONTRIBUTING.md](CONTRIBUTING.md).
107 |
108 | ## License
109 |
110 | Please see the [LICENSE](LICENSE) file for more information about project owners, usage rights, and more.
111 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8 |
9 | ## Our Standards
10 |
11 | Examples of behavior that contributes to a positive environment for our community include:
12 |
13 | - Demonstrating empathy and kindness toward other people
14 | - Being respectful of differing opinions, viewpoints, and experiences
15 | - Giving and gracefully accepting constructive feedback
16 | - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17 | - Focusing on what is best not just for us as individuals, but for the overall community
18 |
19 | Examples of unacceptable behavior include:
20 |
21 | - The use of sexualized language or imagery, and sexual attention or advances of any kind
22 | - Trolling, insulting or derogatory comments, and personal or political attacks
23 | - Public or private harassment
24 | - Publishing others' private information, such as a physical or email address, without their explicit permission
25 | - Other conduct which could reasonably be considered inappropriate in a professional setting
26 |
27 | ## Enforcement Responsibilities
28 |
29 | Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
32 |
33 | ## Scope
34 |
35 | This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
36 |
37 | ## Enforcement
38 |
39 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at https://cdget.com/contact. All complaints will be reviewed and investigated promptly and fairly.
40 |
41 | All community leaders are obligated to respect the privacy and security of the reporter of any incident.
42 |
43 | ## Enforcement Guidelines
44 |
45 | Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
46 |
47 | ### 1. Correction
48 |
49 | **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
50 |
51 | **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
52 |
53 | ### 2. Warning
54 |
55 | **Community Impact**: A violation through a single incident or series of actions.
56 |
57 | **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
58 |
59 | ### 3. Temporary Ban
60 |
61 | **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
62 |
63 | **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
64 |
65 | ### 4. Permanent Ban
66 |
67 | **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
68 |
69 | **Consequence**: A permanent ban from any sort of public interaction within the community.
70 |
71 | ## Attribution
72 |
73 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
74 |
75 | Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
76 |
77 | [homepage]: https://www.contributor-covenant.org
78 |
79 | For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
80 |
--------------------------------------------------------------------------------
/docs/zhHans/advanced-usage/multiple-sidebars-how-to.md:
--------------------------------------------------------------------------------
1 | # 多侧边栏操作方法
2 |
3 | 多侧边栏是一项允许根据特定 URI 路径显示不同侧边栏菜单的功能。
4 |
5 | 只需在 `vitepress-sidebar` 中进行一些简单设置,就能轻松实现这一功能。最终,**VitePress**将按照预期输出选项。
6 |
7 | 要先了解有关多侧边栏的更多信息,我们建议您查看下面**VitePress 的**官方文档:
8 |
9 | https://vitepress.dev/zh/reference/default-theme-sidebar#multiple-sidebars
10 |
11 | ## 基本用法
12 |
13 | 首先,假设你有一个名为 `docs` 的根项目,其中有名为 `guide` 和 `config` 的子目录,就像这样:
14 |
15 | ```text
16 | docs/
17 | ├─ guide/
18 | │ ├─ index.md
19 | │ ├─ one.md
20 | │ ├─ two.md
21 | │ └─ do-not-include.md
22 | └─ config/
23 | ├─ index.md
24 | ├─ three.md
25 | └─ four.md
26 | ```
27 |
28 | 当URL位于`/guide`页面时,用户希望菜单仅显示`guide`的子菜单,隐藏`config`的子菜单。同样,当`guide`位于`/config`页面时,您希望隐藏`guide`的子菜单。
29 |
30 | 要在 `vitepress-sidebar` 中实现此功能,您需要采用与现有设置不同的方法。
31 |
32 | 像以前一样使用`withSidebar`函数,但传递一个数组。该数组至少包含一个来自`vitepress-sidebar`的选项。数组中的值可以是任意数量的URL。当然,您也可以使用不同的设置进行配置。
33 |
34 | ```javascript
35 | // 必须传递数组参数!!!!
36 | const vitePressConfigs = {
37 | /* ... */
38 | };
39 |
40 | export default defineConfig(
41 | withSidebar(vitePressConfigs, [
42 | {
43 | documentRootPath: 'docs',
44 | scanStartPath: 'guide',
45 | basePath: '/guide/',
46 | resolvePath: '/guide/',
47 | useTitleFromFileHeading: true
48 | },
49 | {
50 | documentRootPath: 'docs',
51 | scanStartPath: 'config',
52 | resolvePath: '/config/',
53 | useTitleFromFrontmatter: true
54 | }
55 | ])
56 | );
57 | ```
58 |
59 | 这些选项的值在结果中的使用情况如下:
60 |
61 | ```text
62 | {
63 | : [
64 | {
65 | base: ,
66 | items: [...] // `/path/to/items`
67 | }
68 | ]
69 | }
70 | ```
71 |
72 | 下面是上述设置的输出示例:
73 |
74 | ```json5
75 | {
76 | '/guide/': {
77 | base: '/guide/',
78 | items: [
79 | {
80 | text: 'One',
81 | link: 'one'
82 | },
83 | {
84 | text: 'Two',
85 | link: 'two'
86 | }
87 | ]
88 | },
89 | '/config/': {
90 | base: '/config/',
91 | items: [
92 | {
93 | text: 'Three',
94 | link: 'three'
95 | },
96 | {
97 | text: 'Four',
98 | link: 'four'
99 | }
100 | ]
101 | }
102 | }
103 | ```
104 |
105 | ## 多个侧边栏选项
106 |
107 | 以下选项可用于多个侧边栏:`scanStartPath`、`basePath`和`resolvePath`。每个选项都是可选的,但应根据具体情况正确使用。
108 |
109 | 下文将对每个选项进行说明。但我们建议您首先参考[选项](/zhHans/guide/options)页面上对每个选项的描述。
110 |
111 | 以下描述基于以下示例:
112 |
113 | ```text
114 | docs/
115 | ├─ .vitepress/
116 | ├─ guide/
117 | │ ├─ api/
118 | │ │ ├─ api-one.md
119 | │ │ └─ api-two.md
120 | │ ├─ one.md
121 | │ └─ two.md
122 | └─ config/
123 | ├─ index.md
124 | ├─ three.md
125 | └─ four.md
126 | ```
127 |
128 | ### `scanStartPath`
129 |
130 | 此选项用于为不同的路由规则指定不同的根目录。`documentRootPath`是实际要扫描的根目录(即`.vitepress`目录所在的位置),而`scanStartPath`是此路由规则中实际要显示的根目录。
131 |
132 | 例如,若要仅包含`/guide`目录中的文件,请将`scanStartPath`的值指定为`guide`。但是,`documentRootPath`中的路径不应包含在内。
133 |
134 | ### `resolvePath`
135 |
136 | VitePress使用此选项在遇到特定URI时显示相关菜单。例如,如果您想在到达`example.com/guide/api`时仅显示`guide/api`目录的内容,则`resolvePath`的值为`/guide/api`。建议您在路径前添加`/`。
137 |
138 | 通常,它的值与 `scanStartPath` 类似,但有时您可能需要为 **i18n** 路由指定不同的值。
139 |
140 | ### `basePath`
141 |
142 | 此选项主要用于VitePress的重写规则,否则为可选。
143 |
144 | 它取代了VitePress中`base`路径的值。如果未指定该值,则指定`resolvePath`的值或根路径(`/`)。
145 |
146 | 如果目录的实际路径与URI中的路径结构不同,您应该能够通过重写功能导航到页面。通常情况下,侧边栏会根据根目录生成路径,而不会引用VitePress中的重写路径。
147 |
148 | 例如,假设您有一个重写规则,如下所示:
149 |
150 | ```javascript
151 | const vitePressConfigs = {
152 | rewrites: {
153 | 'guide/:page': 'help/:page'
154 | }
155 | };
156 |
157 | const vitePressSidebarConfigs = [
158 | {
159 | documentRootPath: 'docs',
160 | scanStartPath: 'guide',
161 | resolvePath: '/guide/'
162 | }
163 | ];
164 |
165 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
166 | ```
167 |
168 | `guide/one.md` 文档显示在 `help/one` 的路径中。但是,如果您这样做,侧边栏将不会显示菜单,因为它会尝试找到 `help/one`,而这是路径本身。
169 |
170 | 要解决这个问题,请将`basePath`中的路径改为`help`:
171 |
172 | ```javascript
173 | const vitePressConfigs = {
174 | rewrites: {
175 | 'guide/:page': 'help/:page'
176 | }
177 | };
178 |
179 | const vitePressSidebarConfigs = [
180 | {
181 | documentRootPath: 'docs',
182 | scanStartPath: 'guide',
183 | basePath: 'help', // <---------------------- 添加这一行
184 | resolvePath: '/guide/'
185 | }
186 | ];
187 |
188 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
189 | ```
190 |
191 | ## 显示带有复杂路径和 URI 的菜单
192 |
193 | 上面的例子通常是在路径按步骤定义的情况下,但当你想显示按步骤深入的文件夹时,特别是当 URI 较短或使用与实际文件夹路径不同的约定时,你需要使用额外的方法。例如,你有一个这样的文件夹结构:
194 |
195 | ```text
196 | docs/
197 | ├─ guide/
198 | │ ├─ api/
199 | │ │ ├─ api-one.md
200 | │ │ └─ api-two.md
201 | │ ├─ one.md
202 | │ └─ two.md
203 | └─ config/
204 | ├─ index.md
205 | ├─ three.md
206 | └─ four.md
207 | ```
208 |
209 | 这次,我们希望当到达单级 URI `/api` 时,在 `docs/guide/api` 中显示菜单。预期的菜单仅显示 `api-one.md` 和 `api-two.md`。
210 |
211 | ```javascript
212 | withSidebar([
213 | {
214 | documentRootPath: 'docs',
215 | scanStartPath: 'guide/api',
216 | resolvePath: '/api/'
217 | }
218 | ]);
219 | ```
220 |
221 | 但是,如果您这样配置选项,将无法显示菜单,因为`api`目录是`guide`的子目录。**VitePress**无法检测到这一点,并会导航到一个不存在的文档。
222 |
223 | 要解决这个问题,您需要同时使用**VitePress的**路由功能,请参阅以下文章以获取说明:
224 |
225 | https://vitepress.dev/zh/guide/routing#route-rewrites
226 |
227 | 按照上面的示例,在 `defineConfig` 中的 VitePress 设置中添加 `rewrites` 选项:
228 |
229 | ```javascript
230 | const vitePressConfigs = {
231 | /* [START] Add This */
232 | rewrites: {
233 | 'guide/api/:page': 'api/:page'
234 | }
235 | /* [END] Add This */
236 | };
237 |
238 | const vitePressSidebarConfigs = {
239 | documentRootPath: 'docs',
240 | scanStartPath: 'guide/api',
241 | resolvePath: '/api/'
242 | };
243 |
244 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
245 | ```
246 |
247 | 现在,当 URI 路径以 `/api` 开头时,将显示 `docs/guide/api` 的子菜单!
248 |
--------------------------------------------------------------------------------
/test/specs/multiple-sidebar.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'assert';
2 | import { describe, it } from 'node:test';
3 | import { generateSidebar } from '../../dist';
4 |
5 | const TEST_DIR_BASE = 'test/resources';
6 |
7 | describe('Test: multiple sidebars', () => {
8 | it('Multiple Sidebars (A)', () => {
9 | assert.deepEqual(
10 | generateSidebar([
11 | {
12 | documentRootPath: `${TEST_DIR_BASE}/general`,
13 | resolvePath: '/'
14 | },
15 | {
16 | documentRootPath: `${TEST_DIR_BASE}/general`,
17 | scanStartPath: 'folder',
18 | resolvePath: '/folder/'
19 | },
20 | {
21 | documentRootPath: `${TEST_DIR_BASE}/general`,
22 | scanStartPath: 'folder-2',
23 | resolvePath: '/folder-2'
24 | }
25 | ]),
26 | {
27 | '/': {
28 | base: '/',
29 | items: [
30 | {
31 | text: 'a',
32 | link: 'a'
33 | },
34 | {
35 | text: 'b',
36 | link: 'b'
37 | },
38 | {
39 | text: 'c',
40 | link: 'c'
41 | },
42 | {
43 | text: 'folder',
44 | items: [
45 | {
46 | text: 'folder-test-2',
47 | link: 'folder/folder-test-2'
48 | },
49 | {
50 | text: 'folder-test',
51 | link: 'folder/folder-test'
52 | },
53 | {
54 | text: 'subFolder',
55 | items: [
56 | {
57 | text: 'sub-folder-test',
58 | link: 'folder/subFolder/sub-folder-test'
59 | }
60 | ]
61 | }
62 | ]
63 | },
64 | {
65 | text: 'folder-2',
66 | items: [
67 | {
68 | text: 'folder2',
69 | link: 'folder-2/folder2'
70 | }
71 | ]
72 | },
73 | {
74 | text: 'test',
75 | link: 'test'
76 | }
77 | ]
78 | },
79 | '/folder/': {
80 | base: '/folder/',
81 | items: [
82 | {
83 | text: 'folder-test-2',
84 | link: 'folder-test-2'
85 | },
86 | {
87 | text: 'folder-test',
88 | link: 'folder-test'
89 | },
90 | {
91 | text: 'subFolder',
92 | items: [
93 | {
94 | text: 'sub-folder-test',
95 | link: 'subFolder/sub-folder-test'
96 | }
97 | ]
98 | }
99 | ]
100 | },
101 | '/folder-2': {
102 | base: '/folder-2',
103 | items: [
104 | {
105 | text: 'folder2',
106 | link: 'folder2'
107 | }
108 | ]
109 | }
110 | }
111 | );
112 | });
113 |
114 | it('Multiple Sidebars (B)', () => {
115 | assert.deepEqual(
116 | generateSidebar([
117 | {
118 | documentRootPath: `${TEST_DIR_BASE}/general`,
119 | scanStartPath: 'folder/subFolder',
120 | resolvePath: '/folder'
121 | }
122 | ]),
123 | {
124 | '/folder': {
125 | base: '/folder',
126 | items: [
127 | {
128 | text: 'sub-folder-test',
129 | link: 'sub-folder-test'
130 | }
131 | ]
132 | }
133 | }
134 | );
135 | });
136 |
137 | it('Multiple Sidebars (C)', () => {
138 | assert.deepEqual(
139 | generateSidebar([
140 | {
141 | documentRootPath: `${TEST_DIR_BASE}/general`,
142 | scanStartPath: 'folder',
143 | resolvePath: '/folder/',
144 | includeRootIndexFile: true,
145 | includeFolderIndexFile: true
146 | },
147 | {
148 | documentRootPath: `${TEST_DIR_BASE}/general`,
149 | scanStartPath: 'folder-2',
150 | resolvePath: '/folder-2/',
151 | includeRootIndexFile: true,
152 | includeFolderIndexFile: true,
153 | useFolderLinkFromIndexFile: true
154 | }
155 | ]),
156 | {
157 | '/folder/': {
158 | base: '/folder/',
159 | items: [
160 | {
161 | text: 'folder-test-2',
162 | link: 'folder-test-2'
163 | },
164 | {
165 | text: 'folder-test',
166 | link: 'folder-test'
167 | },
168 | {
169 | text: 'subFolder',
170 | items: [
171 | {
172 | text: 'sub-folder-test',
173 | link: 'subFolder/sub-folder-test'
174 | }
175 | ]
176 | }
177 | ]
178 | },
179 | '/folder-2/': {
180 | base: '/folder-2/',
181 | items: [
182 | {
183 | text: 'folder2',
184 | link: 'folder2'
185 | },
186 | {
187 | text: 'index',
188 | link: 'index.md'
189 | }
190 | ]
191 | }
192 | }
193 | );
194 | });
195 |
196 | it('Multiple Sidebars (D)', () => {
197 | assert.deepEqual(
198 | generateSidebar([
199 | {
200 | documentRootPath: `${TEST_DIR_BASE}/general`,
201 | scanStartPath: 'folder/subFolder',
202 | basePath: 'page',
203 | resolvePath: 'folder'
204 | }
205 | ]),
206 | {
207 | folder: {
208 | base: 'page',
209 | items: [
210 | {
211 | text: 'sub-folder-test',
212 | link: 'sub-folder-test'
213 | }
214 | ]
215 | }
216 | }
217 | );
218 | });
219 | });
220 |
--------------------------------------------------------------------------------
/docs/ko/advanced-usage/multiple-sidebars-how-to.md:
--------------------------------------------------------------------------------
1 | # 다중 사이드바
2 |
3 | 다중 사이드바는 특정 URI 경로에 따라 서로 다른 사이드바 메뉴를 표시할 수 있는 기능입니다.
4 |
5 | 이것은 몇 가지 간단한 설정으로 `vitepress-sidebar`에서 쉽게 구현할 수 있습니다. 결국 **VitePress**는 의도한 대로 옵션을 출력합니다.
6 |
7 | 다중 사이드바에 대해 자세히 알아보려면 먼저 아래의 **VitePress** 공식 문서를 살펴보는 것이 좋습니다:
8 |
9 | https://vitepress.dev/ko/reference/default-theme-sidebar#multiple-sidebars
10 |
11 | ## 기본 사용법
12 |
13 | 먼저, 다음과 같이 `docs`라는 루트 프로젝트와 `guide` 및 `config`라는 하위 디렉터리가 있다고 가정해 보겠습니다:
14 |
15 | ```text
16 | docs/
17 | ├─ guide/
18 | │ ├─ index.md
19 | │ ├─ one.md
20 | │ ├─ two.md
21 | │ └─ do-not-include.md
22 | └─ config/
23 | ├─ index.md
24 | ├─ three.md
25 | └─ four.md
26 | ```
27 |
28 | URL이 `/guide` 페이지에 있는 경우 사용자는 메뉴에 `guide`의 하위 메뉴만 표시하고 `config`의 하위 메뉴는 숨기기를 원합니다. 마찬가지로 `/config` 페이지에 `guide`의 하위 메뉴가 있을 때 하위 메뉴를 숨기려고 합니다.
29 |
30 | 이를 `vitepress-sidebar`에서 구현하려면 기존 설정과 다르게 접근해야 합니다.
31 |
32 | 이전과 같이 `withSidebar` 함수를 사용하되 배열을 전달합니다. 배열에는 `vitepress-sidebar`의 옵션이 하나 이상 포함됩니다. 배열의 값은 원하는 만큼의 URL을 지정할 수 있습니다. 물론 다른 설정으로 구성할 수도 있습니다.
33 |
34 | ```javascript
35 | // 배열 인수를 전달해야 함!!!!
36 | const vitePressConfigs = {
37 | /* ... */
38 | };
39 |
40 | export default defineConfig(
41 | withSidebar(vitePressConfigs, [
42 | {
43 | documentRootPath: 'docs',
44 | scanStartPath: 'guide',
45 | basePath: '/guide/',
46 | resolvePath: '/guide/',
47 | useTitleFromFileHeading: true
48 | },
49 | {
50 | documentRootPath: 'docs',
51 | scanStartPath: 'config',
52 | resolvePath: '/config/',
53 | useTitleFromFrontmatter: true
54 | }
55 | ])
56 | );
57 | ```
58 |
59 | 이러한 옵션의 값은 다음과 같이 결과에 사용됩니다:
60 |
61 | ```text
62 | {
63 | : [
64 | {
65 | base: ,
66 | items: [...] // `/path/to/items`
67 | }
68 | ]
69 | }
70 | ```
71 |
72 | 다음은 위 설정의 출력 예시입니다:
73 |
74 | ```json5
75 | {
76 | '/guide/': {
77 | base: '/guide/',
78 | items: [
79 | {
80 | text: 'One',
81 | link: 'one'
82 | },
83 | {
84 | text: 'Two',
85 | link: 'two'
86 | }
87 | ]
88 | },
89 | '/config/': {
90 | base: '/config/',
91 | items: [
92 | {
93 | text: 'Three',
94 | link: 'three'
95 | },
96 | {
97 | text: 'Four',
98 | link: 'four'
99 | }
100 | ]
101 | }
102 | }
103 | ```
104 |
105 | ## 다중 사이드바 설정
106 |
107 | 다중 사이드바에서 사용할 수 있는 옵션은 다음과 같습니다: `scanStartPath`, `basePath` 및 `resolvePath`. 각 옵션은 선택 사항이지만 상황에 따라 올바르게 사용할 수 있어야 합니다.
108 |
109 | 각 옵션은 아래에 설명되어 있습니다. 그러나 먼저 [옵션](/ko/guide/options) 페이지에서 각 옵션에 대한 설명을 참조하는 것이 좋습니다.
110 |
111 | 아래 설명은 다음 예시를 기반으로 합니다:
112 |
113 | ```text
114 | docs/
115 | ├─ .vitepress/
116 | ├─ guide/
117 | │ ├─ api/
118 | │ │ ├─ api-one.md
119 | │ │ └─ api-two.md
120 | │ ├─ one.md
121 | │ └─ two.md
122 | └─ config/
123 | ├─ index.md
124 | ├─ three.md
125 | └─ four.md
126 | ```
127 |
128 | ### `scanStartPath`
129 |
130 | 이 옵션은 다른 라우팅 규칙의 루트 경로로 다른 디렉터리를 지정하는 데 사용됩니다. `documenRootPath`는 실제로 스캔할 루트 경로(`.vitepress` 디렉터리가 있는 위치)이고 `scanStartPath`는 이 경로 규칙에서 실제로 표시되어야 하는 루트 경로입니다.
131 |
132 | 예를 들어 `/guide` 디렉터리에 있는 파일만 포함하려면 `scanStartPath`의 값을 `guide`로 지정합니다. 단, `documentRootPath`의 경로는 포함되지 않아야 합니다.
133 |
134 | ### `resolvePath`
135 |
136 | 이 옵션은 특정 URI를 발견했을 때 관련 메뉴를 표시하기 위해 VitePress에서 사용합니다. 예를 들어 `example.com/guide/api`에 도달할 때 `guide/api` 디렉토리의 내용만 표시하려면 `resolvePath`의 값은 `/guide/api`가 됩니다. 경로 앞에 `/`를 포함하는 것이 좋습니다.
137 |
138 | 이 값은 일반적으로 `scanStartPath`와 비슷한 값을 갖지만, **i18n** 라우팅을 위해 다르게 지정해야 하는 경우도 있습니다.
139 |
140 | ### `basePath`
141 |
142 | 이 옵션은 주로 VitePress의 `rewrite` 규칙으로 작업할 때 사용되며, 그 외에는 선택 사항입니다.
143 |
144 | VitePress에서 `base` 경로의 값을 대체합니다. 이 값을 지정하지 않으면 `resolvePath` 값 또는 루트 경로(`/`)가 지정됩니다.
145 |
146 | 디렉토리의 실제 경로가 URI의 경로 구조와 다른 경우 다시 쓰기를 통해 제공된 페이지로 이동할 수 있어야 합니다. 일반적으로 사이드바는 루트 디렉터리를 기반으로 경로를 생성하며 VitePress의 다시 쓰기 경로를 참조하지 않습니다.
147 |
148 | 예를 들어 다음과 같은 재작성 규칙이 있다고 가정해 보겠습니다:
149 |
150 | ```javascript
151 | const vitePressConfigs = {
152 | rewrites: {
153 | 'guide/:page': 'help/:page'
154 | }
155 | };
156 |
157 | const vitePressSidebarConfigs = [
158 | {
159 | documentRootPath: 'docs',
160 | scanStartPath: 'guide',
161 | resolvePath: '/guide/'
162 | }
163 | ];
164 |
165 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
166 | ```
167 |
168 | `guide/one.md` 문서가 `help/one` 경로에 표시됩니다. 그러나 이렇게 하면 사이드바가 경로인 `help/one`을 그대로 찾으려고 하기 때문에 메뉴가 표시되지 않습니다.
169 |
170 | 이 문제를 해결하려면 `basePath`의 경로를 `help`로 변경하세요:
171 |
172 | ```javascript
173 | const vitePressConfigs = {
174 | rewrites: {
175 | 'guide/:page': 'help/:page'
176 | }
177 | };
178 |
179 | const vitePressSidebarConfigs = [
180 | {
181 | documentRootPath: 'docs',
182 | scanStartPath: 'guide',
183 | basePath: 'help', // <---------------------- 이 라인을 추가합니다.
184 | resolvePath: '/guide/'
185 | }
186 | ];
187 |
188 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
189 | ```
190 |
191 | ## 복잡한 경로 및 URI가 있는 메뉴 표시하기
192 |
193 | 위의 예는 일반적으로 경로가 단계로 정의된 경우이지만, 단계가 깊은 폴더를 표시하려는 경우, 특히 URI가 더 짧거나 실제 폴더 경로와 다른 규칙을 사용하는 경우에는 추가 방법을 사용해야 합니다. 예를 들어 다음과 같은 폴더 구조가 있습니다:
194 |
195 | ```text
196 | docs/
197 | ├─ guide/
198 | │ ├─ api/
199 | │ │ ├─ api-one.md
200 | │ │ └─ api-two.md
201 | │ ├─ one.md
202 | │ └─ two.md
203 | └─ config/
204 | ├─ index.md
205 | ├─ three.md
206 | └─ four.md
207 | ```
208 |
209 | 이번에는 `/api`라는 한 단계 URI에 도달했을 때 `docs/guide/api`의 메뉴를 표시하고 싶습니다. 예상되는 메뉴는 `api-one.md`와 `api-two.md`만 표시하는 것입니다.
210 |
211 | ```javascript
212 | withSidebar([
213 | {
214 | documentRootPath: 'docs',
215 | scanStartPath: 'guide/api',
216 | resolvePath: '/api/'
217 | }
218 | ]);
219 | ```
220 |
221 | 하지만 이렇게 옵션을 구성하면 `api` 디렉터리가 `guide`의 하위 디렉터리이기 때문에 메뉴를 표시할 수 없습니다. **VitePress**는 이를 감지하지 못하고 존재하지 않는 문서로 이동합니다.
222 |
223 | 이를 해결하려면 **VitePress**의 라우팅 기능을 병행해서 사용해야 합니다. 관련 내용은 아래 글을 참고하세요:
224 |
225 | https://vitepress.dev/ko/guide/routing#route-rewrites
226 |
227 | 위의 예에 따라 `defineConfig`의 VitePress 설정에 `rewrites` 옵션을 추가합니다:
228 |
229 | ```javascript
230 | const vitePressConfigs = {
231 | /* [START] Add This */
232 | rewrites: {
233 | 'guide/api/:page': 'api/:page'
234 | }
235 | /* [END] Add This */
236 | };
237 |
238 | const vitePressSidebarConfigs = {
239 | documentRootPath: 'docs',
240 | scanStartPath: 'guide/api',
241 | resolvePath: '/api/'
242 | };
243 |
244 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
245 | ```
246 |
247 | 이제 URI 경로가 `/api`로 시작하면 `docs/guide/api`의 하위 메뉴가 표시됩니다!
248 |
--------------------------------------------------------------------------------
/docs/zhHans/advanced-usage/internationalization.md:
--------------------------------------------------------------------------------
1 | # 国际化
2 |
3 | 本页介绍如何使用 VitePress Sidebar 实现国际化(i18n)。
4 |
5 | VitePress 支持多语言文档。如果您将翻译好的标记文件放在每种语言的目录中,并在 VitePress 的 `defineConfig` 中使用 `locales` 选项,就会显示语言选择器,并显示指定目录中每种语言的文档。
6 |
7 | ## 翻译页面布局(手动)
8 |
9 | 首先,VitePress 允许您翻译各种布局界面元素。所谓布局,是指 “上一页”、“下一页”、“目录”、“更改主题 ”等功能的所有相关文本。 它还包括翻译搜索功能中出现的所有文本。
10 |
11 | VitePress 页面上的各种界面(布局)文本可提供特定语言的 `locales` 翻译。例如:
12 |
13 | ```text
14 | "locales": {
15 | "root": {
16 | "lang": "en-US",
17 | "label": "English",
18 | "description": "VitePress Sidebar is a VitePress plugin that automatically generates sidebar menus with one setup and no hassle. Save time by easily creating taxonomies for tons of articles.",
19 | "themeConfig": {
20 | "docFooter": {
21 | "prev": "Previous page",
22 | "next": "Next page"
23 | },
24 | "outline": {
25 | "label": "On this page"
26 | },
27 | "lastUpdated": {
28 | "text": "Last updated"
29 | },
30 | "langMenuLabel": "Change language",
31 | "returnToTopLabel": "Return to top",
32 | "sidebarMenuLabel": "Menu",
33 | "darkModeSwitchLabel": "Appearance",
34 | "lightModeSwitchTitle": "Switch to light theme",
35 | "darkModeSwitchTitle": "Switch to dark theme"
36 | }
37 | },
38 | "ko": {
39 | "lang": "ko-KR",
40 | "label": "한국어",
41 | "description": "VitePress Sidebar는 번거로운 작업 없이 한번의 설정만으로 사이드바 메뉴를 자니다. 수많은 문서에 대한 분류를 손쉽게 만들어 시간을 절약하세요.",
42 | "themeConfig": {
43 | "docFooter": {
44 | "prev": "이전",
45 | "next": "다음"
46 | },
47 | "outline": {
48 | "label": "이 페이지 콘텐츠"
49 | },
50 | "lastUpdated": {
51 | "text": "업데이트 일자"
52 | },
53 | "langMenuLabel": "언어 변경",
54 | "returnToTopLabel": "맨 위로",
55 | "sidebarMenuLabel": "사이드바 메뉴",
56 | "darkModeSwitchLabel": "다크 모드",
57 | "lightModeSwitchTitle": "라이트 모드로 변경",
58 | "darkModeSwitchTitle": "다크 모드로 변경"
59 | }
60 | }
61 | }
62 | ```
63 |
64 | (`root` "语言指页面上的主要语言)。
65 |
66 | 要了解有关翻译布局的更多信息,请参阅以下文章: https://vitepress.dev/zh/guide/i18n
67 |
68 | 对于搜索功能中出现的文本,需要在 `defineConfig` 中的 `themeConfig.search` 选项中进行设置,例如:
69 |
70 | ```text
71 | "themeConfig": {
72 | "search": {
73 | "provider": "local",
74 | "options": {
75 | "locales": {
76 | "root": {
77 | "translations": {
78 | "button": {
79 | "buttonText": "Search",
80 | "buttonAriaLabel": "Search"
81 | },
82 | "modal": {
83 | "displayDetails": "Display detailed list",
84 | "resetButtonTitle": "Reset search",
85 | "backButtonTitle": "Close search",
86 | "noResultsText": "No results for",
87 | "footer": {
88 | "selectText": "to select",
89 | "selectKeyAriaLabel": "enter",
90 | "navigateText": "to navigate",
91 | "navigateUpKeyAriaLabel": "up arrow",
92 | "navigateDownKeyAriaLabel": "down arrow",
93 | "closeText": "to close",
94 | "closeKeyAriaLabel": "escape"
95 | }
96 | }
97 | }
98 | },
99 | "ko": {
100 | "translations": {
101 | "button": {
102 | "buttonText": "검색",
103 | "buttonAriaLabel": "검색"
104 | },
105 | "modal": {
106 | "displayDetails": "상세 목록 표시",
107 | "resetButtonTitle": "검색 초기화",
108 | "backButtonTitle": "검색 닫기",
109 | "noResultsText": "결과를 찾을 수 없음",
110 | "footer": {
111 | "selectText": "선택",
112 | "selectKeyAriaLabel": "선택하기",
113 | "navigateText": "탐색",
114 | "navigateUpKeyAriaLabel": "위로",
115 | "navigateDownKeyAriaLabel": "아래로",
116 | "closeText": "닫기",
117 | "closeKeyAriaLabel": "esc"
118 | }
119 | }
120 | }
121 | }
122 | }
123 | }
124 | }
125 | }
126 | ```
127 |
128 | ## 翻译页面布局(自动)
129 |
130 | [VitePress I18n](https://vitepress-i18n.cdget.com)是VitePress侧边栏的一个家族插件,可让您自动完成上述手动翻译过程。只需进行一些简单的设置,您就不必花费数小时来翻译布局!
131 |
132 | 使用以下命令安装 VitePress I18n 模块:
133 |
134 | ```shell
135 | $ npm i -D vitepress-i18n
136 | ```
137 |
138 | 在 `defineConfig` 中,将其设置为:
139 |
140 | ```javascript
141 | import { withSidebar } from 'vitepress-sidebar';
142 | import { withI18n } from 'vitepress-i18n';
143 |
144 | const vitePressConfig = {
145 | // VitePress config
146 | };
147 |
148 | const vitePressSidebarConfig = {
149 | // VitePress Sidebar config
150 | };
151 |
152 | const vitePressI18nConfig = {
153 | // VitePress I18n config
154 | locales: ['en', 'ko'], // first locale 'en' is root locale
155 | searchProvider: 'local' // enable search with auto translation
156 | };
157 |
158 | export default defineConfig(
159 | withSidebar(withI18n(vitePressConfig, vitePressI18nConfig), vitePressSidebarConfig)
160 | );
161 | ```
162 |
163 | 现在,您可以将界面翻译工作交给模块来完成!当然,您也可以自定义详细文本。
164 |
165 | 更多信息,请阅读 VitePress I18n 文档页面: https://vitepress-i18n.cdget.com/guide/getting-started
166 |
167 | ## 特定语言侧边栏设置
168 |
169 | 在 VitePress 中,您可以根据不同的语言显示不同的侧边栏。例如,假设您的文件夹结构如下:
170 |
171 | ```text
172 | /
173 | ├─ package.json
174 | ├─ docs/
175 | │ ├─ .vitepress/
176 | │ │ └─ config.js
177 | │ ├─ en/
178 | │ │ └─ abc.md
179 | │ ├─ ko/
180 | │ │ └─ abc.md
181 | │ └─ zhHans/
182 | │ └─ abc.md
183 | └─ ...
184 | ```
185 |
186 | 在示例中,`abc.md` 是翻译成每种语言的同一文档。如果将语言分别改为英文、韩文和中文,侧边栏将扫描每个目录`en`、`ko`和`zhHans`,以获取该语言的标题。
187 |
188 | 下面举例说明如何做到这一点:
189 |
190 | ```javascript
191 | const rootLocale = 'en'
192 | const supportedLocales = [rootLocale, 'ko', 'zhHans'];
193 |
194 | const vitePressConfigs = {
195 | rewrites: {
196 | 'en/:rest*': ':rest*'
197 | }
198 | }
199 |
200 | const commonSidebarConfigs = {
201 | // Sidebar common configurations
202 | }
203 |
204 | const vitePressSidebarConfigs = [
205 | ...supportedLocales.map((lang) => {
206 | return {
207 | ...commonSidebarConfigs,
208 | ...(rootLocale === lang ? {} : { basePath: `/${lang}/` }), // If using `rewrites` option
209 | documentRootPath: `/docs/${lang}`,
210 | resolvePath: rootLocale === lang ? '/' : `/${lang}/`,
211 | };
212 | })
213 | ]
214 |
215 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs)
216 | ```
217 |
218 | 首先,`rewrites` 允许您在使用英语作为根语言(`en` 目录)时抑制 URI 路径中的 `/en/`(这是可选的)。
219 |
220 | 下一步,`sidebar` 的设置与上一步类似,但需要为每种语言设置多个侧边栏和目录。 下文将解释每个选项:
221 |
222 | - `basePath`: 与 `rewrites` 规则一起使用时,可防止根本地化指向 `/en/` 路径。
223 | - `documentRootPath`: 实际文档文件所在的根路径。 对于每种语言,查找 `en`、`ko` 和 `zhHans` 目录。
224 | - `resolvePath`: `/docs` 实际扫描侧边栏列表的目录中文件的位置。 为每种语言指定目录位置,不包括根本地语言。
225 |
226 | 这样可以确保侧边栏只显示指定目录下每种语言的文档。以上只是一个示例,您可能需要根据项目规模或目录结构设置不同的选项。
227 |
--------------------------------------------------------------------------------
/docs/ko/advanced-usage/internationalization.md:
--------------------------------------------------------------------------------
1 | # 국제화
2 |
3 | 이 페이지에서는 VitePress Sidebar를 사용하여 i18n (internationalization)을 달성하는 방법을 기술합니다.
4 |
5 | VitePress에서는 다국어 문서를 지원합니다. 번역된 마크다운 파일을 각 언어별 디렉토리에 배치하고 VitePress의 `defineConfig`의 `locales` 옵션을 사용할 경우 언어 선택기가 표시되며 각 언어별로 지정된 디렉토리의 문서를 표시합니다.
6 |
7 | ## 페이지 레이아웃 번역 (수동)
8 |
9 | 먼저 VitePress에서는 각종 레이아웃 인터페이스 요소를 번역할 수 있습니다. 여기서 레이아웃은 '이전', '다음', '목차', '테마 변경'과 같은 기능에 대한 관련된 모든 텍스트를 의미합니다. 또한 검색 기능에 표시되는 모든 텍스트 번역을 포함합니다.
10 |
11 | VitePress 페이지에 있는 각종 인터페이스(레이아웃) 텍스트는 `locales`에 언어별로 번역된 텍스트를 제공할 수 있습니다. 예를 들면 다음과 같습니다:
12 |
13 | ```text
14 | "locales": {
15 | "root": {
16 | "lang": "en-US",
17 | "label": "English",
18 | "description": "VitePress Sidebar is a VitePress plugin that automatically generates sidebar menus with one setup and no hassle. Save time by easily creating taxonomies for tons of articles.",
19 | "themeConfig": {
20 | "docFooter": {
21 | "prev": "Previous page",
22 | "next": "Next page"
23 | },
24 | "outline": {
25 | "label": "On this page"
26 | },
27 | "lastUpdated": {
28 | "text": "Last updated"
29 | },
30 | "langMenuLabel": "Change language",
31 | "returnToTopLabel": "Return to top",
32 | "sidebarMenuLabel": "Menu",
33 | "darkModeSwitchLabel": "Appearance",
34 | "lightModeSwitchTitle": "Switch to light theme",
35 | "darkModeSwitchTitle": "Switch to dark theme"
36 | }
37 | },
38 | "ko": {
39 | "lang": "ko-KR",
40 | "label": "한국어",
41 | "description": "VitePress Sidebar는 번거로운 작업 없이 한번의 설정만으로 사이드바 메뉴를 자니다. 수많은 문서에 대한 분류를 손쉽게 만들어 시간을 절약하세요.",
42 | "themeConfig": {
43 | "docFooter": {
44 | "prev": "이전",
45 | "next": "다음"
46 | },
47 | "outline": {
48 | "label": "이 페이지 콘텐츠"
49 | },
50 | "lastUpdated": {
51 | "text": "업데이트 일자"
52 | },
53 | "langMenuLabel": "언어 변경",
54 | "returnToTopLabel": "맨 위로",
55 | "sidebarMenuLabel": "사이드바 메뉴",
56 | "darkModeSwitchLabel": "다크 모드",
57 | "lightModeSwitchTitle": "라이트 모드로 변경",
58 | "darkModeSwitchTitle": "다크 모드로 변경"
59 | }
60 | }
61 | }
62 | ```
63 |
64 | (`root` 언어는 페이지에서 주 언어를 의미합니다.)
65 |
66 | 레이아웃 번역을 자세히 알아보려면 다음 문서를 참고하세요: https://vitepress.dev/ko/guide/i18n
67 |
68 | 검색 기능에 표시되는 텍스트의 경우 `defineConfig`의 `themeConfig.search` 옵션에서 설정해야 합니다. 예를 들면 다음과 같습니다:
69 |
70 | ```text
71 | "themeConfig": {
72 | "search": {
73 | "provider": "local",
74 | "options": {
75 | "locales": {
76 | "root": {
77 | "translations": {
78 | "button": {
79 | "buttonText": "Search",
80 | "buttonAriaLabel": "Search"
81 | },
82 | "modal": {
83 | "displayDetails": "Display detailed list",
84 | "resetButtonTitle": "Reset search",
85 | "backButtonTitle": "Close search",
86 | "noResultsText": "No results for",
87 | "footer": {
88 | "selectText": "to select",
89 | "selectKeyAriaLabel": "enter",
90 | "navigateText": "to navigate",
91 | "navigateUpKeyAriaLabel": "up arrow",
92 | "navigateDownKeyAriaLabel": "down arrow",
93 | "closeText": "to close",
94 | "closeKeyAriaLabel": "escape"
95 | }
96 | }
97 | }
98 | },
99 | "ko": {
100 | "translations": {
101 | "button": {
102 | "buttonText": "검색",
103 | "buttonAriaLabel": "검색"
104 | },
105 | "modal": {
106 | "displayDetails": "상세 목록 표시",
107 | "resetButtonTitle": "검색 초기화",
108 | "backButtonTitle": "검색 닫기",
109 | "noResultsText": "결과를 찾을 수 없음",
110 | "footer": {
111 | "selectText": "선택",
112 | "selectKeyAriaLabel": "선택하기",
113 | "navigateText": "탐색",
114 | "navigateUpKeyAriaLabel": "위로",
115 | "navigateDownKeyAriaLabel": "아래로",
116 | "closeText": "닫기",
117 | "closeKeyAriaLabel": "esc"
118 | }
119 | }
120 | }
121 | }
122 | }
123 | }
124 | }
125 | }
126 | ```
127 |
128 | ## 페이지 레이아웃 번역 (자동)
129 |
130 | VitePress Sidebar의 패밀리 플러그인인 [VitePress I18n](https://vitepress-i18n.cdget.com/ko/)을 사용하면 위와 같이 수동으로 번역하는 과정을 자동화할 수 있습니다. 몇가지 간단한 설정만으로 레이아웃 번역에 시간을 투자하지 않아도 됩니다!
131 |
132 | 아래 명령어로 VitePress I18n 모듈을 설치하세요:
133 |
134 | ```shell
135 | $ npm i -D vitepress-i18n
136 | ```
137 |
138 | 그리고 `defineConfig`에 다음과 같이 설정합니다:
139 |
140 | ```javascript
141 | import { withSidebar } from 'vitepress-sidebar';
142 | import { withI18n } from 'vitepress-i18n';
143 |
144 | const vitePressConfig = {
145 | // VitePress config
146 | };
147 |
148 | const vitePressSidebarConfig = {
149 | // VitePress Sidebar config
150 | };
151 |
152 | const vitePressI18nConfig = {
153 | // VitePress I18n config
154 | locales: ['en', 'ko'], // first locale 'en' is root locale
155 | searchProvider: 'local' // enable search with auto translation
156 | };
157 |
158 | export default defineConfig(
159 | withSidebar(withI18n(vitePressConfig, vitePressI18nConfig), vitePressSidebarConfig)
160 | );
161 | ```
162 |
163 | 이제 인터페이스 번역은 모듈에게 맡기세요! 물론 세부적인 텍스트도 커스터마이징 할 수 있습니다.
164 |
165 | 자세한 내용은 VitePress I18n의 문서 페이지를 읽어주세요: https://vitepress-i18n.cdget.com/ko/guide/getting-started
166 |
167 | ## 언어별 사이드바 설정
168 |
169 | VitePress에서 언어별로 사이드바를 다르게 표시할 수 있습니다. 예를 들면 다음과 같은 폴더 구조를 가지고 있다고 가정해보겠습니다:
170 |
171 | ```text
172 | /
173 | ├─ package.json
174 | ├─ docs/
175 | │ ├─ .vitepress/
176 | │ │ └─ config.js
177 | │ ├─ en/
178 | │ │ └─ abc.md
179 | │ ├─ ko/
180 | │ │ └─ abc.md
181 | │ └─ zhHans/
182 | │ └─ abc.md
183 | └─ ...
184 | ```
185 |
186 | 예시의 `abc.md`는 각 언어로 번역된 같은 문서입니다. 언어를 각각 영어, 한국어, 중국어로 변경할 경우 사이드바는 각 디렉토리 `en`, `ko`, `zhHans`를 스캔하여 언어에 맞는 제목을 가져 올 것입니다.
187 |
188 | 이를 달성하는 예시는 다음과 같습니다:
189 |
190 | ```javascript
191 | const rootLocale = 'en'
192 | const supportedLocales = [rootLocale, 'ko', 'zhHans'];
193 |
194 | const vitePressConfigs = {
195 | rewrites: {
196 | 'en/:rest*': ':rest*'
197 | }
198 | }
199 |
200 | const commonSidebarConfigs = {
201 | // Sidebar common configurations
202 | }
203 |
204 | const vitePressSidebarConfigs = [
205 | ...supportedLocales.map((lang) => {
206 | return {
207 | ...commonSidebarConfigs,
208 | ...(rootLocale === lang ? {} : { basePath: `/${lang}/` }), // If using `rewrites` option
209 | documentRootPath: `/docs/${lang}`,
210 | resolvePath: rootLocale === lang ? '/' : `/${lang}/`,
211 | };
212 | })
213 | ]
214 |
215 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs)
216 | ```
217 |
218 | 먼저 `rewrites`는 root 언어인 영어(`en` 디렉토리)를 사용 중일 때, URI 경로에 `/en/`을 표시하지 않게 해줍니다. (이는 선택사항입니다.)
219 |
220 | 다음으로 `sidebar`의 설정은 기존과 비슷하지만, 각 언어별 디렉토리로 구성된 다중 사이드바를 설정해야 합니다. 각 옵션에 대한 설명은 다음과 같습니다:
221 |
222 | - `basePath`: `rewrites` 규칙과 함께 사용 중일 때 root 로캐일이면 `/en/` 경로를 가리키지 않도록 합니다.
223 | - `documentRootPath`: 실제 문서 파일이 위치한 루트 경로입니다. 각 언어별로 `en`, `ko`, `zhHans` 디렉토리를 찾도록 합니다.
224 | - `resolvePath`: `/docs` 디렉토리로부터 실제로 사이드바 목록을 스캔해야 할 파일의 위치입니다. root 로캐일을 제외하고 각 언어별로 디렉토리 위치를 지정합니다.
225 |
226 | 이렇게 하면 언어 마다 지정한 디렉토리의 문서만 사이드바에서 표시할 수 있도록 합니다. 위는 예시이므로 프로젝트의 규모나 디렉토리 구조에 따라 옵션 설정을 다르게 해야 할 수 있습니다.
227 |
--------------------------------------------------------------------------------
/docs/zhHans/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | ---
4 |
5 | # 入门
6 |
7 | 本页面将指导您安装和使用"VitePress Sidebar"模块。
8 |
9 | ## 安装
10 |
11 | 首先,在使用本模块之前,您可能需要预先配置 **[VitePress](https://vitepress.dev/zh/)**。
12 |
13 | 我们建议使用 **Node.js 20.x** 或更高版本。**VitePress Sidebar**是用`ESM`编写的。要在 "CommonJS" 中使用它,[请参见此处的说明](/zhHans/troubleshooting/err-require-esm)。
14 |
15 | 您需要使用 [NPM](https://www.npmjs.com/package/vitepress-sidebar) 或任何其他 Node 模块包管理器安装该模块。该软件包应安装在 `devDependencies` 中,因为它仅在开发人员环境中使用。使用下面的命令:
16 |
17 | ```shell
18 | # via npm
19 | $ npm i -D vitepress-sidebar
20 |
21 | # via yarn
22 | $ yarn add -D vitepress-sidebar
23 |
24 | # via pnpm
25 | $ pnpm i -D vitepress-sidebar
26 | ```
27 |
28 | ## 工作原理
29 |
30 | VitePress Sidebar 会根据您在项目文件夹中指定的文件夹路径(`documentRootPath`),分层扫描您的文件夹和标记文件。
31 |
32 | 然后,它会根据您的设置对某些文件进行排除、排序和格式化,读取侧边栏菜单的标题,最后根据 VitePress 要求的侧边栏规范输出设置数据。
33 |
34 | 因此,VitePress 的 `config.js` 文件应如下所示
35 |
36 | ```javascript
37 | export default {
38 | themeConfig: {
39 | sidebar: [
40 | // VitePress Sidebar 的输出
41 | {
42 | text: 'Guide',
43 | items: [
44 | { text: 'Introduction', link: '/introduction' },
45 | { text: 'Getting Started', link: '/getting-started' }
46 | ]
47 | }
48 | ]
49 | }
50 | };
51 | ```
52 |
53 | 这样就无需在 “边栏 ”中手动创建每个菜单。
54 |
55 | ## 如何使用
56 |
57 | VitePress Sidebar 可通过两个函数自动生成侧边栏:`withSidebar` 和 `generateSidebar`。它们的行为相同,但在何处使用这两个函数却不同。一般来说,我们建议使用`withSidebar`。
58 |
59 | 要将安装的模块导入代码,请打开VitePress的`config.js`文件。请注意,该文件位于`.vitepress`目录下,扩展名可能有所不同,具体取决于您的项目。
60 |
61 | 文件,并以以下两种方式之一使用 `vitepress-sidebar`.
62 |
63 | ### 1. 使用 `withSidebar`(推荐)
64 |
65 | `withSidebar` 用于 `defineConfig` 级别。请注意,VitePress 的配置对象应放在第一个参数中,VitePress 侧边栏的选项应放在第二个参数中。
66 |
67 | VitePress 侧边栏将覆盖 VitePress 中现有选项所需的任何附加选项。 您已手动设置的任何 `sidebar` 选项都将被新选项覆盖。
68 |
69 | ```javascript
70 | // `.vitepress/config.js`
71 | import { withSidebar } from 'vitepress-sidebar';
72 |
73 | const vitePressOptions = {
74 | // VitePress's options here...
75 | title: 'VitePress Sidebar',
76 | themeConfig: {
77 | // ...
78 | }
79 | };
80 |
81 | const vitePressSidebarOptions = {
82 | // VitePress Sidebar's options here...
83 | documentRootPath: '/',
84 | collapsed: false,
85 | capitalizeFirst: true
86 | };
87 |
88 | export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));
89 | ```
90 |
91 | ### 2. 使用 `generateSidebar`
92 |
93 | `generateSidebar` 在`themeConfig.sidebar`级别可用。当需要对更详细的 `themeConfig` 设置进行代码分离时,可以使用此功能。
94 |
95 | ```javascript
96 | // `.vitepress/config.js`
97 | import { generateSidebar } from 'vitepress-sidebar';
98 |
99 | export default defineConfig({
100 | themeConfig: {
101 | sidebar: generateSidebar({
102 | // VitePress Sidebar's options here...
103 | })
104 | }
105 | });
106 | ```
107 |
108 | 要扫描您的项目文档,VitePress Sidebar需要通过 `documentRootPath` 选项指定工作路径来了解正确的位置。默认是`/`,但如果你的VitePress项目位于一个单独的文件夹中,如`docs`,根据你的项目,你将需要自己指定路径。
109 |
110 | 根据项目根路径,`documentRootPath` 中的路径将写入 `.vitePress` 文件夹所在的路径。
111 |
112 | ```text
113 | /
114 | ├─ package.json
115 | ├─ src/
116 | ├─ docs/ <--------------- `documentRootPath` ('/docs')
117 | │ ├─ .vitepress/
118 | │ ├─ another-directory/
119 | │ ├─ hello.md
120 | │ └─ index.md
121 | └─ ...
122 | ```
123 |
124 | 如果您的项目结构如上,则需要这样设置:
125 |
126 | ```javascript
127 | // `.vitepress/config.js`
128 | import { withSidebar } from 'vitepress-sidebar';
129 |
130 | const vitePressOptions = {};
131 |
132 | const vitePressSidebarOptions = {
133 | documentRootPath: '/docs'
134 | };
135 |
136 | export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));
137 | ```
138 |
139 | 要测试侧边栏结果如何打印,请在构建 VitePress 时将 `debugPrint` 选项设置为 `true`。你应该能在控制台中看到输出结果。
140 |
141 | 有关 VitePress Sidebar 配置的更多信息,请参阅下面的 **[选项](/zhHans/guide/options)** 部分。
142 |
143 | ## 代码示例
144 |
145 | ```javascript
146 | import { withSidebar } from 'vitepress-sidebar';
147 |
148 | const vitePressConfigs = {
149 | title: 'VitePress Sidebar',
150 | themeConfig: {
151 | // ...
152 | }
153 | };
154 |
155 | export default defineConfig(
156 | withSidebar(vitePressConfigs, {
157 | /*
158 | * 有关详细说明,请参阅下面的链接:
159 | * https://vitepress-sidebar.cdget.com/zhHans/guide/options
160 | */
161 | //
162 | // ============ [ RESOLVING PATHS ] ============
163 | // documentRootPath: '/',
164 | // scanStartPath: null,
165 | // resolvePath: null,
166 | // basePath: null,
167 | // followSymlinks: false,
168 | //
169 | // ============ [ GROUPING ] ============
170 | // collapsed: true,
171 | // collapseDepth: 2,
172 | // rootGroupText: 'Contents',
173 | // rootGroupLink: 'https://github.com/jooy2',
174 | // rootGroupCollapsed: false,
175 | //
176 | // ============ [ GETTING MENU TITLE ] ============
177 | // useTitleFromFileHeading: true,
178 | // useTitleFromFrontmatter: true,
179 | // useFolderLinkFromIndexFile: false,
180 | // useFolderTitleFromIndexFile: false,
181 | // frontmatterTitleFieldName: 'title',
182 | //
183 | // ============ [ GETTING MENU LINK ] ============
184 | // useFolderLinkFromSameNameSubFile: false,
185 | // useFolderLinkFromIndexFile: false,
186 | // folderLinkNotIncludesFileName: false,
187 | //
188 | // ============ [ INCLUDE / EXCLUDE ] ============
189 | // excludeByGlobPattern: ['README.md', 'folder/'],
190 | // excludeFilesByFrontmatterFieldName: 'exclude',
191 | // excludeByFolderDepth: undefined,
192 | // includeDotFiles: false,
193 | // includeEmptyFolder: false,
194 | // includeRootIndexFile: false,
195 | // includeFolderIndexFile: false,
196 | //
197 | // ============ [ STYLING MENU TITLE ] ============
198 | // hyphenToSpace: true,
199 | // underscoreToSpace: true,
200 | // capitalizeFirst: false,
201 | // capitalizeEachWords: false,
202 | // keepMarkdownSyntaxFromTitle: false,
203 | // removePrefixAfterOrdering: false,
204 | // prefixSeparator: '.',
205 | //
206 | // ============ [ SORTING ] ============
207 | // manualSortFileNameByPriority: ['first.md', 'second', 'third.md'],
208 | // sortFolderTo: null,
209 | // sortMenusByName: false,
210 | // sortMenusByFileDatePrefix: false,
211 | // sortMenusByFrontmatterOrder: false,
212 | // frontmatterOrderDefaultValue: 0,
213 | // sortMenusByFrontmatterDate: false,
214 | // sortMenusOrderByDescending: false,
215 | // sortMenusOrderNumericallyFromTitle: false,
216 | // sortMenusOrderNumericallyFromLink: false,
217 | //
218 | // ============ [ MISC ] ============
219 | // debugPrint: false,
220 | })
221 | );
222 | ```
223 |
224 | ## 输出示例
225 |
226 | ```text
227 | {
228 | documentRootPath: 'javascript',
229 | useTitleFromFileHeading: true,
230 | hyphenToSpace: true,
231 | excludeByGlobPattern: ['vitepress-how-to']
232 | }
233 |
234 | /*
235 | [
236 | {
237 | text: 'examples',
238 | items: [
239 | {
240 | text: 'Examples',
241 | link: '/javascript/examples/examples'
242 | }
243 | ]
244 | },
245 | {
246 | text: 'functions',
247 | items: [
248 | {
249 | text: 'prototypes',
250 | items: [
251 | {
252 | text: 'Array',
253 | items: [
254 | {
255 | text: 'Array.indexOf',
256 | link: '/javascript/functions/prototypes/Array/Array.indexOf'
257 | }
258 | ]
259 | }
260 | ]
261 | }
262 | ]
263 | },
264 | {
265 | text: 'Getting Started',
266 | link: '/javascript/getting_started'
267 | }
268 | ];
269 | */
270 | ```
271 |
--------------------------------------------------------------------------------
/docs/ko/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | ---
4 |
5 | # 시작하기
6 |
7 | 이 페이지에서는 VitePress Sidebar 모듈의 설치 및 사용 방법을 안내합니다.
8 |
9 | ## 설치
10 |
11 | 먼저 이 모듈을 사용하기 전에 **[VitePress](https://vitepress.dev/ko/)** 모듈을 사전 구성해야 할 수 있습니다.
12 |
13 | Node.js 버전은 20.x 이상을 사용하는 것이 좋습니다. **VitePress Sidebar**는 `ESM`으로 작성되었습니다. CommonJS 환경에서 사용하려면 [여기 지침을 참조하세요](/ko/troubleshooting/err-require-esm).
14 |
15 | [NPM](https://www.npmjs.com/package/vitepress-sidebar) 또는 다른 노드 모듈 패키지 관리자를 사용하여 모듈을 설치할 수 있습니다. 이 패키지는 개발자 환경에서만 사용되므로 `devDependencies`에 설치해야 합니다. 아래 명령어로 설치하세요:
16 |
17 | ```shell
18 | # `npm`으로 설치
19 | $ npm i -D vitepress-sidebar
20 |
21 | # `yarn`으로 설치
22 | $ yarn add -D vitepress-sidebar
23 |
24 | # `pnpm`으로 설치
25 | $ pnpm i -D vitepress-sidebar
26 | ```
27 |
28 | ## 동작 과정
29 |
30 | VitePress Sidebar는 귀하의 프로젝트의 폴더에서 지정한 폴더 경로(`documentRootPath`)를 기준으로 폴더와 마크다운 파일을 계층별로 스캔합니다.
31 |
32 | 이후 설정에 따라 특정 파일을 제외, 정렬, 포맷팅하여 사이드바 메뉴의 제목을 읽어온 후 VitePress에서 요구하는 사이드바 스펙에 따라 설정 데이터를 최종적으로 출력하게 됩니다.
33 |
34 | 결과적으로는 VitePress의 `config.js` 파일은 다음과 같이 변환 될 것입니다.
35 |
36 | ```javascript
37 | export default {
38 | themeConfig: {
39 | sidebar: [
40 | // VitePress Sidebar의 출력 결과
41 | {
42 | text: 'Guide',
43 | items: [
44 | { text: 'Introduction', link: '/introduction' },
45 | { text: 'Getting Started', link: '/getting-started' }
46 | ]
47 | }
48 | ]
49 | }
50 | };
51 | ```
52 |
53 | 이로 인해 `sidebar`의 각 메뉴에 대한 수동 작성이 필요하지 않습니다.
54 |
55 | ## 사용 방법
56 |
57 | VitePress Sidebar는 `withSidebar`와 `generateSidebar` 두가지 함수로 사이드 바를 자동으로 생성할 수 있습니다. 이 둘의 동작은 같지만 함수를 사용하는 위치가 다릅니다. 일반적으로는 `withSidebar`를 사용하는 것을 권장합니다.
58 |
59 | 설치한 모듈을 코드에 가져오려면 VitePress의 `config.js` 파일을 엽니다. 이 파일은 `.vitepress` 디렉토리에 위치하며 프로젝트에 따라 다른 확장자의 이름일 수 있으니 유의하시기 바랍니다.
60 |
61 | 파일을 열고 아래 두가지 방법 중 하나를 사용하여 `vitepress-sidebar`를 사용할 수 있습니다:
62 |
63 | ### 1. `withSidebar` 사용 (권장)
64 |
65 | `withSidebar`는 `defineConfig`레벨에서 사용합니다. 이 때 주의할 점은 VitePress의 설정 객체가 첫번째 파라미터에, 이후 VitePress Sidebar의 옵션이 두번째 파라미터에 위치해야 합니다.
66 |
67 | VitePress Sidebar는 기존 VitePress의 옵션에 필요한 추가 옵션을 오버라이딩 할 것입니다. 기존에 설정한 수동 `sidebar` 옵션은 새 옵션에 의해 무시됩니다.
68 |
69 | ```javascript
70 | // `.vitepress/config.js`
71 | import { withSidebar } from 'vitepress-sidebar';
72 |
73 | const vitePressOptions = {
74 | // VitePress의 옵션
75 | title: 'VitePress Sidebar',
76 | themeConfig: {
77 | // ...
78 | }
79 | };
80 |
81 | const vitePressSidebarOptions = {
82 | // VitePress Sidebar의 옵션
83 | documentRootPath: '/',
84 | collapsed: false,
85 | capitalizeFirst: true
86 | };
87 |
88 | export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));
89 | ```
90 |
91 | ### 2. `generateSidebar` 사용
92 |
93 | `generateSidebar`는 `themeConfig.sidebar` 레벨에서 사용할 수 있습니다. 이는 좀 더 세부적인 `themeConfig` 설정을 위해 코드 분리가 필요할 때 사용할 수 있습니다.
94 |
95 | ```javascript
96 | // `.vitepress/config.js`
97 | import { generateSidebar } from 'vitepress-sidebar';
98 |
99 | export default defineConfig({
100 | themeConfig: {
101 | sidebar: generateSidebar({
102 | // VitePress Sidebar의 옵션
103 | })
104 | }
105 | });
106 | ```
107 |
108 | VitePress Sidebar는 프로젝트의 문서를 스캔하기 위해 `documentRootPath` 옵션으로 작업 경로를 지정하여 올바른 위치를 알려주어야 합니다. 기본값은 `/`이지만 프로젝트에 따라 `docs`와 같이 별도의 폴더에 VitePress 프로젝트가 위치하는 경우에는 직접 경로를 지정해야 합니다.
109 |
110 | 프로젝트 루트 경로를 기준으로, `documentRootPath`의 경로는 `.vitePress` 폴더가 위치한 경로를 작성합니다.
111 |
112 | ```text
113 | /
114 | ├─ package.json
115 | ├─ src/
116 | ├─ docs/ <--------------- `documentRootPath` ('/docs')
117 | │ ├─ .vitepress/
118 | │ ├─ another-directory/
119 | │ ├─ hello.md
120 | │ └─ index.md
121 | └─ ...
122 | ```
123 |
124 | 위와 같은 구조의 프로젝트인 경우 아래와 같이 설정해야 합니다:
125 |
126 | ```javascript
127 | // `.vitepress/config.js`
128 | import { withSidebar } from 'vitepress-sidebar';
129 |
130 | const vitePressOptions = {};
131 |
132 | const vitePressSidebarOptions = {
133 | documentRootPath: '/docs'
134 | };
135 |
136 | export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));
137 | ```
138 |
139 | 사이드바 결과가 어떻게 출력되는지 테스트하려면 `debugPrint` 옵션을 `true`로 설정하여 VitePress를 빌드해 보세요. 콘솔에 출력이 표시될 것입니다.
140 |
141 | VitePress Sidebar의 설정에 대한 자세한 내용은 아래 **[옵션](/ko/guide/options)** 섹션을 참조하세요.
142 |
143 | ## 코드 예시
144 |
145 | ```javascript
146 | import { withSidebar } from 'vitepress-sidebar';
147 |
148 | const vitePressConfigs = {
149 | title: 'VitePress Sidebar',
150 | themeConfig: {
151 | // ...
152 | }
153 | };
154 |
155 | export default defineConfig(
156 | withSidebar(vitePressConfigs, {
157 | /*
158 | * 자세한 지침은 아래 링크를 참조하세요:
159 | * https://vitepress-sidebar.cdget.com/guide/options
160 | */
161 | //
162 | // ============ [ RESOLVING PATHS ] ============
163 | // documentRootPath: '/',
164 | // scanStartPath: null,
165 | // resolvePath: null,
166 | // basePath: null,
167 | // followSymlinks: false,
168 | //
169 | // ============ [ GROUPING ] ============
170 | // collapsed: true,
171 | // collapseDepth: 2,
172 | // rootGroupText: 'Contents',
173 | // rootGroupLink: 'https://github.com/jooy2',
174 | // rootGroupCollapsed: false,
175 | //
176 | // ============ [ GETTING MENU TITLE ] ============
177 | // useTitleFromFileHeading: true,
178 | // useTitleFromFrontmatter: true,
179 | // useFolderLinkFromIndexFile: false,
180 | // useFolderTitleFromIndexFile: false,
181 | // frontmatterTitleFieldName: 'title',
182 | //
183 | // ============ [ GETTING MENU LINK ] ============
184 | // useFolderLinkFromSameNameSubFile: false,
185 | // useFolderLinkFromIndexFile: false,
186 | // folderLinkNotIncludesFileName: false,
187 | //
188 | // ============ [ INCLUDE / EXCLUDE ] ============
189 | // excludeByGlobPattern: ['README.md', 'folder/'],
190 | // excludeFilesByFrontmatterFieldName: 'exclude',
191 | // excludeByFolderDepth: undefined,
192 | // includeDotFiles: false,
193 | // includeEmptyFolder: false,
194 | // includeRootIndexFile: false,
195 | // includeFolderIndexFile: false,
196 | //
197 | // ============ [ STYLING MENU TITLE ] ============
198 | // hyphenToSpace: true,
199 | // underscoreToSpace: true,
200 | // capitalizeFirst: false,
201 | // capitalizeEachWords: false,
202 | // keepMarkdownSyntaxFromTitle: false,
203 | // removePrefixAfterOrdering: false,
204 | // prefixSeparator: '.',
205 | //
206 | // ============ [ SORTING ] ============
207 | // manualSortFileNameByPriority: ['first.md', 'second', 'third.md'],
208 | // sortFolderTo: null,
209 | // sortMenusByName: false,
210 | // sortMenusByFileDatePrefix: false,
211 | // sortMenusByFrontmatterOrder: false,
212 | // frontmatterOrderDefaultValue: 0,
213 | // sortMenusByFrontmatterDate: false,
214 | // sortMenusOrderByDescending: false,
215 | // sortMenusOrderNumericallyFromTitle: false,
216 | // sortMenusOrderNumericallyFromLink: false,
217 | //
218 | // ============ [ MISC ] ============
219 | // debugPrint: false,
220 | })
221 | );
222 | ```
223 |
224 | ## 출력 예시
225 |
226 | ```text
227 | {
228 | documentRootPath: 'javascript',
229 | useTitleFromFileHeading: true,
230 | hyphenToSpace: true,
231 | excludeByGlobPattern: ['vitepress-how-to']
232 | }
233 |
234 | /*
235 | [
236 | {
237 | text: 'examples',
238 | items: [
239 | {
240 | text: 'Examples',
241 | link: '/javascript/examples/examples'
242 | }
243 | ]
244 | },
245 | {
246 | text: 'functions',
247 | items: [
248 | {
249 | text: 'prototypes',
250 | items: [
251 | {
252 | text: 'Array',
253 | items: [
254 | {
255 | text: 'Array.indexOf',
256 | link: '/javascript/functions/prototypes/Array/Array.indexOf'
257 | }
258 | ]
259 | }
260 | ]
261 | }
262 | ]
263 | },
264 | {
265 | text: 'Getting Started',
266 | link: '/javascript/getting_started'
267 | }
268 | ];
269 | */
270 | ```
271 |
--------------------------------------------------------------------------------
/docs/en/advanced-usage/multiple-sidebars-how-to.md:
--------------------------------------------------------------------------------
1 | # Multiple Sidebars How-to
2 |
3 | Multiple sidebars is a feature that allows you to display different sidebar menus based on a specific URI path.
4 |
5 | This is easily implemented in `vitepress-sidebar` with a few simple settings. In the end, **VitePress** will output the options as intended.
6 |
7 | To learn more about Multiple sidebars first, we recommend taking a look at **VitePress'** official documentation below:
8 |
9 | https://vitepress.dev/reference/default-theme-sidebar#multiple-sidebars
10 |
11 | ## Basic usage
12 |
13 | First, let's assume you have a root project called `docs` with subdirectories called `guide` and `config`, like this:
14 |
15 | ```text
16 | docs/
17 | ├─ guide/
18 | │ ├─ index.md
19 | │ ├─ one.md
20 | │ ├─ two.md
21 | │ └─ do-not-include.md
22 | └─ config/
23 | ├─ index.md
24 | ├─ three.md
25 | └─ four.md
26 | ```
27 |
28 | When the URL is located on a `/guide` page, the user wants the menu to show only the submenu of `guide` and hide the submenu of `config`. Similarly, you want to hide the submenu of `guide` when it is located on the `/config` page.
29 |
30 | To implement this in `vitepress-sidebar`, you need to approach it differently from the existing setup.
31 |
32 | Use the `withSidebar` function as before, but pass an array. The array will contain at least one option from `vitepress-sidebar`. The values in the array can be as many URLs as you want to specify. Of course, you can also configure them with different settings.
33 |
34 | ```javascript
35 | // Must pass array arguments!!!!
36 | const vitePressConfigs = {
37 | /* ... */
38 | };
39 |
40 | export default defineConfig(
41 | withSidebar(vitePressConfigs, [
42 | {
43 | documentRootPath: 'docs',
44 | scanStartPath: 'guide',
45 | basePath: '/guide/',
46 | resolvePath: '/guide/',
47 | useTitleFromFileHeading: true
48 | },
49 | {
50 | documentRootPath: 'docs',
51 | scanStartPath: 'config',
52 | resolvePath: '/config/',
53 | useTitleFromFrontmatter: true
54 | }
55 | ])
56 | );
57 | ```
58 |
59 | The values of these options are used in the results as follows:
60 |
61 | ```text
62 | {
63 | : [
64 | {
65 | base: ,
66 | items: [...] // `/path/to/items`
67 | }
68 | ]
69 | }
70 | ```
71 |
72 | Here's an example of the output from the above setup:
73 |
74 | ```json5
75 | {
76 | '/guide/': {
77 | base: '/guide/',
78 | items: [
79 | {
80 | text: 'One',
81 | link: 'one'
82 | },
83 | {
84 | text: 'Two',
85 | link: 'two'
86 | }
87 | ]
88 | },
89 | '/config/': {
90 | base: '/config/',
91 | items: [
92 | {
93 | text: 'Three',
94 | link: 'three'
95 | },
96 | {
97 | text: 'Four',
98 | link: 'four'
99 | }
100 | ]
101 | }
102 | }
103 | ```
104 |
105 | ## Multiple sidebar options
106 |
107 | The following options are available in Multiple sidebars: `scanStartPath`, `basePath`, and `resolvePath`. Each option is optional, but should be able to be used correctly depending on the situation.
108 |
109 | Each option is described below. However, we recommend that you first refer to the descriptions of each option on the [Options](/guide/options) page.
110 |
111 | The descriptions below are based on the following examples:
112 |
113 | ```text
114 | docs/
115 | ├─ .vitepress/
116 | ├─ guide/
117 | │ ├─ api/
118 | │ │ ├─ api-one.md
119 | │ │ └─ api-two.md
120 | │ ├─ one.md
121 | │ └─ two.md
122 | └─ config/
123 | ├─ index.md
124 | ├─ three.md
125 | └─ four.md
126 | ```
127 |
128 | ### `scanStartPath`
129 |
130 | This option is used to specify different directories as root paths for different routing rules. While `documentRootPath` is the root path that will actually be scanned (where the `.vitepress` directory is located), `scanStartPath` is the root path that should actually be seen in this route rule.
131 |
132 | For example, to include only files in the `/guide` directory, specify the value of `scanStartPath` as `guide`. However, the path in `documentRootPath` should not be included.
133 |
134 | ### `resolvePath`
135 |
136 | This option is used by VitePress to display the relevant menu when it encounters a specific URI. For example, if you want to display only the contents of the `guide/api` directory when reaching `example.com/guide/api`, the value of `resolvePath` would be `/guide/api`. It is recommended that you include `/` in front of the path.
137 |
138 | This will usually have a similar value to `scanStartPath`, but sometimes you may need to specify it differently for **i18n** routing.
139 |
140 | ### `basePath`
141 |
142 | This option is primarily utilized when working with VitePress' rewrite rules, and is optional otherwise.
143 |
144 | It replaces the value of the `base` path in VitePress. If this value is not specified, the value of `resolvePath` or the root path (`/`) is specified.
145 |
146 | If the actual path to the directory is different from the path structure in the URI, you should be able to navigate to the page provided by rewrite. Typically, the sidebar will generate a path based on the root directory and will not reference the rewrite path in VitePress.
147 |
148 | For example, suppose you have a rewrite rule that looks like this:
149 |
150 | ```javascript
151 | const vitePressConfigs = {
152 | rewrites: {
153 | 'guide/:page': 'help/:page'
154 | }
155 | };
156 |
157 | const vitePressSidebarConfigs = [
158 | {
159 | documentRootPath: 'docs',
160 | scanStartPath: 'guide',
161 | resolvePath: '/guide/'
162 | }
163 | ];
164 |
165 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
166 | ```
167 |
168 | The `guide/one.md` document is displayed in the path to `help/one`. However, if you do this, the sidebar will not display the menu because it will try to find `help/one`, which is the path as it is.
169 |
170 | To fix this, change the path in `basePath` to `help`:
171 |
172 | ```javascript
173 | const vitePressConfigs = {
174 | rewrites: {
175 | 'guide/:page': 'help/:page'
176 | }
177 | };
178 |
179 | const vitePressSidebarConfigs = [
180 | {
181 | documentRootPath: 'docs',
182 | scanStartPath: 'guide',
183 | basePath: 'help', // <---------------------- Add this
184 | resolvePath: '/guide/'
185 | }
186 | ];
187 |
188 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
189 | ```
190 |
191 | ## Displaying menus with complex paths and URIs
192 |
193 | The above example is typically when the path is defined in steps, but when you want to show folders that are deep in steps, especially when the URI is shorter or uses different conventions than the actual folder path, you need to use additional methods. For example, you have a folder structure like this:
194 |
195 | ```text
196 | docs/
197 | ├─ guide/
198 | │ ├─ api/
199 | │ │ ├─ api-one.md
200 | │ │ └─ api-two.md
201 | │ ├─ one.md
202 | │ └─ two.md
203 | └─ config/
204 | ├─ index.md
205 | ├─ three.md
206 | └─ four.md
207 | ```
208 |
209 | This time, we want to show the menu in `docs/guide/api` when we reach the one-level URI `/api`. The expected menu is to show only `api-one.md` and `api-two.md`.
210 |
211 | ```javascript
212 | withSidebar([
213 | {
214 | documentRootPath: 'docs',
215 | scanStartPath: 'guide/api',
216 | resolvePath: '/api/'
217 | }
218 | ]);
219 | ```
220 |
221 | However, if you configure the options like this, you won't be able to display the menu, because the `api` directory is a subdirectory of `guide`. **VitePress** won't detect this and will navigate to a non-existent document.
222 |
223 | To solve this, you need to use **VitePress'** Routing feature in parallel, see the article below for an explanation:
224 |
225 | https://vitepress.dev/guide/routing#route-rewrites
226 |
227 | Add the `rewrites` option to the VitePress settings in `defineConfig` following the example above:
228 |
229 | ```javascript
230 | const vitePressConfigs = {
231 | /* [START] Add This */
232 | rewrites: {
233 | 'guide/api/:page': 'api/:page'
234 | }
235 | /* [END] Add This */
236 | };
237 |
238 | const vitePressSidebarConfigs = {
239 | documentRootPath: 'docs',
240 | scanStartPath: 'guide/api',
241 | resolvePath: '/api/'
242 | };
243 |
244 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs));
245 | ```
246 |
247 | Now this will show a submenu of `docs/guide/api` when the URI path starts with `/api`!
248 |
--------------------------------------------------------------------------------
/docs/en/advanced-usage/internationalization.md:
--------------------------------------------------------------------------------
1 | # Internationalization
2 |
3 | This page describes how to achieve internationalization (i18n) using VitePress Sidebar.
4 |
5 | VitePress supports multilingual documentation. If you place translated markdown files in a directory for each language and use the `locales` option in VitePress's `defineConfig`, a language selector will be displayed and will show documents in the specified directory for each language.
6 |
7 | ## Translate page layouts (manually)
8 |
9 | First, VitePress allows you to translate various layout interface elements. By layout, we mean all the associated text for features like 'Previous', 'Next', 'Table of Contents', and 'Change Theme'. It also includes translating any text that appears in the search function.
10 |
11 | Various interface (layout) texts on a VitePress page can provide language-specific translations for `locales`. For example
12 |
13 | ```text
14 | "locales": {
15 | "root": {
16 | "lang": "en-US",
17 | "label": "English",
18 | "description": "VitePress Sidebar is a VitePress plugin that automatically generates sidebar menus with one setup and no hassle. Save time by easily creating taxonomies for tons of articles.",
19 | "themeConfig": {
20 | "docFooter": {
21 | "prev": "Previous page",
22 | "next": "Next page"
23 | },
24 | "outline": {
25 | "label": "On this page"
26 | },
27 | "lastUpdated": {
28 | "text": "Last updated"
29 | },
30 | "langMenuLabel": "Change language",
31 | "returnToTopLabel": "Return to top",
32 | "sidebarMenuLabel": "Menu",
33 | "darkModeSwitchLabel": "Appearance",
34 | "lightModeSwitchTitle": "Switch to light theme",
35 | "darkModeSwitchTitle": "Switch to dark theme"
36 | }
37 | },
38 | "ko": {
39 | "lang": "ko-KR",
40 | "label": "한국어",
41 | "description": "VitePress Sidebar는 번거로운 작업 없이 한번의 설정만으로 사이드바 메뉴를 자니다. 수많은 문서에 대한 분류를 손쉽게 만들어 시간을 절약하세요.",
42 | "themeConfig": {
43 | "docFooter": {
44 | "prev": "이전",
45 | "next": "다음"
46 | },
47 | "outline": {
48 | "label": "이 페이지 콘텐츠"
49 | },
50 | "lastUpdated": {
51 | "text": "업데이트 일자"
52 | },
53 | "langMenuLabel": "언어 변경",
54 | "returnToTopLabel": "맨 위로",
55 | "sidebarMenuLabel": "사이드바 메뉴",
56 | "darkModeSwitchLabel": "다크 모드",
57 | "lightModeSwitchTitle": "라이트 모드로 변경",
58 | "darkModeSwitchTitle": "다크 모드로 변경"
59 | }
60 | }
61 | }
62 | ```
63 |
64 | (The `root` language is the primary language on the page).
65 |
66 | To learn more about translating layouts, see the following articles: https://vitepress.dev/guide/i18n
67 |
68 | For the text that appears in the search function, you need to set it in the `themeConfig.search` option in `defineConfig`, for example
69 |
70 | ```text
71 | "themeConfig": {
72 | "search": {
73 | "provider": "local",
74 | "options": {
75 | "locales": {
76 | "root": {
77 | "translations": {
78 | "button": {
79 | "buttonText": "Search",
80 | "buttonAriaLabel": "Search"
81 | },
82 | "modal": {
83 | "displayDetails": "Display detailed list",
84 | "resetButtonTitle": "Reset search",
85 | "backButtonTitle": "Close search",
86 | "noResultsText": "No results for",
87 | "footer": {
88 | "selectText": "to select",
89 | "selectKeyAriaLabel": "enter",
90 | "navigateText": "to navigate",
91 | "navigateUpKeyAriaLabel": "up arrow",
92 | "navigateDownKeyAriaLabel": "down arrow",
93 | "closeText": "to close",
94 | "closeKeyAriaLabel": "escape"
95 | }
96 | }
97 | }
98 | },
99 | "ko": {
100 | "translations": {
101 | "button": {
102 | "buttonText": "검색",
103 | "buttonAriaLabel": "검색"
104 | },
105 | "modal": {
106 | "displayDetails": "상세 목록 표시",
107 | "resetButtonTitle": "검색 초기화",
108 | "backButtonTitle": "검색 닫기",
109 | "noResultsText": "결과를 찾을 수 없음",
110 | "footer": {
111 | "selectText": "선택",
112 | "selectKeyAriaLabel": "선택하기",
113 | "navigateText": "탐색",
114 | "navigateUpKeyAriaLabel": "위로",
115 | "navigateDownKeyAriaLabel": "아래로",
116 | "closeText": "닫기",
117 | "closeKeyAriaLabel": "esc"
118 | }
119 | }
120 | }
121 | }
122 | }
123 | }
124 | }
125 | }
126 | ```
127 |
128 | ## Translate page layouts (automatic)
129 |
130 | [VitePress I18n](https://vitepress-i18n.cdget.com), a family plugin of VitePress Sidebar, allows you to automate the process of translating manually like above. With a few simple settings, you can stop spending hours translating layouts!
131 |
132 | Install the VitePress I18n module with the command below:
133 |
134 | ```shell
135 | $ npm i -D vitepress-i18n
136 | ```
137 |
138 | And in `defineConfig`, set the following:
139 |
140 | ```javascript
141 | import { withSidebar } from 'vitepress-sidebar';
142 | import { withI18n } from 'vitepress-i18n';
143 |
144 | const vitePressConfig = {
145 | // VitePress config
146 | };
147 |
148 | const vitePressSidebarConfig = {
149 | // VitePress Sidebar config
150 | };
151 |
152 | const vitePressI18nConfig = {
153 | // VitePress I18n config
154 | locales: ['en', 'ko'], // first locale 'en' is root locale
155 | searchProvider: 'local' // enable search with auto translation
156 | };
157 |
158 | export default defineConfig(
159 | withSidebar(withI18n(vitePressConfig, vitePressI18nConfig), vitePressSidebarConfig)
160 | );
161 | ```
162 |
163 | Now leave the interface translation to the module! Of course, you can customize the detailed text as well.
164 |
165 | For more information, read the documentation page for VitePress I18n: https://vitepress-i18n.cdget.com/guide/getting-started
166 |
167 | ## Language-specific sidebar settings
168 |
169 | In VitePress, you can display the sidebar differently for different languages. For example, let's say you have a folder structure like this
170 |
171 | ```text
172 | /
173 | ├─ package.json
174 | ├─ docs/
175 | │ ├─ .vitepress/
176 | │ │ └─ config.js
177 | │ ├─ en/
178 | │ │ └─ abc.md
179 | │ ├─ ko/
180 | │ │ └─ abc.md
181 | │ └─ zhHans/
182 | │ └─ abc.md
183 | └─ ...
184 | ```
185 |
186 | In the example, `abc.md` is the same document translated into each language. If you change the language to English, Korean, and Chinese respectively, the sidebar will scan each directory `en`, `ko`, and `zhHans` to get the title for the language.
187 |
188 | Here's an example of how to accomplish this:
189 |
190 | ```javascript
191 | const rootLocale = 'en'
192 | const supportedLocales = [rootLocale, 'ko', 'zhHans'];
193 |
194 | const vitePressConfigs = {
195 | rewrites: {
196 | 'en/:rest*': ':rest*'
197 | }
198 | }
199 |
200 | const commonSidebarConfigs = {
201 | // Sidebar common configurations
202 | }
203 |
204 | const vitePressSidebarConfigs = [
205 | ...supportedLocales.map((lang) => {
206 | return {
207 | ...commonSidebarConfigs,
208 | ...(rootLocale === lang ? {} : { basePath: `/${lang}/` }), // If using `rewrites` option
209 | documentRootPath: `/docs/${lang}`,
210 | resolvePath: rootLocale === lang ? '/' : `/${lang}/`,
211 | };
212 | })
213 | ]
214 |
215 | export default defineConfig(withSidebar(vitePressConfigs, vitePressSidebarConfigs)
216 | ```
217 |
218 | First, `rewrites` allows you to suppress `/en/` in the URI path when you are using English as the root language (the `en` directory). (This is optional.)
219 |
220 | Next, the setup of `sidebar` is similar to the previous one, but you need to set up multiple sidebars with directories for each language. Here's a description of each option:
221 |
222 | - `basePath`: When used in conjunction with the `rewrites` rule, it prevents the root locale from pointing to the `/en/` path.
223 | - `documentRootPath`: The root path where the actual documentation files are located. For each language, look for the `en`, `ko`, and `zhHans` directories.
224 | - `resolvePath`: `/docs` The location of the file from the directory that should actually scan the sidebar listings. Specify the directory location for each language, excluding the root locale.
225 |
226 | This ensures that the sidebar only displays articles from the specified directory per language. The above is an example, so you may need to set the options differently depending on the size of your project or directory structure.
227 |
--------------------------------------------------------------------------------
/docs/zhHans/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | title: VitePress Sidebar
5 | titleTemplate: 功能强大的自动侧边栏生成器
6 |
7 | hero:
8 | name: VitePress Sidebar
9 | text: 功能强大的自动侧边栏生成器
10 | tagline: VitePress自动侧边栏插件,可自动创建一个简单的配置
11 | actions:
12 | - theme: brand
13 | text: 入门
14 | link: /zhHans/guide/getting-started
15 | - theme: alt
16 | text: 选项
17 | link: /zhHans/guide/options
18 | - theme: alt
19 | text: GitHub
20 | link: https://github.com/jooy2/vitepress-sidebar
21 | image:
22 | src: /sidebar.png
23 | alt: Sidebar
24 |
25 | features:
26 | - icon:
27 | title: 与 VitePress 的最佳搭配
28 | details: 针对最新版本的VitePress进行了优化。
29 | - icon:
30 | title: 轻松配置细粒度侧边栏
31 | details: 简单易用,大量选项可按你的喜好自定义。自定义菜单可用于排序、特殊字符转换、文件和文件夹过滤器等!
32 | - icon:
33 | title: 可广泛扩展的用例
34 | details: 支持多个侧边栏、Frontmatter 和 TypeScript,以处理各种使用情况。
35 | - icon:
36 | title: 可靠的维护支持
37 | details: 我们的下载量超过 2K+,在现实世界中有许多使用案例,而且我们拥有快速的技术支持。
38 | ---
39 |
40 |
61 |
--------------------------------------------------------------------------------
/docs/en/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | ---
4 |
5 | # Getting Started
6 |
7 | This page walks you through the installation and use of the VitePress Sidebar module.
8 |
9 | ## Installation
10 |
11 | First, you may need to pre-configure **[VitePress](https://vitepress.dev)** before using this module.
12 |
13 | We recommend using **Node.js 20.x** or higher. The **VitePress Sidebar** is written in `ESM`. To use it in `CommonJS`, [see instructions here](/troubleshooting/err-require-esm).
14 |
15 | You will need to install the module using [NPM](https://www.npmjs.com/package/vitepress-sidebar) or any other Node module package manager. The package should be installed in `devDependencies` as it is only used in the developer environment. Use the command below:
16 |
17 | ```shell
18 | # via npm
19 | $ npm i -D vitepress-sidebar
20 |
21 | # via yarn
22 | $ yarn add -D vitepress-sidebar
23 |
24 | # via pnpm
25 | $ pnpm i -D vitepress-sidebar
26 | ```
27 |
28 | ## How it works
29 |
30 | VitePress Sidebar scans your folders and markdown files hierarchically based on the folder path (`documentRootPath`) you specify in your project's folders.
31 |
32 | It will then exclude, sort, and format certain files based on your settings to read the titles of the sidebar menus, and finally output the settings data according to the sidebar specs required by VitePress.
33 |
34 | As a result, VitePress's `config.js` file should look something like this
35 |
36 | ```javascript
37 | export default {
38 | themeConfig: {
39 | sidebar: [
40 | // VitePress Sidebar's output
41 | {
42 | text: 'Guide',
43 | items: [
44 | { text: 'Introduction', link: '/introduction' },
45 | { text: 'Getting Started', link: '/getting-started' }
46 | ]
47 | }
48 | ]
49 | }
50 | };
51 | ```
52 |
53 | This eliminates the need for manual creation for each menu in the `sidebar`.
54 |
55 | ## How to use
56 |
57 | VitePress Sidebar can automatically generate sidebars with two functions: `withSidebar` and `generateSidebar`. They have the same behavior, but where to use the functions is different. In general, we recommend using `withSidebar`.
58 |
59 | To import the modules you installed into your code, open VitePress's `config.js` file. Note that this file is located in the `.vitepress` directory and may have a different extension depending on your project.
60 |
61 | File and use `vitepress-sidebar` in one of the two ways below:
62 |
63 | ### 1. Using `withSidebar` (recommended)
64 |
65 | The `withSidebar` is used at the `defineConfig` level. Note that the configuration object from VitePress should be placed in the first parameter and the options from the VitePress Sidebar in the second parameter.
66 |
67 | VitePress Sidebar will override any additional options required by the existing options in VitePress. Any manual `sidebar` options you may have set previously will be overridden by the new options.
68 |
69 | ```javascript
70 | // `.vitepress/config.js`
71 | import { withSidebar } from 'vitepress-sidebar';
72 |
73 | const vitePressOptions = {
74 | // VitePress's options here...
75 | title: 'VitePress Sidebar',
76 | themeConfig: {
77 | // ...
78 | }
79 | };
80 |
81 | const vitePressSidebarOptions = {
82 | // VitePress Sidebar's options here...
83 | documentRootPath: '/',
84 | collapsed: false,
85 | capitalizeFirst: true
86 | };
87 |
88 | export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));
89 | ```
90 |
91 | ### 2. Using `generateSidebar`
92 |
93 | `generateSidebar` is available at the `themeConfig.sidebar` level. This can be used when code separation is needed for more detailed `themeConfig` settings.
94 |
95 | ```javascript
96 | // `.vitepress/config.js`
97 | import { generateSidebar } from 'vitepress-sidebar';
98 |
99 | export default defineConfig({
100 | themeConfig: {
101 | sidebar: generateSidebar({
102 | // VitePress Sidebar's options here...
103 | })
104 | }
105 | });
106 | ```
107 |
108 | To scan your project's documents, VitePress Sidebar needs to know the correct location by specifying the working path with the `documentRootPath` option. The default is `/`, but if your VitePress project is located in a separate folder, such as `docs`, depending on your project, you will need to specify the path yourself.
109 |
110 | Based on the project root path, the path in `documentRootPath` will write the path where the `.vitePress` folder is located.
111 |
112 | ```text
113 | /
114 | ├─ package.json
115 | ├─ src/
116 | ├─ docs/ <--------------- `documentRootPath` ('/docs')
117 | │ ├─ .vitepress/
118 | │ ├─ another-directory/
119 | │ ├─ hello.md
120 | │ └─ index.md
121 | └─ ...
122 | ```
123 |
124 | If your project is structured like the one above, you'll need to set it up like this:
125 |
126 | ```javascript
127 | // `.vitepress/config.js`
128 | import { withSidebar } from 'vitepress-sidebar';
129 |
130 | const vitePressOptions = {};
131 |
132 | const vitePressSidebarOptions = {
133 | documentRootPath: '/docs'
134 | };
135 |
136 | export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));
137 | ```
138 |
139 | To test how the sidebar results are printed, try building VitePress with the `debugPrint` option set to `true`. You should see the output in the console.
140 |
141 | For more information about the configuration of VitePress Sidebar, see **[Options](/guide/options)** section below.
142 |
143 | ## Code Example
144 |
145 | ```javascript
146 | import { withSidebar } from 'vitepress-sidebar';
147 |
148 | const vitePressConfigs = {
149 | title: 'VitePress Sidebar',
150 | themeConfig: {
151 | // ...
152 | }
153 | };
154 |
155 | export default defineConfig(
156 | withSidebar(vitePressConfigs, {
157 | /*
158 | * For detailed instructions, see the links below:
159 | * https://vitepress-sidebar.cdget.com/guide/options
160 | */
161 | //
162 | // ============ [ RESOLVING PATHS ] ============
163 | // documentRootPath: '/',
164 | // scanStartPath: null,
165 | // resolvePath: null,
166 | // basePath: null,
167 | // followSymlinks: false,
168 | //
169 | // ============ [ GROUPING ] ============
170 | // collapsed: true,
171 | // collapseDepth: 2,
172 | // rootGroupText: 'Contents',
173 | // rootGroupLink: 'https://github.com/jooy2',
174 | // rootGroupCollapsed: false,
175 | //
176 | // ============ [ GETTING MENU TITLE ] ============
177 | // useTitleFromFileHeading: true,
178 | // useTitleFromFrontmatter: true,
179 | // useFolderLinkFromIndexFile: false,
180 | // useFolderTitleFromIndexFile: false,
181 | // frontmatterTitleFieldName: 'title',
182 | //
183 | // ============ [ GETTING MENU LINK ] ============
184 | // useFolderLinkFromSameNameSubFile: false,
185 | // useFolderLinkFromIndexFile: false,
186 | // folderLinkNotIncludesFileName: false,
187 | //
188 | // ============ [ INCLUDE / EXCLUDE ] ============
189 | // excludeByGlobPattern: ['README.md', 'folder/'],
190 | // excludeFilesByFrontmatterFieldName: 'exclude',
191 | // excludeByFolderDepth: undefined,
192 | // includeDotFiles: false,
193 | // includeEmptyFolder: false,
194 | // includeRootIndexFile: false,
195 | // includeFolderIndexFile: false,
196 | //
197 | // ============ [ STYLING MENU TITLE ] ============
198 | // hyphenToSpace: true,
199 | // underscoreToSpace: true,
200 | // capitalizeFirst: false,
201 | // capitalizeEachWords: false,
202 | // keepMarkdownSyntaxFromTitle: false,
203 | // removePrefixAfterOrdering: false,
204 | // prefixSeparator: '.',
205 | //
206 | // ============ [ SORTING ] ============
207 | // manualSortFileNameByPriority: ['first.md', 'second', 'third.md'],
208 | // sortFolderTo: null,
209 | // sortMenusByName: false,
210 | // sortMenusByFileDatePrefix: false,
211 | // sortMenusByFrontmatterOrder: false,
212 | // frontmatterOrderDefaultValue: 0,
213 | // sortMenusByFrontmatterDate: false,
214 | // sortMenusOrderByDescending: false,
215 | // sortMenusOrderNumericallyFromTitle: false,
216 | // sortMenusOrderNumericallyFromLink: false,
217 | //
218 | // ============ [ MISC ] ============
219 | // debugPrint: false,
220 | })
221 | );
222 | ```
223 |
224 | ## Example output
225 |
226 | ```text
227 | {
228 | documentRootPath: 'javascript',
229 | useTitleFromFileHeading: true,
230 | hyphenToSpace: true,
231 | excludeByGlobPattern: ['vitepress-how-to']
232 | }
233 |
234 | /*
235 | [
236 | {
237 | text: 'examples',
238 | items: [
239 | {
240 | text: 'Examples',
241 | link: '/javascript/examples/examples'
242 | }
243 | ]
244 | },
245 | {
246 | text: 'functions',
247 | items: [
248 | {
249 | text: 'prototypes',
250 | items: [
251 | {
252 | text: 'Array',
253 | items: [
254 | {
255 | text: 'Array.indexOf',
256 | link: '/javascript/functions/prototypes/Array/Array.indexOf'
257 | }
258 | ]
259 | }
260 | ]
261 | }
262 | ]
263 | },
264 | {
265 | text: 'Getting Started',
266 | link: '/javascript/getting_started'
267 | }
268 | ];
269 | */
270 | ```
271 |
--------------------------------------------------------------------------------
/docs/ko/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | title: VitePress Sidebar
5 | titleTemplate: 강력한 사이드바 생성 자동화 도구
6 |
7 | hero:
8 | name: VitePress Sidebar
9 | text: 강력한 사이드바 생성 자동화 도구
10 | tagline: 간단한 구성으로 알아서 생성하는 VitePress의 사이드바 플러그인을 소개합니다.
11 | actions:
12 | - theme: brand
13 | text: 시작하기
14 | link: /ko/guide/getting-started
15 | - theme: alt
16 | text: 옵션
17 | link: /ko/guide/options
18 | - theme: alt
19 | text: GitHub
20 | link: https://github.com/jooy2/vitepress-sidebar
21 | image:
22 | src: /sidebar.png
23 | alt: Sidebar
24 |
25 | features:
26 | - icon:
27 | title: VitePress를 효율적으로 활용
28 | details: 최신 버전의 VitePress에 최적화되었습니다.
29 | - icon:
30 | title: 쉽고 세분화된 사이드바 구성
31 | details: 사용하기 쉽고, 원하는 대로 사용자 지정할 수 있는 다양한 옵션이 있습니다. 정렬, 특수 문자 변환, 파일 및 폴더 필터 등을 위한 메뉴를 사용자 지정하세요!
32 | - icon:
33 | title: 광범위한 사용 사례
34 | details: 다양한 사용 사례를 처리할 수 있도록 다중 사이드바, Frontmatter, TypeScript를 지원합니다.
35 | - icon:
36 | title: 안정적인 유지 관리 지원
37 | details: 2K 이상의 다운로드를 통해 실제 사용 사례가 많으며, 빠른 기술 지원을 제공합니다.
38 | ---
39 |
40 |
61 |
--------------------------------------------------------------------------------
/test/specs/base.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'assert';
2 | import { describe, it } from 'node:test';
3 | import { generateSidebar, withSidebar } from '../../dist';
4 |
5 | const TEST_DIR_BASE = 'test/resources';
6 |
7 | describe('Test: base test', () => {
8 | it('Without configurations', () => {
9 | assert.deepStrictEqual(
10 | generateSidebar({
11 | documentRootPath: `${TEST_DIR_BASE}/general`
12 | }),
13 | [
14 | {
15 | text: 'a',
16 | link: '/a'
17 | },
18 | {
19 | text: 'b',
20 | link: '/b'
21 | },
22 | {
23 | text: 'c',
24 | link: '/c'
25 | },
26 | {
27 | text: 'folder',
28 | items: [
29 | {
30 | text: 'folder-test-2',
31 | link: '/folder/folder-test-2'
32 | },
33 | {
34 | text: 'folder-test',
35 | link: '/folder/folder-test'
36 | },
37 | {
38 | text: 'subFolder',
39 | items: [
40 | {
41 | text: 'sub-folder-test',
42 | link: '/folder/subFolder/sub-folder-test'
43 | }
44 | ]
45 | }
46 | ]
47 | },
48 | {
49 | text: 'folder-2',
50 | items: [
51 | {
52 | text: 'folder2',
53 | link: '/folder-2/folder2'
54 | }
55 | ]
56 | },
57 | {
58 | text: 'test',
59 | link: '/test'
60 | }
61 | ]
62 | );
63 | });
64 |
65 | it('With complex configurations (A)', () => {
66 | assert.deepEqual(
67 | generateSidebar({
68 | documentRootPath: `${TEST_DIR_BASE}/general`,
69 | collapsed: false,
70 | hyphenToSpace: true,
71 | underscoreToSpace: true,
72 | includeRootIndexFile: true,
73 | useTitleFromFrontmatter: true,
74 | excludeByGlobPattern: ['a.md', 'c.md', 'folder-2/']
75 | }),
76 | [
77 | {
78 | text: 'b',
79 | link: '/b'
80 | },
81 | {
82 | text: 'folder',
83 | items: [
84 | {
85 | text: 'folder test 2',
86 | link: '/folder/folder-test-2'
87 | },
88 | {
89 | text: 'folder test',
90 | link: '/folder/folder-test'
91 | },
92 | {
93 | text: 'subFolder',
94 | items: [
95 | {
96 | text: 'sub folder test',
97 | link: '/folder/subFolder/sub-folder-test'
98 | }
99 | ],
100 | collapsed: false
101 | }
102 | ],
103 | collapsed: false
104 | },
105 | {
106 | text: 'test',
107 | link: '/test'
108 | }
109 | ]
110 | );
111 | });
112 |
113 | it('With complex configurations (B)', () => {
114 | assert.deepEqual(
115 | generateSidebar({
116 | documentRootPath: `${TEST_DIR_BASE}/general`,
117 | includeEmptyFolder: true,
118 | includeDotFiles: true,
119 | excludeByGlobPattern: ['subFolder/'],
120 | hyphenToSpace: true,
121 | underscoreToSpace: true,
122 | capitalizeFirst: true,
123 | useTitleFromFrontmatter: true,
124 | useTitleFromFileHeading: true
125 | }),
126 | [
127 | {
128 | text: 'A',
129 | link: '/a'
130 | },
131 | {
132 | text: 'B',
133 | link: '/b'
134 | },
135 | {
136 | text: 'C',
137 | link: '/c'
138 | },
139 | {
140 | text: 'Folder',
141 | items: [
142 | {
143 | text: 'Folder test 2',
144 | link: '/folder/folder-test-2'
145 | },
146 | {
147 | text: 'FolderTestFile',
148 | link: '/folder/folder-test'
149 | }
150 | ]
151 | },
152 | {
153 | text: 'Folder 2',
154 | items: [
155 | {
156 | text: 'Folder2 File',
157 | link: '/folder-2/folder2'
158 | }
159 | ]
160 | },
161 | {
162 | text: 'TestFile',
163 | link: '/test'
164 | }
165 | ]
166 | );
167 | });
168 |
169 | it('API: With complex configurations (C)', () => {
170 | assert.deepEqual(
171 | generateSidebar({
172 | documentRootPath: `${TEST_DIR_BASE}/number-title-and-filename`,
173 | excludeByGlobPattern: ['index.md'],
174 | capitalizeFirst: true,
175 | collapsed: true,
176 | sortMenusOrderNumericallyFromTitle: true,
177 | useFolderTitleFromIndexFile: true,
178 | useFolderLinkFromSameNameSubFile: true,
179 | useTitleFromFileHeading: true,
180 | useTitleFromFrontmatter: true,
181 | hyphenToSpace: true
182 | }),
183 | [
184 | {
185 | link: '/1-introduction',
186 | text: '1. Introduction'
187 | },
188 | {
189 | link: '/2-how-to-use',
190 | text: '2. How to use'
191 | }
192 | ]
193 | );
194 | });
195 |
196 | it('withSidebar: basic', () => {
197 | assert.deepStrictEqual(
198 | withSidebar(
199 | {
200 | title: 'VitePress Sidebar',
201 | themeConfig: {
202 | sidebar: [
203 | {
204 | text: 'Not used',
205 | link: '/'
206 | }
207 | ],
208 | logo: { src: '/logo.png' },
209 | footer: {
210 | message: 'Footer'
211 | }
212 | }
213 | },
214 | {
215 | documentRootPath: `${TEST_DIR_BASE}/general`
216 | }
217 | ),
218 | {
219 | title: 'VitePress Sidebar',
220 | themeConfig: {
221 | sidebar: [
222 | {
223 | text: 'a',
224 | link: '/a'
225 | },
226 | {
227 | text: 'b',
228 | link: '/b'
229 | },
230 | {
231 | text: 'c',
232 | link: '/c'
233 | },
234 | {
235 | text: 'folder',
236 | items: [
237 | {
238 | text: 'folder-test-2',
239 | link: '/folder/folder-test-2'
240 | },
241 | {
242 | text: 'folder-test',
243 | link: '/folder/folder-test'
244 | },
245 | {
246 | text: 'subFolder',
247 | items: [
248 | {
249 | text: 'sub-folder-test',
250 | link: '/folder/subFolder/sub-folder-test'
251 | }
252 | ]
253 | }
254 | ]
255 | },
256 | {
257 | text: 'folder-2',
258 | items: [
259 | {
260 | text: 'folder2',
261 | link: '/folder-2/folder2'
262 | }
263 | ]
264 | },
265 | {
266 | text: 'test',
267 | link: '/test'
268 | }
269 | ],
270 | logo: {
271 | src: '/logo.png'
272 | },
273 | footer: {
274 | message: 'Footer'
275 | }
276 | }
277 | }
278 | );
279 | });
280 |
281 | it('Contains a path with the same name as `documentRootPath`', () => {
282 | assert.deepStrictEqual(
283 | generateSidebar({
284 | documentRootPath: `${TEST_DIR_BASE}/same-name-path`
285 | }),
286 | [
287 | {
288 | text: 'a',
289 | link: '/a'
290 | },
291 | {
292 | text: 'test',
293 | items: [
294 | {
295 | text: 'resources',
296 | items: [
297 | {
298 | text: 'same-name-path',
299 | items: [
300 | {
301 | text: 'b',
302 | link: '/test/resources/same-name-path/b'
303 | }
304 | ]
305 | }
306 | ]
307 | }
308 | ]
309 | }
310 | ]
311 | );
312 | });
313 |
314 | it('`index.md` file must be used correctly according to the situation.', () => {
315 | assert.deepEqual(
316 | generateSidebar({
317 | documentRootPath: `${TEST_DIR_BASE}/index-files`,
318 | useTitleFromFileHeading: true,
319 | excludeByGlobPattern: ['abc']
320 | }),
321 | [
322 | {
323 | text: 'a',
324 | items: [
325 | {
326 | text: 'Test Index',
327 | link: '/a/testindex'
328 | }
329 | ]
330 | },
331 | {
332 | text: 'index',
333 | items: [
334 | {
335 | text: 'B',
336 | link: '/index/b'
337 | }
338 | ]
339 | }
340 | ]
341 | );
342 | });
343 | });
344 |
--------------------------------------------------------------------------------
/docs/en/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | title: VitePress Sidebar
5 | titleTemplate: Powerful auto sidebar generator
6 |
7 | hero:
8 | name: VitePress Sidebar
9 | text: Powerful auto sidebar generator
10 | tagline: A VitePress auto sidebar plugin that automatically creates a simple configuration
11 | actions:
12 | - theme: brand
13 | text: Getting Started
14 | link: /guide/getting-started
15 | - theme: alt
16 | text: Options
17 | link: /guide/options
18 | - theme: alt
19 | text: GitHub
20 | link: https://github.com/jooy2/vitepress-sidebar
21 | image:
22 | src: /sidebar.png
23 | alt: Sidebar
24 |
25 | features:
26 | - icon:
27 | title: Best Pairings with VitePress
28 | details: Optimized for the latest version of VitePress.
29 | - icon:
30 | title: Easy and granular sidebar configuration
31 | details: Easy to use, lots of options to customize to your liking. Customize menus for sorting, special character conversion, file and folder filters, and more!
32 | - icon:
33 | title: Broadly scalable use cases
34 | details: Support for multiple sidebars, Frontmatter, and TypeScript to handle a variety of use cases.
35 | - icon:
36 | title: Reliable maintenance support
37 | details: With 2K+ downloads, there are many real-world use cases, and we have fast technical support.
38 | ---
39 |
40 |
61 |
--------------------------------------------------------------------------------
/lib/helper.ts:
--------------------------------------------------------------------------------
1 | // Get a single value of type T from Frontmatter
2 | // Defaults to defaultValue
3 | import { readFileSync } from 'fs';
4 | import matter from 'gray-matter';
5 | import { capitalizeFirst } from 'qsu';
6 | import type {
7 | AnyValueObject,
8 | SidebarItem,
9 | SidebarListItem,
10 | SortByObjectKeyOptions,
11 | VitePressSidebarOptions
12 | } from './types.ts';
13 |
14 | export function generateNotTogetherMessage(options: string[]): string {
15 | return `These options cannot be used together: ${options.join(', ')}`;
16 | }
17 |
18 | export function getValueFromFrontmatter(filePath: string, key: string, defaultValue: T): T {
19 | try {
20 | const fileData = readFileSync(filePath, 'utf-8');
21 | const { data } = matter(fileData);
22 |
23 | // Try for using gray-matter
24 | if (data?.[key]) {
25 | return data[key];
26 | }
27 |
28 | // Try manual parsing
29 | const lines = fileData.split('\n');
30 | let frontmatterStart = false;
31 |
32 | for (let i = 0, len = lines.length; i < len; i += 1) {
33 | const str = lines[i].toString().replace('\r', '');
34 |
35 | if (/^---$/.test(str)) {
36 | frontmatterStart = true;
37 | }
38 | if (new RegExp(`^${key}: (.*)`).test(str) && frontmatterStart) {
39 | return JSON.parse(str.replace(`${key}: `, '')) as T;
40 | }
41 | }
42 | } catch {
43 | return defaultValue;
44 | }
45 | return defaultValue;
46 | }
47 |
48 | export function getOrderFromFrontmatter(filePath: string, defaultOrder: number): number {
49 | return parseFloat(getValueFromFrontmatter(filePath, 'order', defaultOrder.toString()));
50 | }
51 |
52 | export function getDateFromFrontmatter(filePath: string): string {
53 | return getValueFromFrontmatter(filePath, 'date', '0001-01-01');
54 | }
55 |
56 | export function getExcludeFromFrontmatter(
57 | filePath: string,
58 | excludeFrontmatterFieldName?: string
59 | ): boolean {
60 | if (!excludeFrontmatterFieldName) {
61 | return false;
62 | }
63 |
64 | return getValueFromFrontmatter(filePath, excludeFrontmatterFieldName, false);
65 | }
66 |
67 | export function formatTitle(
68 | options: VitePressSidebarOptions,
69 | title: string,
70 | fromTitleHeading = false
71 | ): string {
72 | const htmlTags: string[] = [];
73 | const h1Headers: string[] = [];
74 | const htmlPlaceholder = '\u0001';
75 | const h1Placeholder = '\u0002';
76 | let text = title;
77 |
78 | // Replace HTML tags and Markdown h1 headers with placeholders
79 | text = text.replace(/<[^>]*>/g, (match) => {
80 | htmlTags.push(match);
81 | return htmlPlaceholder;
82 | });
83 | text = text.replace(/^(#+.*)$/gm, (match) => {
84 | h1Headers.push(match);
85 | return h1Placeholder;
86 | });
87 |
88 | // Remove certain Markdown format
89 | if (fromTitleHeading && !options.keepMarkdownSyntaxFromTitle) {
90 | text = text.replace(/\*{1,2}([^*]+?)\*{1,2}/g, '$1');
91 | text = text.replace(/_{1,2}([^_]+?)_{1,2}/g, '$1');
92 | text = text.replace(/~{1,2}([^~]+?)~{1,2}/g, '$1');
93 | text = text.replace(/`{1,3}([^`]+?)`{1,3}/g, '$1');
94 | }
95 |
96 | // Replace text [START]
97 | if (options.hyphenToSpace) {
98 | text = text.replace(/-/g, ' ');
99 | }
100 | if (options.underscoreToSpace) {
101 | text = text.replace(/_/g, ' ');
102 | }
103 | if (options.capitalizeEachWords) {
104 | let lastChar = '';
105 |
106 | for (let i = 0; i < text.length; i += 1) {
107 | if ((i === 0 || !/[a-zA-Z0-9]/.test(lastChar)) && /[a-z]/.test(text[i])) {
108 | text = text.slice(0, i) + text[i].toUpperCase() + text.slice(i + 1);
109 | }
110 |
111 | lastChar = text[i];
112 | }
113 | } else if (options.capitalizeFirst) {
114 | text = capitalizeFirst(text);
115 | }
116 | // Replace text [END]
117 |
118 | // Restore Markdown headers and HTML tags
119 | let h1Index = -1;
120 | let htmlIndex = -1;
121 | text = text.replace(new RegExp(h1Placeholder, 'g'), () => {
122 | h1Index += 1;
123 | return h1Headers[h1Index];
124 | });
125 | text = text.replace(new RegExp(htmlPlaceholder, 'g'), () => {
126 | htmlIndex += 1;
127 | return htmlTags[htmlIndex];
128 | });
129 |
130 | return text;
131 | }
132 |
133 | export function getTitleFromMd(
134 | fileName: string,
135 | filePath: string,
136 | options: VitePressSidebarOptions,
137 | isDirectory: boolean,
138 | callbackTitleReceived?: () => void
139 | ): string {
140 | if (isDirectory) {
141 | return formatTitle(options, fileName);
142 | }
143 |
144 | if (options.useTitleFromFrontmatter) {
145 | // Use content frontmatter title value instead of file name
146 | let value = getValueFromFrontmatter(
147 | filePath,
148 | options.frontmatterTitleFieldName || 'title',
149 | undefined
150 | );
151 | // Try to use title front-matter as fallback
152 | if (!value) {
153 | value = getValueFromFrontmatter(filePath, 'title', undefined);
154 | }
155 | if (value) {
156 | callbackTitleReceived?.();
157 | return formatTitle(options, value);
158 | }
159 | }
160 |
161 | if (options.useTitleFromFileHeading) {
162 | // Use content 'h1' string instead of file name
163 | try {
164 | const data = readFileSync(filePath, 'utf-8');
165 | const lines = data.split('\n');
166 |
167 | for (let i = 0, len = lines.length; i < len; i += 1) {
168 | let str = lines[i].toString().replace('\r', '');
169 |
170 | if (/^# /.test(str)) {
171 | str = str.replace(/^# /, '');
172 |
173 | if (/\[(.*)]\(.*\)/.test(str)) {
174 | // Remove hyperlink from h1 if exists
175 | const execValue = /(.*)?\[(.*)]\((.*)\)(.*)?/.exec(str) || '';
176 |
177 | str =
178 | execValue.length > 0
179 | ? `${execValue[1] || ''}${execValue[2] || ''}${execValue[4] || ''}`
180 | : '';
181 | }
182 |
183 | callbackTitleReceived?.();
184 | return formatTitle(options, str, true);
185 | }
186 | }
187 | } catch {
188 | return 'Unknown';
189 | }
190 | }
191 |
192 | return formatTitle(options, fileName.replace(/\.md$/, ''));
193 | }
194 |
195 | export function sortByFileTypes(
196 | arrItems: SidebarListItem,
197 | sortFolderTo: 'top' | 'bottom'
198 | ): object[] {
199 | for (let i = 0; i < arrItems.length; i += 1) {
200 | if (arrItems[i].items && arrItems[i].items.length) {
201 | arrItems[i].items = sortByFileTypes(arrItems[i].items, sortFolderTo);
202 | }
203 | }
204 |
205 | const itemFolders = arrItems.filter((item: SidebarItem) => Object.hasOwn(item, 'items'));
206 | const itemFiles = arrItems.filter((item: SidebarItem) => !Object.hasOwn(item, 'items'));
207 |
208 | if (sortFolderTo === 'top') {
209 | return [...itemFolders, ...itemFiles];
210 | }
211 |
212 | return [...itemFiles, ...itemFolders];
213 | }
214 |
215 | export function sortByObjectKey(options: SortByObjectKeyOptions): object[] {
216 | for (let i = 0; i < options.arr.length; i += 1) {
217 | if (options.arr[i].items && options.arr[i].items.length) {
218 | options.arr[i].items = sortByObjectKey({
219 | ...options,
220 | arr: options.arr[i].items
221 | });
222 | }
223 | }
224 |
225 | const basicCollator = new Intl.Collator([], {
226 | numeric: options.numerically,
227 | sensitivity: 'base'
228 | });
229 | let result;
230 |
231 | if (options.dateSortFromFrontmatter) {
232 | result = options.arr.sort(
233 | (a: SidebarListItem, b: SidebarListItem) =>
234 | new Date(a[options.key]).valueOf() - new Date(b[options.key]).valueOf()
235 | );
236 |
237 | if (options.desc) {
238 | result = result.reverse();
239 | }
240 | } else if (options.dateSortFromTextWithPrefix) {
241 | const dateRegex = /^[0-9]{4}-[0-9]{2}-[0-9]{2}/g;
242 |
243 | result = options.arr.sort((a: SidebarListItem, b: SidebarListItem) => {
244 | const aDate = a[options.key].split(dateRegex)?.[0];
245 | const bDate = b[options.key].split(dateRegex)?.[0];
246 |
247 | return new Date(aDate).valueOf() - new Date(bDate).valueOf();
248 | });
249 |
250 | if (options.desc) {
251 | result = result.reverse();
252 | }
253 | } else {
254 | result = options.arr.sort((a: SidebarListItem, b: SidebarListItem) => {
255 | const compareResult = basicCollator.compare(a[options.key], b[options.key]);
256 |
257 | return options.desc ? -compareResult : compareResult;
258 | });
259 | }
260 |
261 | return result;
262 | }
263 |
264 | export function deepDeleteKey(obj: SidebarListItem, key: string): void {
265 | if (typeof obj !== 'object' || obj === null) {
266 | return;
267 | }
268 |
269 | if (Object.hasOwn(obj, key)) {
270 | delete obj[key];
271 | }
272 |
273 | Object.keys(obj).forEach((item) => {
274 | if (typeof obj[item] === 'object') {
275 | deepDeleteKey(obj[item], key);
276 | }
277 | });
278 | }
279 |
280 | export function removePrefixFromTitleAndLink(
281 | sidebarList: SidebarListItem,
282 | options: VitePressSidebarOptions
283 | ): SidebarListItem {
284 | const sidebarListLength = sidebarList.length;
285 |
286 | for (let i = 0; i < sidebarListLength; i += 1) {
287 | const obj = sidebarList[i];
288 |
289 | for (let j = 0; j < Object.keys(obj).length; j += 1) {
290 | const key = Object.keys(obj)[j];
291 |
292 | if (key === 'text') {
293 | if (
294 | !(
295 | !(options.prefixSeparator instanceof RegExp) &&
296 | obj[key].indexOf(options.prefixSeparator) === -1
297 | )
298 | ) {
299 | const splitItem = obj[key].split(options.prefixSeparator);
300 |
301 | splitItem.shift();
302 |
303 | obj[key] = splitItem.join(options.prefixSeparator);
304 | }
305 | } else if (key === 'items') {
306 | obj[key] = removePrefixFromTitleAndLink(obj[key], options);
307 | }
308 | }
309 | }
310 |
311 | return sidebarList;
312 | }
313 |
314 | export function debugPrint(optionItems?: AnyValueObject, sidebarResult?: AnyValueObject): void {
315 | process.stdout.write(
316 | `\n${'='.repeat(50)}\n${JSON.stringify(optionItems, null, 2)}\n${'-'.repeat(
317 | 50
318 | )}\n${JSON.stringify(sidebarResult, null, 2)}\n${'='.repeat(50)}\n\n`
319 | );
320 | }
321 |
--------------------------------------------------------------------------------
/docs/zhHans/guide/options.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 2
3 | ---
4 |
5 | # 侧边栏选项
6 |
7 | 本页介绍 VitePress 侧边栏的所有选项。
8 |
9 | ## @ 快速搜索
10 |
11 | | 解决路径问题 | 分组 |
12 | | ------------------------------------- | ----------------------------------------- |
13 | | [documentRootPath](#documentrootpath) | [collapsed](#collapsed) |
14 | | [scanStartPath](#scanstartpath) | [collapseDepth](#collapsedepth) |
15 | | [resolvePath](#resolvepath) | [rootGroupText](#rootgrouptext) |
16 | | [basePath](#basepath) | [rootGroupLink](#rootgrouplink) |
17 | | [followSymlinks](#followsymlinks) | [rootGroupCollapsed](#rootgroupcollapsed) |
18 |
19 | | 获取菜单标题 | 获取菜单链接 |
20 | | --- | --- |
21 | | [useTitleFromFileHeading](#usetitlefromfileheading) | [useFolderLinkFromSameNameSubFile](#usefolderlinkfromsamenamesubfile) |
22 | | [useTitleFromFrontmatter](#usetitlefromfrontmatter) | [folderLinkNotIncludesFileName](#folderlinknotincludesfilename) |
23 | | [useFolderTitleFromIndexFile](#usefoldertitlefromindexfile) | [useFolderLinkFromIndexFile](#usefolderlinkfromindexfile) |
24 | | [frontmatterTitleFieldName](#frontmattertitlefieldname) | |
25 |
26 | | 包括/排除 | 菜单标题样式 |
27 | | --- | --- |
28 | | [excludeByGlobPattern](#excludebyglobpattern) | [hyphenToSpace](#hyphentospace) |
29 | | [excludeFilesByFrontmatterFieldName](#excludefilesbyfrontmatterfieldname) | [underscoreToSpace](#underscoretospace) |
30 | | [excludeByFolderDepth](#excludebyfolderdepth) | [capitalizeFirst](#capitalizefirst) |
31 | | [includeDotFiles](#includedotfiles) | [capitalizeEachWords](#capitalizeeachwords) |
32 | | [includeEmptyFolder](#sortmenusbyfrontmatterdate) | [keepMarkdownSyntaxFromTitle](#keepmarkdownsyntaxfromtitle) |
33 | | [includeRootIndexFile](#sortmenusbyfrontmatterdate) | [removePrefixAfterOrdering](#removeprefixafterordering) |
34 | | [includeFolderIndexFile](#sortmenusbyfrontmatterdate) | [prefixSeparator](#prefixseparator) |
35 |
36 | | 分类 | 杂项 |
37 | | --- | --- |
38 | | [manualSortFileNameByPriority](#manualsortfilenamebypriority) | [debugPrint](#debugprint) |
39 | | [sortFolderTo](#sortfolderto) | |
40 | | [sortMenusByName](#sortmenusbyname) | |
41 | | [sortMenusByFileDatePrefix](#sortmenusbyfiledateprefix) | |
42 | | [sortMenusByFrontmatterOrder](#sortmenusbyfrontmatterorder) | |
43 | | [frontmatterOrderDefaultValue](#frontmatterorderdefaultvalue) | |
44 | | [sortMenusByFrontmatterDate](#sortmenusbyfrontmatterdate) | |
45 | | [sortMenusOrderByDescending](#sortmenusorderbydescending) | |
46 | | [sortMenusOrderNumericallyFromTitle](#sortmenusordernumericallyfromtitle) | |
47 | | [sortMenusOrderNumericallyFromLink](#sortmenusordernumericallyfromlink) | |
48 |
49 | ## `documentRootPath`
50 |
51 | - Type: `string`
52 | - Default: `'/'`
53 |
54 | 文档文件所在的顶级路径。默认值为 `/`。
55 |
56 | 这是 `.vitepress`目录所在的路径,如果项目根目录中文档所在的文件夹是 `/docs`,则该选项的值应设为 `docs` 或 `/docs`。
57 |
58 | ```text
59 | /
60 | ├─ package.json
61 | ├─ src/
62 | ├─ docs/ <--------------- `documentRootPath` ('/docs')
63 | │ ├─ .vitepress/ <------ VitePress 配置目录
64 | │ ├─ another-directory/
65 | │ ├─ hello.md
66 | │ └─ index.md
67 | └─ ...
68 | ```
69 |
70 | ## `scanStartPath`
71 |
72 | - Type: `string|null`
73 | - Default: `null`
74 |
75 | 此选项用于配置多个侧边栏。您可以在 **[多个侧边栏](/zhHans/advanced-usage/multiple-sidebars-how-to)** 页面上了解更多信息。
76 |
77 | 用于扫描文档列表的根目录路径。在`documentRootPath`中设置的路径中的文件,在`scanStartPath`中设置的路径之外,不会被扫描。如果您指定了`scanStartPath`,建议您也设置`documentRootPath`,因为`documentRootPath`中设置的父路径应该出现在`link`中。
78 |
79 | 例如,如果根路径是`/docs`,要扫描的文件是`/docs/sub-dir/scan-me`,则设置如下:
80 |
81 | - `documentRootPath`: `/docs`,
82 | - `scanStartPath`: `sub-dir/scan-me` (请勿包含 `documentRootPath` 的路径。)
83 |
84 | ## `resolvePath`
85 |
86 | - Type: `string|null`
87 | - Default: `null`
88 |
89 | 此选项用于配置多个侧边栏。您可以在 **[多个侧边栏](/zhHans/advanced-usage/multiple-sidebars-how-to)** 页面上了解更多信息。
90 |
91 | 输入路径,为每个路径显示不同的侧边栏。路径前必须包含`/`。没有此值的选项将设置为根路径(`/`)。
92 |
93 | 例如: `/`, `/path/sub-path`, `/guide/`...
94 |
95 | ## `basePath`
96 |
97 | - Type: `string|null`
98 | - Default: `null`
99 |
100 | 此选项用于配置多个侧边栏。您可以在 **[多个侧边栏](/zhHans/advanced-usage/multiple-sidebars-how-to)** 页面上了解更多信息。
101 |
102 | 如果路径因VitePress的重写选项而改变,则可以使用此选项。它替换VitePress中的基本路径。如果此值不存在,则将使用来自`resolvePath`的值。
103 |
104 | ## `followSymLinks`
105 |
106 | - Type: `boolean`
107 | - Default: `false`
108 |
109 | 如果该值为 `true`,则在扫描目录时,会包含任何已设置符号链接的目录或文件,并将其添加到菜单中。如果符号链接配置不正确或链接设置复杂,请务必小心,因为这可能导致性能低下或无限扫描。
110 |
111 | ## `useTitleFromFileHeading`
112 |
113 | - Type: `boolean`
114 | - Default: `false`
115 |
116 | 如果值为 `true`,则显示带有 `.md` 文件中 `h1` 标题内容的标题。如果文件中不存在 `h1` 标题,则显示 `Unknown`。
117 |
118 | 默认菜单项按文件夹树顺序排序,因此如果您想按更改后的菜单名称重新排序,请将`sortMenusByName`选项设置为`true`。
119 |
120 | ## `useTitleFromFrontmatter`
121 |
122 | - Type: `boolean`
123 | - Default: `false`
124 |
125 | 如果值为`true`,则根据文件`Frontmatter`中`title`的值显示标题。如果无法解析该值,则如果`useTitleFromFileHeading`选项为`true`,则从`h1`标签中获取该值,如果失败,则从文件名中获取该值。
126 |
127 | `Frontmatter`应位于文档顶部,并应如下所示(在 `title:` 值和标题之间需要留出空格)。
128 |
129 | ```markdown
130 | ---
131 | title: Hello World
132 | ---
133 | ```
134 |
135 | ## `frontmatterTitleFieldName`
136 |
137 | - Type: `string`
138 | - Default: `title`
139 |
140 | 根据文件中指定的Frontmatter中的键名显示菜单标题。如果指定的值在Frontmatter中不存在,将使用默认的`title`作为后备。
141 |
142 | ```markdown
143 | ---
144 | name: This is frontmatter title value.
145 | ---
146 | ```
147 |
148 | 欲了解更多信息,请参阅以下文章: https://vitepress.dev/guide/frontmatter
149 |
150 | 默认菜单项是按文件夹树顺序排序的,因此如果想按更改后的菜单名称重新排序,请将 `sortMenusByName` 选项设置为 `true`。
151 |
152 | ## `useFolderTitleFromIndexFile`
153 |
154 | - Type: `boolean`
155 | - Default: `false`
156 |
157 | 如果该值为 `true`,则使用当前文件夹的 `index.md` 文件中的信息来获取菜单名称。如果不存在 `index.md` 文件,则使用文件夹名称。由于我们通常从 `index.md` 文件中获取 `index` 名称,因此建议同时使用 `useTitleFromFileHeading` 或 `useTitleFromFrontmatter` 选项,从该文件的 Markdown 标题或 Frontmatter 中获取标题。
158 |
159 | 侧边栏菜单会隐藏 `index.md` 文件,但如果 `includeFolderIndexFile` 选项为 `true`,索引文件就会显示在菜单中。
160 |
161 | ## `useFolderLinkFromIndexFile`
162 |
163 | - Type: `boolean`
164 | - Default: `false`
165 |
166 | 如果此值为 `true`,将指定一个指向文件夹的链接,以便您可以导航到当前文件夹中的 `index.md` 文件。如果 `index.md` 文件不存在,则不会创建链接。
167 |
168 | 侧边栏菜单会隐藏 `index.md` 文件,但如果 `includeFolderIndexFile` 选项为 `true`,则可在菜单中显示索引文件。
169 |
170 | ## `manualSortFileNameByPriority`
171 |
172 | - Type: `Array`
173 | - Default: `[]`
174 |
175 | 按文件名(包括扩展名)数组的顺序排序。如果数组中没有与文件名匹配的值,排序优先级将被退回。这适用于文件和目录,同样的排列规则也适用于子目录。
176 |
177 | ## `sortFolderTo`
178 |
179 | - Type: `undefined | 'top' | 'bottom'`
180 | - Default: `undefined`
181 |
182 | 完成所有排序后,文件夹和文件将被分批放置。如果值为 `top`,则所有文件夹都放在文件上方;如果为 `bottom`,则放在文件下方。子文件夹中的项目也会一起排序。
183 |
184 | ## `sortMenusByName`
185 |
186 | - Type: `boolean`
187 | - Default: `false`
188 |
189 | 按名称对菜单项中的项目进行排序。通常情况下,文件夹扫描是按名称升序排序的,因此,如果不应用此选项,则应用默认排序,但如果使用`useTitleFromFileHeading`或`useTitleFromFrontmatter`选项,则可能需要按名称重新排序,因为菜单名称已更改。此选项强制按名称排序,即使菜单名称已更改也是如此。
190 |
191 | ## `sortMenusByFileDatePrefix`
192 |
193 | - Type: `boolean`
194 | - Default: `false`
195 |
196 | 如果值为 `true`,则按菜单项名称中的日期前缀排序。日期格式必须是 `YYYY-MM-DD` 格式(例如 `2024-01-01-menu-name`, `2024-01-02.menu-name`...)
197 |
198 | 要删除菜单文本中残留的日期前缀,可以使用 `prefixSeparator` 和 `removePrefixAfterOrdering` 选项。
199 |
200 | 默认菜单项是按文件夹树顺序排序的,因此如果想按更改后的菜单名称重新排序,请将 `sortMenusByName` 选项设置为 `true`。
201 |
202 | ## `sortMenusByFrontmatterOrder`
203 |
204 | - Type: `boolean`
205 | - Default: `false`
206 |
207 | 按 frontmatter 的 `order` 属性对菜单项排序。对于每个文件夹,按 `order` 属性的值(数字)升序排序,如果 `sortMenusOrderByDescending` 选项为 `true`,则按降序排序。如果 `order` 属性的值不是数字或不存在,则 `order` 会被判定为 `0`。
208 |
209 | ## `sortMenusByFrontmatterDate`
210 |
211 | - Type: `boolean`
212 | - Default: `false`
213 |
214 | 根据前端的`date`属性对菜单项进行排序。它还会按日期升序(如果`sortMenusOrderByDescending`为`true`,则按日期降序)对`date`属性值进行排序。日期格式必须符合`YYYY-MM-DD`或JavaScript Date数据类型。
215 |
216 | ## `sortMenusOrderByDescending`
217 |
218 | - Type: `boolean`
219 | - Default: `false`
220 |
221 | 如果此值为 `true`,则按降序排列菜单项中的项目。只有当 `sortMenusByName` 或 `sortMenusByFrontmatterOrder` 为 `true`时,才会启用此选项。
222 |
223 | ## `sortMenusOrderNumericallyFromTitle`
224 |
225 | - Type: `boolean`
226 | - Default: `false`
227 |
228 | 如果该值为`true`,则如果菜单名称以数字开头,则按数字而不是名称排序。例如,如果您有名为`1-a`、`10-a`和`2-a`的文件,则常规排序将按名称排序,即`['1-a', '10-a', '2-a']`。这会导致菜单以非预期的顺序显示,因为`10-a`优先于`2-a`。
229 |
230 | 使用此选项,它们按以下顺序排序:`['1-a', '2-a', '10-a']`
231 |
232 | 如果您希望按降序排序,则应与`sortMenusOrderByDescending`选项一起使用。
233 |
234 | ## `sortMenusOrderNumericallyFromLink`
235 |
236 | - Type: `boolean`
237 | - Default: `false`
238 |
239 | 如果此值为`true`,则如果菜单名称以数字开头,则按数字而不是名称排序。此选项与`sortMenusOrderNumericallyFromTitle`相同,但按链接而不是文件标题排序。因此,它不能与`sortMenusOrderNumericallyFromTitle`选项一起使用。
240 |
241 | 如果您希望按降序排序,则应与`sortMenusOrderByDescending`选项一起使用。
242 |
243 | ## `frontmatterOrderDefaultValue`
244 |
245 | - Type: `number`
246 | - Default: `0`
247 |
248 | 设置 frontmatter 的 `order` 属性未设置时的默认值。该选项仅在 `sortMenusByFrontmatterOrder` 为 `true` 时启用。
249 |
250 | ## `collapsed`
251 |
252 | - Type: `boolean`
253 | - Default: `false`
254 |
255 | 如果未指定`collapsed`选项(`null` 或 `undefined`),则不使用分组折叠/展开,所有菜单将一次性显示。如果为`false`,则创建菜单时所有分组都处于展开状态。如果为`true`,则创建菜单时所有分组都处于折叠状态。
256 |
257 | (即使值为`true`,如果菜单位于折叠组中的文档中,也可能被展开。)
258 |
259 | 
260 |
261 | ## `collapseDepth`
262 |
263 | - Type: `number`
264 | - Default: `1`
265 |
266 | 在指定的深度,菜单组会折叠。指定该选项后,组的折叠/展开将自动启用。顶层文件夹的深度为 `1`。
267 |
268 | ## `hyphenToSpace`
269 |
270 | - Type: `boolean`
271 | - Default: `false`
272 |
273 | 如果值为 `true`,文件名中的`-`符号将转换为空格并显示为标题。通过 Markdown 标题或 frontmatter 导入菜单名称时,该选项也会受到影响。
274 |
275 | ## `underscoreToSpace`
276 |
277 | - Type: `boolean`
278 | - Default: `false`
279 |
280 | 如果值为 `true`,文件名中的`_`符号将转换为空格并显示为标题。通过 Markdown 标题或 frontmatter 导入菜单名称时,该选项也会受到影响。
281 |
282 | ## `capitalizeFirst`
283 |
284 | - Type: `boolean`
285 | - Default: `false`
286 |
287 | 如果值为 `true`,菜单名称的第一个字母将强制为大写。当菜单名称通过 Markdown 标题或 frontmatter 导入时,该选项也会受到影响。
288 |
289 | ## `capitalizeEachWords`
290 |
291 | - Type: `boolean`
292 | - Default: `false`
293 |
294 | 如果值为 `true`,将大写由特殊字符分隔的单词的所有首字母。当菜单名称通过 markdown 标头或 Frontmatter 导入时,该选项也会受到影响。
295 |
296 | 例如,`abc def ghi`和`abc-def ghi`将分别变为`Abc Def Ghi`和`Abc-Def Ghi`。
297 |
298 | ## `excludeByGlobPattern`
299 |
300 | - Type: `Array`
301 | - Default: `[]`
302 |
303 | [glob]() 根据文件模式字符串数组排除文件或文件夹。
304 |
305 | 例如,该值可能如下所示`['abc/', 'def.md', 'ghi/file-**']`这将分别排除所有路径中的`abc`目录和子目录、`def.md`文件以及`ghi`路径中以`file-`开头的文件,这些文件和文件夹将被排除在菜单之外。
306 |
307 | ## `excludeFilesByFrontmatterFieldName`
308 |
309 | - Type: `string|null`
310 | - Default: `null`
311 |
312 | 指定前缀字段名称为`true`的文档将从菜单中排除。
313 |
314 | 如果未指定选项或选项值未定义,则忽略该选项。
315 |
316 | 例如,如果选项值为`exclude`,则菜单中不会显示内容包含`exclude: true`的文档。
317 |
318 | ```markdown
319 | ---
320 | title: This article is excluded.
321 | exclude: true
322 | ---
323 |
324 | # Article
325 |
326 | Content
327 | ```
328 |
329 | 根据选项的值,您可以使用其他名称,如`draft`、`hide`等,来代替`exclude`。
330 |
331 | ## `excludeByFolderDepth`
332 |
333 | - Type: `number|null`
334 | - Default: `null`
335 |
336 | 扫描文件夹时,当达到指定的深度数时,不再扫描子文件夹和文件,也不会在菜单中显示。最上层为 `1`。
337 |
338 | 例如,在下面的结构中,如果选项值为 `3`,则菜单将从第三个深度开始被抑制。
339 |
340 | ```text
341 | root/ <---------- depth: 1 / scan: yes
342 | ├─ aaa1/ <---------- depth: 1
343 | │ ├─ bbb/ <---------- depth: 2
344 | │ │ ├─ b1.md <---------- depth: 3 / scan: no
345 | │ │ ├─ ccc/ <---------- depth: 3
346 | │ │ │ └─ c1.md <---------- depth: 4 / scan: no
347 | │ │ └─ b1.md <---------- depth: 3 / scan: no
348 | │ └─ a1.md <---------- depth: 2 / scan: yes
349 | └─ aaa2/ <---------- depth: 1
350 | └─ aaa1.md <---------- depth: 2 / scan: yes
351 | ```
352 |
353 | ## `includeDotFiles`
354 |
355 | - Type: `boolean`
356 | - Default: `false`
357 |
358 | 通常情况下,如果文件和文件夹名称前有句点(`.`),它们会被视为隐藏文件,不会在列表中显示。但是,如果此选项为`true`,则强制在列表中显示所有隐藏文件和文件夹。
359 |
360 | ## `includeEmptyFolder`
361 |
362 | - Type: `boolean`
363 | - Default: `false`
364 |
365 | 如果值为`true`,则还会显示不存在md文件的目录。
366 |
367 | ## `includeRootIndexFile`
368 |
369 | - Type: `boolean`
370 | - Default: `false`
371 |
372 | 如果值为`true`,则还要在侧边栏菜单中包含顶级路径`index.md`文件。使用`includeFolderIndexFile`选项还可以包含子项目的索引文件。(如果文件不存在,则忽略它。)
373 |
374 | ## `includeFolderIndexFile`
375 |
376 | - Type: `boolean`
377 | - Default: `false`
378 |
379 | 如果值为`true`,则还要在侧边栏菜单中包含文件夹路径`index.md`文件。使用`includeRootIndexFile`选项还可以包含根项目的索引文件。(如果文件不存在,则忽略它。)
380 |
381 | ## `removePrefixAfterOrdering`
382 |
383 | - Type: `boolean`
384 | - Default: `false`
385 |
386 | 从所有操作完成后显示的菜单项的每个菜单标题中删除特定的前缀。如果您想按文件名中的数字排序,而不使用前缀的排序,并且不希望该数字在菜单中显示,这是理想的选择。
387 |
388 | 例如,如果默认使用前缀分隔符(`.`),则以下菜单将重命名为
389 |
390 | - 文件名:`1.hello` -> 菜单名:`hello`
391 | - 文件名:`1.1.hello` -> 菜单名:`1.hello`
392 | - 文件名:`1-1.hello` -> 菜单名:`hello`
393 |
394 | 根据分隔符仅删除一次字母,因此子项(如`1.1.`)应使用`1-1`.。或者,您可以在前缀分隔符值上设置正则表达式来绕过它。
395 |
396 | 可与`prefixSeparator`选项一起使用。更多信息请参阅该选项的描述。
397 |
398 | (注A:前缀仅影响标题,链接将使用文件链接的原始形式)。
399 |
400 | (备注B:如果您使用`useTitleFromFileHeading`或`useTitleFromFrontmatter`选项,则忽略此选项)。
401 |
402 | ## `prefixSeparator`
403 |
404 | - Type: `string|RegExp`
405 | - Default: `'.'`
406 |
407 | 此选项只能与 `removePrefixAfterOrdering` 选项结合使用以删除前缀。
408 |
409 | 从提取的菜单文本中删除指定数量字符(至少一个)的第一部分。例如,如果菜单名称为 `1. Text`,并且您将 `prefixSeparator` 值设置为 `. `,则结果将仅为 `Text`。
410 |
411 | 您还可以使用正则表达式。与正则表达式匹配的值将被删除。例如,要删除 `2024-01-01-hello` 中字符串之前的日期,请将 `prefixSeparator` 值指定为 `/[0-9]{4}-[0-9]{2}-[0-9]{2}-/g`。结果为 `hello`。
412 |
413 | ## `rootGroupText`
414 |
415 | - Type: `string`
416 | - Default: `'Table of Contents'`
417 |
418 | rootGroup 指定整个菜单组,而与目录结构无关。这将使用一个菜单步骤,因此您在使用时应格外小心。如果您不需要 rootGroup 选项,可以将其禁用。如果指定此值,则指定顶级菜单的名称。
419 |
420 | ## `rootGroupLink`
421 |
422 | - Type: `string`
423 | - Default: `null`
424 |
425 | 有关 rootGroup 的更多信息,请参阅 `rootGroupText` 选项说明。指定此值可指定指向 rootGroup 的链接。如果值为空,则不添加链接。
426 |
427 | ## `rootGroupCollapsed`
428 |
429 | - Type: `boolean`
430 | - Default: `null`
431 |
432 | 有关 rootGroup 的更多信息,请参阅 `rootGroupText` 选项说明。`rootGroupCollapsed`选项设置是否展开根组的子项。如果指定的默认值为 `null` 或 `undefined`,则不显示展开/折叠按钮。如果该值为 `true`,子项将以折叠方式显示;如果为 `false`,子项将以展开方式显示。
433 |
434 | 此选项仅适用于顶层项目。有关一般项目的折叠性,请参阅 `collapsed` 选项。
435 |
436 | ## `useFolderLinkFromSameNameSubFile`
437 |
438 | - Type: `boolean`
439 | - Default: `false`
440 |
441 | 如果此值为`true`,则当存在与文件夹同名的子文件时,将在文件夹中创建一个链接,用于导航至该文件,而该文件不会显示在子项中。
442 |
443 | 例如,如果您有一个文件夹,如下所示:
444 |
445 | ```
446 | docs/
447 | ├─ guide/
448 | │ ├─ api/
449 | │ │ └─ api.md
450 | │ ├─ one.md
451 | │ └─ two.md
452 | └─ config/
453 | └─ index.md
454 | ```
455 |
456 | 在 `api` 文件夹中添加了一个链接,而 `api` 文件夹中的 `api` 页面不包含在菜单列表中。点击文件夹中的链接会显示 `api/api.md`中的文件。
457 |
458 | ## `folderLinkNotIncludesFileName`
459 |
460 | - Type: `boolean`
461 | - Default: `false`
462 |
463 | 此选项仅在特殊情况下使用:当您有 [rewrite](https://vitepress.dev/guide/routing#route-rewrites) 规则并且存在具有相同文件夹名称的子文件时,请将其与 `useFolderLinkFromSameNameSubFile` 选项并行使用。
464 |
465 | **注意:** 如果您在未配置 VitePress rewrites 的情况下启用此选项,点击文件夹链接将导致 404 错误。请确保在您的 VitePress 配置中设置相应的 rewrite 规则。
466 |
467 | 如果此值为 `true`,则在建立文件夹链接时,忽略子项的存在,并仅将链接指定为文件夹路径。
468 |
469 | 例如,如果您有一个如下所示的文件夹:
470 |
471 | ```
472 | docs/
473 | ├─ guide/
474 | │ ├─ api/
475 | │ │ └─ api.md
476 | │ ├─ one.md
477 | │ └─ two.md
478 | └─ config/
479 | └─ index.md
480 | ```
481 |
482 | 使用 `useFolderLinkFromSameNameSubFile` 选项,单击 guide/api 文件夹菜单将带您进入 `guide/api/api`,但如果您使用 `folderLinkNotIncludesFileName` 选项,则链接将为 `guide/api/`。
483 |
484 | 要使此功能正常工作,您需要配置 VitePress rewrites 将文件夹路径映射到实际文件。在您的 `.vitepress/config.ts` 中添加以下内容:
485 |
486 | ```typescript
487 | export default defineConfig({
488 | rewrites: {
489 | 'guide/api/api.md': 'guide/api/index.md'
490 | }
491 | });
492 | ```
493 |
494 | 或者使用动态 rewrite 函数来处理多个文件夹:
495 |
496 | ```typescript
497 | export default defineConfig({
498 | rewrites(id) {
499 | // 将 'folder/folder.md' 重写为 'folder/index.md'
500 | return id.replace(/([^/]+)\/\1\.md$/, '$1/index.md');
501 | }
502 | });
503 | ```
504 |
505 | ## `keepMarkdownSyntaxFromTitle`
506 |
507 | - Type: `boolean`
508 | - Default: `false`
509 |
510 | 如果此值为 `true`,则保留标题文本中包含的 Markdown 语法,而不删除它。通常会保留任何高亮或内联代码。无论是否使用此选项,超链接文本都会被移除。
511 |
512 | ## `debugPrint`
513 |
514 | - Type: `boolean`
515 | - Default: `false`
516 |
517 | 如果该值为`true`,则会将执行后创建的对象打印到控制台日志中。如果您配置了多个侧边栏,即使只包含其中一个选项,它也会输出所有侧边栏的结果。
518 |
--------------------------------------------------------------------------------