Compare commits

...

341 Commits

Author SHA1 Message Date
pengzhanbo
d69e0b9765 ci: update workflow permissions 2026-04-22 17:07:34 +08:00
pengzhanbo
02038f2df0 build: publish v1.0.0-rc.196 2026-04-19 14:37:52 +08:00
pengzhanbo
e5126663ef fix: fix security 2026-04-19 14:34:47 +08:00
pengzhanbo
402f259086
refactor(plugin-md-power): refactor obsidian plugins (#893) 2026-04-19 14:10:54 +08:00
pengzhanbo
58ea2fc8cb
fix(theme): remove cwd options from picomatch (#892) 2026-04-19 14:10:40 +08:00
pengzhanbo
6ebb1bda6e
fix(plugin-md-power): fix cell display issue caused by colspan in table (#891) 2026-04-19 14:10:22 +08:00
pengzhanbo
68f39695c4 chore: update tsconfig 2026-04-19 14:09:52 +08:00
pengzhanbo
76787f6530 build: publish v1.0.0-rc.195 2026-04-18 17:13:48 +08:00
pengzhanbo
e2b47da532 chore: tweak 2026-04-18 17:09:26 +08:00
pengzhanbo
035d521e96 chore: update deps to latest 2026-04-18 17:07:12 +08:00
pengzhanbo
bfd0c8409c
feat(plugin-md-power): compat obsidian official markdown syntax (#890)
* feat(plugin-md-power): compat obsidian official markdown syntax

* chore: tweak

* chore: tweak

* chore: tweak

* chore: tweak
2026-04-18 17:01:41 +08:00
pengzhanbo
e11c7a8fcd build: publish v1.0.0-rc.194 2026-04-14 15:37:37 +08:00
pengzhanbo
1329051536 chore: tweak 2026-04-14 15:36:15 +08:00
pengzhanbo
0677f6749e chore: update deps to latest 2026-04-14 15:31:38 +08:00
pengzhanbo
28963eb419
fix(plugin-search): fix search index race condition on pageUpdated, close #888 (#889) 2026-04-14 15:29:58 +08:00
pengzhanbo
cfc89adab8 chore: update security deps 2026-04-04 16:35:48 +08:00
pengzhanbo
e0ba59a6f9 build: update changelog 2026-04-03 02:56:28 +08:00
pengzhanbo
352874b29a build: publish v1.0.0-rc.193 2026-04-03 02:25:46 +08:00
pengzhanbo
c824ad85f4 chore: update gitignore 2026-04-03 02:18:23 +08:00
pengzhanbo
db2eda82f3 build: update clean scripts 2026-04-03 02:18:01 +08:00
pengzhanbo
e9fe35bc4f
fix(theme): fix sidebar items prefix not handled correctly, close #876 (#885) 2026-04-03 02:13:18 +08:00
pengzhanbo
709ade741c chore: improve comment 2026-04-03 02:06:32 +08:00
pengzhanbo
d8b79e89e8
refactor(plugin-search): improve search index update (#884) 2026-04-03 01:58:25 +08:00
pengzhanbo
dbc6f0be0f
fix(theme): fix auto-sidebar group icon error inherit, close #873 (#883) 2026-04-02 22:05:54 +08:00
pengzhanbo
9fe294b9dd fix(theme): fix MarkdownOptions types 2026-04-02 21:15:33 +08:00
pengzhanbo
ecf100cfc6 docs: update security.md 2026-04-02 21:15:08 +08:00
pengzhanbo
b7ee45642e docs: update contributing.md 2026-04-02 21:14:51 +08:00
pengzhanbo
54c05c8cea docs: add claude.md 2026-04-02 21:14:34 +08:00
pengzhanbo
86cb872ce6 refactor: migrate onWatched to onPageUpdated 2026-04-02 21:14:16 +08:00
pengzhanbo
a6cb3820b1 refactor: remove deprecated enhancement 2026-04-02 21:12:59 +08:00
pengzhanbo
184d1aee76 build: improve tsdown bundle config 2026-04-02 20:59:23 +08:00
pengzhanbo
cbc5c55891 perf: update deps to latest 2026-04-02 20:57:51 +08:00
mcenahle
4f40f8441d
docs: add "mcenahle Docs" to demo page (#882)
* Update demos.md

* chore: fix URLs for 哦麦 MC logo and preview images

Updated logo and preview image URLs for 哦麦 MC in demos.md.

---------

Co-authored-by: pengzhanbo <volodymyr@foxmail.com>
2026-04-02 20:54:47 +08:00
pengzhanbo
fe0d4bbc92
feat: improve accessibility features (#869) 2026-04-02 20:49:20 +08:00
pengzhanbo
39a76a35d7
feat(plugin-md-power)!: use # as the comment delimiter (#870) 2026-04-02 20:48:55 +08:00
pengzhanbo
a01bc13c66
fix(plugin-md-power): fix tsdown icon (#878) 2026-04-02 20:48:34 +08:00
pengzhanbo
1b213d4c28
fix(theme): add bulletin to outline ignores (#879) 2026-04-02 20:48:10 +08:00
pengzhanbo
aede6f5d87
fix(theme): twoslash comment error (#881)
* fix(theme): fix incorrect auto-sidebar-link parse

* fix(theme): twoslash comment error
2026-04-02 16:38:33 +08:00
pengzhanbo
7febfbf237
fix(theme): fix incorrect auto-sidebar-link parse (#880) 2026-04-02 16:37:58 +08:00
suixinio
7ce4e40521
docs: update ohmymc img (#877)
docs: update ohmymc img
2026-04-02 14:34:49 +08:00
zhenghaoyang24
12c4f5b39e
docs: fix icon documentation links (#874)
- Update relative paths in markdown config documentation to point
  to correct guide location
- Change sidebar icons link from document.md to quick-start/sidebar.md
  for proper navigation structure
2026-04-02 14:34:14 +08:00
pengzhanbo
aa54090b5d docs: update sponsor 2026-03-19 02:09:31 +08:00
逸燧Esyka
192b260d2b
docs: update repository url for Esyka's blog (#872) 2026-03-15 16:41:38 +08:00
逸燧Esyka
75df783295
docs: add Esyka's Blog to demos (#871)
Added Esyka's Blog with relevant details.
2026-03-14 23:39:00 +08:00
pengzhanbo
97a5ba20c3 docs: fix typo 2026-03-08 21:55:27 +08:00
pengzhanbo
896c7e22df chore: improve theme code comments 2026-03-08 16:59:50 +08:00
pengzhanbo
77856e36c5 chore: improve plugin-md-power code comments 2026-03-08 16:35:52 +08:00
pengzhanbo
552f0f5c32 chore: improve plugin-search code comments 2026-03-08 16:16:04 +08:00
pengzhanbo
7751e4c798 chore: improve cli code comments 2026-03-08 16:15:26 +08:00
pengzhanbo
17646708b1 docs: update skills usage doc 2026-03-06 16:40:02 +08:00
pengzhanbo
f14d663bb5 docs: update skills 2026-03-06 15:54:30 +08:00
pengzhanbo
50fa747ec1 docs: update agent skills 2026-03-06 00:44:21 +08:00
pengzhanbo
f6da09df54 build: publish v1.0.0-rc.192 2026-03-05 15:35:45 +08:00
pengzhanbo
9b9f8f3f77 style: lint fix 2026-03-05 15:34:11 +08:00
pengzhanbo
aa19049f5b perf: update deps to latest 2026-03-05 14:56:16 +08:00
pengzhanbo
fd1dd7c695
feat(theme): add lang switch to update html lang attr (#867) 2026-03-05 14:42:48 +08:00
pengzhanbo
916e9141d9
fix(plugin-md-power): fix potential null pointer exceptions when parsing collapse containers (#866) 2026-03-05 14:41:47 +08:00
pengzhanbo
ca51a345fb
fix(theme): fix the calculation error in the post cover ratio and add link to cover, close #863 (#865) 2026-03-05 14:41:30 +08:00
pengzhanbo
f11e8501d0
fix(theme): fix missing attribute for <VPHomePosts> (#864) 2026-03-05 14:41:11 +08:00
pengzhanbo
3f047914d5 build: publish v1.0.0-rc.191 2026-02-25 22:14:10 +08:00
pengzhanbo
0a3810be2b chore: tweak 2026-02-25 22:12:38 +08:00
pengzhanbo
c541e05997 perf: update deps to latest 2026-02-25 22:04:15 +08:00
pengzhanbo
feb69a282e build: update target Node.js version to 20.19.0 in tsdown.config.mjs files 2026-02-25 22:03:51 +08:00
pengzhanbo
c109d54961
feat: rewrite app.writeTemp to resolve IO race conditions (#862) 2026-02-25 21:50:50 +08:00
pengzhanbo
948c31779b
fix(plugin-search): fix temporary file IO race condition (#861) 2026-02-25 21:50:31 +08:00
pengzhanbo
09a95b7597
fix(plugin-md-power): fix timeout when retrieving remote image size (#860) 2026-02-25 21:50:08 +08:00
pengzhanbo
ce32605aee
feat(plugin-md-power): rename demo-wrapper container to window (#858) 2026-02-25 21:48:39 +08:00
𝙁𝙡𝙖𝙨𝙝
f7d3546962
docs: update 【haipeng-lin】demo (#859) 2026-02-20 00:44:33 +08:00
pengzhanbo
5980fd81f3 build: publish v1.0.0-rc.190 2026-02-15 12:33:55 +08:00
pengzhanbo
f2fe79f923 fix(plugin-md-power): fix timeout issue when retrieving image size 2026-02-15 12:32:33 +08:00
pengzhanbo
7234eebe7e fix(plugin-search): fix incorrect prepare search index 2026-02-15 12:31:46 +08:00
pengzhanbo
479680bba6 docs: update docs 2026-02-15 12:24:31 +08:00
pengzhanbo
cd68f1cdd9 build: publish v1.0.0-rc.189 2026-02-15 11:43:40 +08:00
pengzhanbo
97c7a53aed chore: update deps to latest 2026-02-15 11:41:37 +08:00
pengzhanbo
03dc9da8dc docs: update home page 2026-02-15 11:41:17 +08:00
pengzhanbo
a4c9c85b00
refactor(plugin-md-power): optimize image size (#856) 2026-02-15 11:33:40 +08:00
pengzhanbo
1ed3dd9154
refactor(plugin-search): optimize search data generate (#855) 2026-02-15 11:33:24 +08:00
pengzhanbo
bfd1d1692f
refactor(cli): improve packageJson generate (#854) 2026-02-15 11:33:09 +08:00
pengzhanbo
6db6a58c27
chore: tweak (#857) 2026-02-15 11:32:47 +08:00
pengzhanbo
9751059fcd docs: update readme 2026-02-15 11:23:16 +08:00
pengzhanbo
fc9984b27c test: improve unit test 2026-02-14 20:03:44 +08:00
pengzhanbo
5930c60462 docs: improve docs 2026-02-14 18:14:19 +08:00
pengzhanbo
f173d069bd refactor(theme): fix event listener leaks 2026-02-14 18:14:00 +08:00
pengzhanbo
5c201e3ed0
docs: improve jsdoc (#852) 2026-02-14 14:53:41 +08:00
pengzhanbo
77da8a3470
fix(cli): fix failure to retrieve OS language (#851) 2026-02-14 14:53:23 +08:00
pengzhanbo
9c3899135b docs: update readme 2026-02-14 14:48:01 +08:00
pengzhanbo
dc160b3db4 build: publish v1.0.0-rc.188 2026-02-13 21:12:45 +08:00
pengzhanbo
84bd873efa chore: improve vue-router deps 2026-02-13 21:10:17 +08:00
pengzhanbo
8d4ce99c16 perf: update deps to latest 2026-02-13 20:28:12 +08:00
pengzhanbo
8a873e1e58 style: lint fix 2026-02-13 20:27:38 +08:00
pengzhanbo
2780abd782
feat(plugin-md-power): add copy button for file-tree container, close #835 (#837)
* feat(plugin-md-power): add copy button for file-tree container, close #835

* chore: tweak
2026-02-13 01:16:47 +08:00
pengzhanbo
b1f996cb0e
feat(plugin-md-power): add ::: encrypt container, close #815 (#831)
* feat(plugin-md-power): add `::: encrypt` container

* chore: tweak

* chore: tweak

* chore: tweak
2026-02-12 23:55:21 +08:00
pengzhanbo
78a2859398
perf: optimize memory usage during build time (#850) 2026-02-12 21:11:01 +08:00
pengzhanbo
8daddcac5d chore: update vuepress deps to latest 2026-02-12 01:16:46 +08:00
pengzhanbo
c5759e3a2e chore(theme): add default locale to llmstxt plugin 2026-02-12 01:08:00 +08:00
pengzhanbo
3e68b44771
feat(theme): add sidebar collapse button, close #687 (#839) 2026-02-12 01:02:57 +08:00
pengzhanbo
d2b4654ae3
fix(theme): fix prev/next nav when include sep, close #846 (#849) 2026-02-12 01:01:13 +08:00
pengzhanbo
5a73b59297
fix(theme): broken card a11y, close #841 (#848) 2026-02-12 01:00:52 +08:00
pengzhanbo
98a969c112
fix(theme): fix overflow scrolling in the tab container nav, close #842 (#847) 2026-02-12 01:00:03 +08:00
pengzhanbo
8cd08f4f02
feat(plugin-search): add language-based text segmentation support for search (#838) 2026-02-12 00:59:35 +08:00
pengzhanbo
32e4f92c61
feat(plugin-md-power): add icons about ai (#836) 2026-02-12 00:59:02 +08:00
pengzhanbo
d573fada7a
feat(theme): improve title template (#833)
* feat(theme): improve title template

* chore: tweak
2026-02-12 00:58:33 +08:00
pengzhanbo
a13ed1f503
fix(theme): navbar dropdown renders incorrectly in Safari, close #830 (#832) 2026-02-12 00:57:41 +08:00
pengzhanbo
07c274cdbf
feat: add agent skills (#823)
* feat: add agent skills

* chore: tweak
2026-01-29 15:52:29 +08:00
Konata9
ab4ff06756
docs: add Konata9's Blog (#834)
* chore: Add konata9's blog

* style: lint fix

---------

Co-authored-by: pengzhanbo <volodymyr@foxmail.com>
2026-01-27 11:31:34 +08:00
pengzhanbo
b65529743e docs: update sponsor 2026-01-22 13:17:29 +08:00
pengzhanbo
c46379bc9f docs: update pdf assets 2026-01-20 23:34:40 +08:00
Kairui Liu
6cd8066ee0
docs: add a website demo to the documentation (#827) 2026-01-20 14:41:19 +08:00
pengzhanbo
4ad05ad9f5 build: publish v1.0.0-rc.187 2026-01-19 23:50:07 +08:00
pengzhanbo
6a41d44322 fix(theme): incorrect icon name validation 2026-01-19 23:48:35 +08:00
pengzhanbo
f804ba8420 build: publish v1.0.0-rc.186 2026-01-19 21:56:46 +08:00
pengzhanbo
2a5bd30fe3 perf: update deps to latest 2026-01-19 21:45:42 +08:00
pengzhanbo
a3d8e225b9
feat(theme): add filepath permalink support for auto frontmatter, #815 (#822) 2026-01-19 21:43:41 +08:00
pengzhanbo
f51dff1d58
feat(plugin-md-power): add markdown env presets, #815 (#818) 2026-01-19 21:41:17 +08:00
pengzhanbo
85fc35f119
fix(theme): fix multiple icon provider (#826) 2026-01-19 21:40:47 +08:00
pengzhanbo
48970dd559
fix(theme): fix theme config hmr fail (#820) 2026-01-19 21:40:23 +08:00
pengzhanbo
1dfbb872f7
fix(theme): fix page encrypt password type error (#819) 2026-01-19 21:39:50 +08:00
pengzhanbo
79397faa65
feat(theme): add perplexity to context menu (#817) 2026-01-19 21:38:45 +08:00
来自梦里的一条鱼
7b17ccf378
docs: update haipeng-lin.cn demo (#824) 2026-01-17 17:08:23 +08:00
CuteLittleSky
7a0aee5fb9
docs: add SKYCRAFT server to Demo (#821) 2026-01-15 18:34:59 +08:00
Paiad
a94333d9bd
docs: revise Paiad demo information
Updated the details for the Paiad demo, including name, description, logo, URL, and preview image.
2026-01-13 22:32:39 +08:00
pengzhanbo
5217be0bfc build: publish v1.0.0-rc.185 2026-01-09 15:44:39 +08:00
pengzhanbo
6420ddf8ba chore: update deps to latest 2026-01-09 15:42:08 +08:00
pengzhanbo
6656b3213b docs: add contributor 2026-01-09 15:35:00 +08:00
pengzhanbo
a74c475d7c perf: update deps to latest 2026-01-09 15:33:11 +08:00
pengzhanbo
6d0781b647 chore: tweak 2026-01-09 15:32:49 +08:00
Dahaha
cc3582c1f9
feat(theme): add support for base64 for profile avatars (#808) 2026-01-09 15:22:32 +08:00
pengzhanbo
2cadb7d88c
fix(theme): add slot existence check in VPDocFooter, close #809 (#811) 2026-01-09 15:19:52 +08:00
pengzhanbo
7ed70230af
fix(theme): fix custom social icon rendering misalignment (#812) 2026-01-09 15:19:25 +08:00
pengzhanbo
36c0eddd86 docs: update sponsor 2026-01-03 20:07:24 +08:00
pengzhanbo
b242e59bbe build: publish v1.0.0-rc.184 2025-12-28 15:25:01 +08:00
pengzhanbo
9bbba1ada6
fix(theme): incorrect url convert in PageContextMenu (#807)
* fix(theme): incorrect url convert in `PageContextMenu`

* test: migrate to v8

* perf: update deps to latest
2025-12-28 15:09:32 +08:00
pengzhanbo
e2c9d50539 docs: fix typo 2025-12-28 14:11:59 +08:00
pengzhanbo
ed5c53f494 chore: remove .npmrc 2025-12-28 14:11:36 +08:00
pengzhanbo
fe9ee0dbfc
feat(plugin-md-power): improve caniuse syntax (#806) 2025-12-28 14:00:53 +08:00
pengzhanbo
2bcf761ef1 docs: update sponsor 2025-12-26 23:33:25 +08:00
Lucas
ccf34d4bc8
docs: add demo for Lucas blog (#804) 2025-12-21 23:42:27 +08:00
pengzhanbo
f7c0fe0dd3 docs: update sponsor 2025-12-16 15:15:23 +08:00
only9464
3f9422df83
docs: add HEUOpenResource to demos.md (#803)
Added HEUOpenResource project details to demos.
2025-12-15 19:54:56 +08:00
来自梦里的一条鱼
46ec0fb123
docs: update haipeng-lin site demo (#802) 2025-12-15 11:52:18 +08:00
pengzhanbo
a5f6f991f8 build: publish v1.0.0-rc.183 2025-12-14 01:59:57 +08:00
pengzhanbo
eb73f3d3f1 perf: update deps to latest 2025-12-14 01:57:06 +08:00
pengzhanbo
a15f4e206d
fix: fix incorrect icon rendering, close #799 (#800) 2025-12-14 01:34:50 +08:00
pengzhanbo
ce19b84232
fix(theme): fix incorrect code block rendering within card, close #798 (#801) 2025-12-14 01:34:33 +08:00
pengzhanbo
b86a121707 docs: update component and config 2025-12-14 01:33:46 +08:00
pengzhanbo
c0bb6bcc14 build: publish v1.0.0-rc.182 2025-12-13 16:50:11 +08:00
pengzhanbo
98684ed66a perf: update deps to latest 2025-12-13 16:40:31 +08:00
pengzhanbo
15aa159999 docs: update Demos component 2025-12-13 16:39:40 +08:00
pengzhanbo
956869ab1e
fix(plugin-md-power): fix file-tree container incorrectly rendering in nesting content, close #795 (#797) 2025-12-13 16:18:36 +08:00
pengzhanbo
6e601f9f0e
feat(theme): add meta config support for collection, close #781 (#796) 2025-12-13 15:45:55 +08:00
pengzhanbo
f7bc044147 refactor(theme): improve CodeRepl and DocFooter styles 2025-12-12 20:53:43 +08:00
pengzhanbo
a91cdb60d7 chore: tweak 2025-12-12 20:52:48 +08:00
pengzhanbo
15e62010c2
feat(theme): add cols frontmatter support for friends page, close #781 (#792) 2025-12-12 20:41:30 +08:00
pengzhanbo
a350e62645
fix(plugin-md-power): fix mark lazy animation, close #789 (#791) 2025-12-12 20:41:09 +08:00
pengzhanbo
95d345bf6d
refactor(theme): social icon support all iconify icons, close #781 (#790) 2025-12-12 20:40:50 +08:00
pengzhanbo
c42a601467
refactor(theme): improve post copyright styles, close #780 (#788) 2025-12-12 20:40:30 +08:00
pengzhanbo
46797a0757
fix(theme): fix render overflow of code block within Card on mobile, close #782 (#787) 2025-12-12 20:40:04 +08:00
pengzhanbo
65da8469ce
feat(cli): update lowest version support for nodejs (#786) 2025-12-12 20:39:28 +08:00
pengzhanbo
6383347813
fix(theme): fix boundary detection error for config on home (#785) 2025-12-12 20:39:03 +08:00
pengzhanbo
2c360ac59e
feat(theme): add theme config changed logger (#784) 2025-12-12 20:38:34 +08:00
pengzhanbo
b128511c28 docs: update sponsor 2025-12-10 17:01:56 +08:00
pengzhanbo
8f2f93ec7e build: publish v1.0.0-rc.181 2025-12-05 22:59:22 +08:00
pengzhanbo
8faba7bf10 perf: update deps to latest 2025-12-05 22:57:20 +08:00
pengzhanbo
c8ab57e843 chore: tweak 2025-12-05 22:56:51 +08:00
pengzhanbo
9a77bf4eef docs: update sponsor 2025-12-05 22:25:46 +08:00
pengzhanbo
157281aec8
feat(plugin-md-power): add qrcode syntax plugin for markdown (#777)
* feat(plugin-md-power): add  qrcode syntax plugin for markdown

* chore: tweak
2025-12-05 17:18:13 +08:00
pengzhanbo
07710247bb
fix(theme): fix parsing error for relative path link (#779) 2025-12-05 17:16:48 +08:00
pengzhanbo
9b2b73e05b
fix(theme): fix doc-footer text decoration (#778) 2025-12-05 17:16:30 +08:00
pengzhanbo
8f3c070d07 docs: tweak 2025-12-05 17:07:05 +08:00
pengzhanbo
29b5197c47 test: improve unit test 2025-12-05 17:06:41 +08:00
pengzhanbo
5f82bdeb67
fix(theme): fix home hero background tint-plate rendering fail, close #775 (#776) 2025-12-04 14:10:27 +08:00
pengzhanbo
d677fc99de docs: update sponsor 2025-12-04 14:06:18 +08:00
pengzhanbo
4b1cecf2bd
feat(theme): migrate bcrypt-ts to hash-wasm (#774) 2025-12-03 17:16:14 +08:00
pengzhanbo
32f4a8be5a
feat(plugin-md-power): add markdown-it-cjk-friendly plugin (#773) 2025-12-03 13:41:18 +08:00
pengzhanbo
3553022597
fix(theme): fix navbar horizontal overflow (#772) 2025-12-03 13:35:57 +08:00
pengzhanbo
cd37921975
fix(theme): fix sidebar curtain position-top (#771) 2025-12-03 13:35:12 +08:00
pengzhanbo
78b4b9f572 docs: add tools 2025-12-03 13:34:19 +08:00
pengzhanbo
ab4354e648 docs: add contributor 2025-12-03 13:33:55 +08:00
pengzhanbo
20ebeb5e62
feat(theme): support encryption for all page layouts (#770) 2025-12-03 13:25:16 +08:00
gnehs
4957c8b1de
fix(theme): blockquote icon color in dark mode (#769) 2025-12-03 13:24:55 +08:00
gnehs
3df96e2702
fix(i18n): update Traditional Chinese translations for search and theme locales (#767) 2025-12-02 17:35:21 +08:00
pengzhanbo
3c4985ac1a build: publish v1.0.0-rc.180 2025-12-01 11:38:47 +08:00
pengzhanbo
3a907e0ba8 perf: update deps to latest 2025-12-01 11:37:01 +08:00
pengzhanbo
db8a46eb4c
docs: optimize and completion docs (#766) 2025-12-01 11:30:33 +08:00
pengzhanbo
c97a5af473
feat(cli): optimize template (#765) 2025-12-01 11:30:06 +08:00
pengzhanbo
bba98984d6
fix: support nested ordered lists in collapse plugin (#764) 2025-12-01 11:29:45 +08:00
pengzhanbo
41d2a81a09
fix(theme): fix hybrid mismatch (#763) 2025-12-01 11:29:26 +08:00
pengzhanbo
6a3babcf76
perf(theme): optimize VPFooter and VPFriends layout (#762) 2025-12-01 11:29:05 +08:00
pengzhanbo
f599a4223c
fix(theme): llmstxt should exclude encrypt page (#761) 2025-12-01 11:28:21 +08:00
pengzhanbo
e0b972c3cb
fix(theme): incorrect displaying external link icon (#760) 2025-12-01 11:27:59 +08:00
pengzhanbo
2bb5c0e2d5 ci: update workflow 2025-11-28 22:32:18 +08:00
pengzhanbo
7691cdc9a0 build: publish v1.0.0-rc.179 2025-11-26 01:26:47 +08:00
pengzhanbo
c1f59cf451 perf: update deps to latest 2025-11-26 01:23:22 +08:00
pengzhanbo
fc3676d6dc
feat(theme): add support for {data-outline="level"} attribute syntax for headings, close #757 (#759) 2025-11-26 01:13:24 +08:00
pengzhanbo
73f4935ca9
feat(theme): exclude encrypt page in llmstxt (#758) 2025-11-26 01:13:04 +08:00
pengzhanbo
f9b8c6adf2
refactor(theme): refactor link detector, close #754 (#756)
* refactor(theme): refactor link detector

* chore: tweak
2025-11-26 01:12:42 +08:00
pengzhanbo
8c1d34cb87 chore: tweak 2025-11-26 01:09:57 +08:00
pengzhanbo
631188df85 ci: migrate release publish to github actions 2025-11-26 01:08:30 +08:00
pengzhanbo
a9082dc012 docs: update sponsor 2025-11-25 21:05:53 +08:00
pengzhanbo
1b62b0bf6c docs: update sponsor 2025-11-25 14:55:45 +08:00
yxzlwz
75c12ba458
docs: update demos for YXZL (#755) 2025-11-21 12:56:49 +08:00
pengzhanbo
25c3880ea4 chore: tweak 2025-11-20 21:29:27 +08:00
pengzhanbo
ddb77a06a5 feat(theme): add footer frontmatter 2025-11-20 21:09:26 +08:00
pengzhanbo
a4bea8202b feat(cli): add env config to template 2025-11-20 21:09:06 +08:00
pengzhanbo
57617e6658 docs: update QA 2025-11-20 21:08:43 +08:00
pengzhanbo
ea54d08a50 docs: update demos 2025-11-20 21:08:25 +08:00
pengzhanbo
945cc72860 build: publish v1.0.0-rc.178 2025-11-19 17:02:41 +08:00
pengzhanbo
4884b1acce perf: update deps to latest 2025-11-19 16:59:03 +08:00
pengzhanbo
532ad960a4 docs: add llms redirect 2025-11-19 16:55:00 +08:00
pengzhanbo
ad1f02de62 fix(theme): fix post-list width overflow 2025-11-19 16:54:41 +08:00
pengzhanbo
20728f504d
feat(theme): add plugin-llms and <PageContextMenu /> component (#753) 2025-11-19 16:51:49 +08:00
pengzhanbo
5b780c28d0 docs: update llms config 2025-11-18 21:08:22 +08:00
TinyPiXOS-Dev
e8fa516b2e
docs: update demos.md (#752)
增加TinyPiXOS案例,TinyPiXOS是一款独立可控、架构轻量且高度定制化的嵌入式桌面操作系统,官网和技术文档均采用plume主题构建。
2025-11-18 19:15:24 +08:00
pengzhanbo
e87ae4fc16 build: publish v1.0.0-rc.177 2025-11-14 18:01:17 +08:00
pengzhanbo
5b07f2dd21 perf: update deps to latest 2025-11-14 17:49:51 +08:00
pengzhanbo
6fc6385de4 feat(cli): typescript as a required dependency 2025-11-14 17:45:08 +08:00
pengzhanbo
ab26dec457 feat(theme): when navbar is empty, no preset is applied 2025-11-14 17:43:19 +08:00
pengzhanbo
4119b67e0b fix(theme): fix fixed position failure in Safari 2025-11-14 17:15:48 +08:00
pengzhanbo
05d55e5035 fix(theme): fix table max-width overflow 2025-11-14 17:12:45 +08:00
pengzhanbo
f95e7c8412 feat(theme): optimize VPCollapse styles within Card 2025-11-14 17:09:42 +08:00
pengzhanbo
4e7fb91a56 build: publish v1.0.0-rc.176 2025-11-09 15:05:55 +08:00
pengzhanbo
cd120220f2 build: update tsdown config 2025-11-09 15:00:32 +08:00
pengzhanbo
a63c094df9 fix(theme): fix use admin decrypt page error 2025-11-09 14:59:10 +08:00
pengzhanbo
336205627e perf: update deps to latest 2025-11-09 13:58:48 +08:00
pengzhanbo
a5dfef7202
feat(theme): optimize page encrypt (#750) 2025-11-09 13:48:15 +08:00
pengzhanbo
87cda0c824 test: update vitest config 2025-11-09 13:33:21 +08:00
Hao Chen
b6ee4a4b3d
fix(theme): conditionally render post navigation links on mobile devices (#749) 2025-11-01 22:27:27 +08:00
Hao Chen
2fc6ea5064
fix(cli): corrects function call for defining multiple collections (#748) 2025-11-01 21:46:44 +08:00
pengzhanbo
aa8e774a1b build: publish v1.0.0-rc.175 2025-10-31 20:29:24 +08:00
pengzhanbo
606f47a5a6 perf: update deps to latest 2025-10-31 20:22:59 +08:00
pengzhanbo
e6daf07456 style: lint fix 2025-10-31 20:22:37 +08:00
pengzhanbo
3d48446769
feat(theme): add dark-veil home hero effect (#747) 2025-10-31 18:33:57 +08:00
pengzhanbo
802911c179 perf(theme): cleanup home hero effect when unmounted 2025-10-31 18:08:15 +08:00
pengzhanbo
192017b892
fix(theme): fix auto-sidebar collapsed (#746) 2025-10-31 18:03:06 +08:00
pengzhanbo
cfa70320c8
docs(theme): fix tint-plate tools (#745)
see #742
2025-10-31 17:53:35 +08:00
pengzhanbo
d4ad65a1ea
refactor: use deconstruct syntax to handle component props (#744) 2025-10-31 17:42:28 +08:00
pengzhanbo
0e38265f96
feat(plugin-md-power): add full-width support for table container, close #740 (#741) 2025-10-29 20:45:22 +08:00
pengzhanbo
fbb6ec9a63 feat(theme): optimize local nav 2025-10-26 23:18:44 +08:00
pengzhanbo
19868d147e fix(theme): fix language component not displaying correctly 2025-10-26 23:17:46 +08:00
pengzhanbo
73e6b9d5ca build: publish v1.0.0-rc.174 2025-10-25 12:31:36 +08:00
pengzhanbo
ca3986917c perf: update deps to latest 2025-10-25 12:29:19 +08:00
pengzhanbo
be565baf59 fix(theme): fix ssr compile error 2025-10-25 12:21:44 +08:00
pengzhanbo
aa6168c31d
feat(theme): add home hero effects (#738) 2025-10-25 11:55:17 +08:00
pengzhanbo
51e1f5260c perf: update deps to latest 2025-10-21 16:14:15 +08:00
yxzlwz
441b991b65
fix(plugin-md-power): avoid spellcheck in CodeEditor (#736)
Added spellcheck attribute to textarea for CodeEditor.
2025-10-20 21:47:09 +08:00
HAO CHEN
5fb7b7a216
docs: add Honahec's Blog to demos (#734) 2025-10-19 00:08:32 +08:00
Paiad
2d40e20f51
docs: update Paiad links and logo in demos.md (#733) 2025-10-18 21:39:30 +08:00
pengzhanbo
7f9d72416a build: publish v1.0.0-rc.173 2025-10-18 00:27:09 +08:00
pengzhanbo
ded49c4e88 perf: update deps to latest 2025-10-18 00:24:45 +08:00
pengzhanbo
0a23b94232
fix(theme): fix collection type error when the homepage is set as a posts, close #729 (#732) 2025-10-17 20:19:52 +08:00
pengzhanbo
6325d097cb ci: update issue templates 2025-10-17 19:41:31 +08:00
pengzhanbo
65d3c0551e ci: update issue templates 2025-10-17 18:27:33 +08:00
pengzhanbo
eeb2ce5350 docs: update sponsor 2025-10-17 17:27:35 +08:00
pengzhanbo
e0c0e639d0 chore: update security.md 2025-10-17 13:13:18 +08:00
pengzhanbo
1471547bcd fix(theme): fix the layout misalignment of the <VPButton /> fontawesome icon 2025-10-17 13:12:35 +08:00
rand777
6cd97bb4b8
docs: update demos.md (#731)
update info
2025-10-16 20:51:44 +08:00
pengzhanbo
1f2458f75c docs: update sponsor 2025-10-16 20:48:18 +08:00
pengzhanbo
437d56dd6c docs: update config 2025-10-16 02:24:57 +08:00
pengzhanbo
7adb00be5b build: publish v1.0.0-rc.172 2025-10-16 02:05:34 +08:00
pengzhanbo
74b4ddf8f5 perf: update deps to latest 2025-10-16 02:01:56 +08:00
pengzhanbo
d30325dd96 feat(cli): sort package.json 2025-10-16 00:31:52 +08:00
pengzhanbo
ca84eaeb13 chore: add pure-blog examples 2025-10-15 14:05:03 +08:00
pengzhanbo
0212ec34a8 chore: add pure-blog examples 2025-10-15 14:02:24 +08:00
pengzhanbo
707d534b95
fix(theme): fix post category sort error (#727) 2025-10-15 14:00:28 +08:00
pengzhanbo
4abc1eeb58
feat(theme): add icon to doc footer prev-next (#726) 2025-10-15 12:35:29 +08:00
pengzhanbo
1503a20fbe
feat(theme): optimize view transition (#725) 2025-10-15 12:34:16 +08:00
pengzhanbo
a2d52602d3 build: publish v1.0.0-rc.171 2025-10-13 23:56:15 +08:00
pengzhanbo
fffff72fcd docs: update docs 2025-10-13 15:27:15 +08:00
pengzhanbo
89cb6a585a
fix(theme): fix fontawesome icon, close #720 (#721) 2025-10-13 13:50:52 +08:00
pengzhanbo
c476c2059b
fix(theme): fix sidebar link concatenation error (#722) 2025-10-13 13:50:27 +08:00
pengzhanbo
1686836e38 docs: update docs 2025-10-13 01:14:26 +08:00
HAO CHEN
5c0d211d82
feat(plugin-md-power): add lazy animation mode for mark highlights (#718) 2025-10-12 21:56:15 +08:00
pengzhanbo
aa9c64f00f build: publish v1.0.0-rc.170 2025-10-12 15:42:08 +08:00
pengzhanbo
f505a2636e docs: update sponsor 2025-10-12 15:38:24 +08:00
pengzhanbo
8cec3f23e4
fix(theme): fix page transition flickering (#717) 2025-10-12 14:31:32 +08:00
pengzhanbo
338ca4ad7c fix(theme): optimize post category styles 2025-10-12 14:28:04 +08:00
pengzhanbo
86b7f2e695 docs: update sponsor 2025-10-12 14:27:15 +08:00
pengzhanbo
3a07f590cb
fix(theme): incorrect sidebar link prefix, close #714, #710 (#715) 2025-10-12 01:37:43 +08:00
pengzhanbo
0f350226ef build: add lunaria locales detector 2025-10-11 10:37:26 +08:00
pengzhanbo
729a0d6840 build: add lunaria locales detector 2025-10-11 10:31:40 +08:00
pengzhanbo
9afb57815c build: publish v1.0.0-rc.169 2025-10-09 21:41:32 +08:00
pengzhanbo
3b99ecc46f docs: update docs 2025-10-09 21:39:17 +08:00
pengzhanbo
a8c689f6e9 docs: update docs 2025-10-09 21:30:16 +08:00
pengzhanbo
4a8fd3f7fc docs: update docs 2025-10-09 21:19:07 +08:00
pengzhanbo
b3843c7d97
fix(theme): fix post collection links, close #709 (#712) 2025-10-09 21:13:39 +08:00
pengzhanbo
c2bd0f938e docs: update en docs 2025-10-09 15:54:07 +08:00
pengzhanbo
385059f214
docs: update en docs (#708)
* docs: update en docs

* chore: tweak

* chore: tweak

* chore: tweak
2025-10-09 15:46:05 +08:00
pengzhanbo
c6347676cd build: publish v1.0.0-rc.168 2025-10-08 20:10:00 +08:00
pengzhanbo
104370ca42 perf: update deps to latest 2025-10-08 20:08:38 +08:00
pengzhanbo
9f3de6b8ea fix(theme): sidebar prefix concat incorrectly 2025-10-08 12:50:49 +08:00
pengzhanbo
3b5e2cc5b3 fix(theme): fix I/O race condition causing auto frontmatter not to be written 2025-10-08 12:49:58 +08:00
pengzhanbo
53b90b512c build: publish v1.0.0-rc.167 2025-10-08 02:22:08 +08:00
pengzhanbo
9ed4acc097 docs: update docs 2025-10-08 02:20:31 +08:00
pengzhanbo
2e1ad23112 fix(theme): incorrect configuration loading and page generation sequence 2025-10-08 02:16:00 +08:00
pengzhanbo
133c4f996f build: publish v1.0.0-rc.166 2025-10-08 01:32:33 +08:00
pengzhanbo
b37af47dca feat(theme): add collection breaking change log 2025-10-08 01:29:20 +08:00
pengzhanbo
2a8385f3aa fix(theme): incorrect collection auto complete 2025-10-08 01:28:46 +08:00
pengzhanbo
22b65fd22c docs: update docs 2025-10-08 00:07:08 +08:00
pengzhanbo
b87a5cfd7a docs: update docs 2025-10-07 23:40:16 +08:00
pengzhanbo
4f7b0cabb6 build: publish v1.0.0-rc.165 2025-10-07 23:28:58 +08:00
pengzhanbo
5996f1062f build: update tsconfig 2025-10-07 23:23:51 +08:00
pengzhanbo
4d2361a704
feat(theme)!: add collections support (#704)
* feat(theme)!: add collection support
2025-10-07 23:13:09 +08:00
pengzhanbo
fae5825618
docs: update sponsor.md 2025-10-01 13:02:07 +08:00
yxzlwz
731b11f159
docs: add yxzlwz.dev sites to demos 2025-10-01 13:00:13 +08:00
Rbqwow
1dd9dabb63
docs: added maa to demo projects (#703) 2025-09-23 20:59:47 +08:00
pengzhanbo
a05aa7f598 build: publish v1.0.0-rc.164 2025-09-20 16:14:05 +08:00
pengzhanbo
687439e697 perf: update deps to latest 2025-09-20 16:11:37 +08:00
pengzhanbo
bb30b51a9b docs: update docs 2025-09-20 16:00:13 +08:00
pengzhanbo
9357b21af1 chore: tweak 2025-09-20 15:59:52 +08:00
huyunan
5cbf0ddfcf
feat(theme): add signdown frontmatter for home page (#691)
* signdow 参数添加 是否显示向下箭头标志

* VPSignDown components add.

* Delete the wrongly modified code.

* feat(theme): signdown parameter adds whether to display a downward arrow flag

* feat(theme): signdown marks are changed to be fixed

---------

Co-authored-by: wb_huyunan <wb_huyunan@kuaishou.com>
2025-09-20 15:19:23 +08:00
pengzhanbo
001896b5fa
fix(plugin-md-power): fix stringifyAttrs parse fail (#701) 2025-09-20 15:13:21 +08:00
pengzhanbo
69b9d0bc3d
fix(theme): fix createTime is obtained incorrectly during creation, close #692 (#700) 2025-09-20 15:12:44 +08:00
pengzhanbo
dd958c30cf
fix(plugin-md-power): fix title text overflow, close #698 (#699) 2025-09-20 15:12:25 +08:00
pengzhanbo
2bb5625eb4 chore: tweak 2025-09-20 14:05:18 +08:00
pengzhanbo
3523df74db
feat: add inheritAttrs option to components that include ClientOnly (#697) 2025-09-18 12:43:03 +08:00
pengzhanbo
7a95f6ab95 build: publish v1.0.0-rc.163 2025-09-10 12:58:31 +08:00
pengzhanbo
242ef3a7a8 perf: update deps to latest 2025-09-10 12:56:52 +08:00
pengzhanbo
086528606e
feat(theme): add password support for post frontmatter (#689) 2025-09-10 12:44:01 +08:00
pengzhanbo
2757301d61
fix(theme): fix CardMasonry media query failure (#688) 2025-09-10 12:43:27 +08:00
pengzhanbo
3051b5d146 docs: update sponsor 2025-09-09 21:16:25 +08:00
pengzhanbo
3bca540085 build: publish v1.0.0-rc.162 2025-09-03 23:54:26 +08:00
pengzhanbo
cfc9cefe78 perf: update deps to latest 2025-09-03 23:51:17 +08:00
pengzhanbo
5c00e4f9cf docs: update contributors 2025-09-03 23:42:06 +08:00
pengzhanbo
2c39edf849
fix(plugin-md-power): incorrect rending of footnote in annotation (#686) 2025-09-03 23:41:04 +08:00
Geekinney
46b2da25a6
feat(theme): make blog post list responsive to screen width (#685)
* Make blog post list responsive to screen width

* style: lint fix

---------

Co-authored-by: pengzhanbo <volodymyr@foxmail.com>
2025-09-01 12:50:22 +08:00
pengzhanbo
7c0dfc562e docs: update sponsor 2025-08-22 00:18:44 +08:00
SherkeyXD
0da7055c2b
feat(theme): add telegram social icon (#678)
* feat(icon): add telegram icon

* docs: update social icon list
2025-08-21 00:46:20 +08:00
pengzhanbo
6902067ea6 build: publish v1.0.0-rc.161 2025-08-20 03:19:41 +08:00
pengzhanbo
172aa3fb9c chore: update deps to latest 2025-08-20 03:14:40 +08:00
pengzhanbo
89314f4cb4 style: lint fix 2025-08-20 03:14:15 +08:00
pengzhanbo
22a5f10add
feat(plugin-search): optimize search index logger (#676) 2025-08-20 02:31:25 +08:00
pengzhanbo
94e755c422
feat(theme): add gitee provider support for repocard, close #674 (#675) 2025-08-20 02:31:09 +08:00
pengzhanbo
49d84dcfb4
feat(theme): add fullname prop support for RepoCard, close #669 (#670)
* feat(theme): add `fullname` prop support for `RepoCard`, close #669

* feat: add archive repo status
2025-08-19 23:14:31 +08:00
pengzhanbo
e8e8614d6e style: lint fix 2025-08-11 00:42:43 +08:00
pengzhanbo
96eb076496 build: fix tsdown build config 2025-08-11 00:36:59 +08:00
pengzhanbo
2059cf92ff build: fix tsdown build config 2025-08-11 00:13:41 +08:00
pengzhanbo
c8f16bbf43 chore: update deps to latest 2025-08-10 23:55:49 +08:00
pengzhanbo
27e9ab0982 build: fix tsdown build config 2025-08-10 23:40:48 +08:00
pengzhanbo
bc27437730 build: fix tsdown build config 2025-08-10 23:32:05 +08:00
pengzhanbo
21045599d0 docs: update changelog and contributing frontmatter 2025-08-10 00:08:47 +08:00
rand777
e32c2d2d6b
docs: update PGuide-Docs demo (#666) 2025-08-09 23:26:46 +08:00
1028 changed files with 75245 additions and 20887 deletions

1
.gitattributes vendored
View File

@ -4,6 +4,7 @@
*.png binary
*.jpg binary
*.jpeg binary
*.webp binary
*.ico binary
*.gif binary
*.tff binary

View File

@ -1,6 +1,6 @@
name: Bug report
description: Create a report to help us improve
title: '[Bug]'
title: '[Bug] '
labels:
- bug
assignees: pengzhanbo
@ -58,10 +58,16 @@ body:
description: A clear and concise description of what the bug is.
validations:
required: true
- type: input
id: reproduction
attributes:
label: Minimal reproduction
description: |-
If you are not reporting something obvious, a minimal reproduction repo and related log is required. you can fork [stackblitz.com](https://stackblitz.com/edit/vuepress-theme-plume-playground) to create a minimal reproduction.
placeholder: reproduction repo url
- type: textarea
id: additional-context
attributes:
label: Additional context
description: If you are not reporting something obvious, a minimal reproduction repo and related log is required.
description: If you are not reporting something obvious, related log is required.
placeholder: Add any other context about the problem here. Especially the issue occurs in certain OS, browser or configuration.

View File

@ -1,6 +1,6 @@
name: 问题报告
description: 创建一份问题报告以帮助我们改进
title: '[Bug]'
title: '[Bug] '
labels:
- bug
assignees: pengzhanbo
@ -58,10 +58,16 @@ body:
description: 一个清晰简洁的错误描述。
validations:
required: true
- type: input
id: reproduction
attributes:
label: 最小复现
description: |-
若非报告显而易见的问题,需提供最小化复现仓库及相关日志。你可通过 fork [stackblitz.com](https://stackblitz.com/edit/vuepress-theme-plume-playground) 来创建最小化复现环境。
placeholder: 复现项目 url
- type: textarea
id: additional-context
attributes:
label: 附加上下文
description: 如果你报告的问题不明显,需要提供最小复现仓库及相关日志。
description: 如果你报告的问题不明显,需要提供相关日志。
placeholder: 在此添加有关问题的其他上下文信息。特别是问题在特定操作系统、浏览器或配置下出现。

View File

@ -2,15 +2,25 @@ name: Deploy Docs
on:
push:
tags:
- v*
branches:
- main
paths:
# 以下文件发生变化时触发部署,这些文件与版本无关,因此可以自动更新
- docs/demos.md
- docs/sponsor.md
- CONTRIBUTING.md
- CONTRIBUTING.en-US.md
workflow_dispatch:
workflow_call:
permissions:
contents: write
jobs:
deploy-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
@ -18,9 +28,9 @@ jobs:
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
cache: pnpm
- name: Install deps

View File

@ -6,11 +6,14 @@ on:
- v*
workflow_dispatch:
permissions:
contents: write
jobs:
deploy-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
@ -18,9 +21,9 @@ jobs:
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
cache: pnpm
- name: Install deps

View File

@ -6,6 +6,10 @@ on:
pull_request:
branches: [main]
workflow_call:
permissions:
contents: read
jobs:
lint:
@ -13,15 +17,15 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
cache: pnpm
- name: Install deps

55
.github/workflows/release.yaml vendored Normal file
View File

@ -0,0 +1,55 @@
name: Release
on:
push:
tags:
- v*
permissions:
contents: write
id-token: write
jobs:
lint:
uses: ./.github/workflows/lint.yaml
test:
uses: ./.github/workflows/test.yaml
release:
if: github.repository == 'pengzhanbo/vuepress-theme-plume'
needs: [test, lint]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version: 24
registry-url: https://registry.npmjs.org
cache: pnpm
- name: Install deps
run: pnpm install
- name: Update npm
run: npm i -g npm@latest
- name: Build And Publish
id: publish
run: |
pnpm build
pnpm release:publish --no-git-checks
pnpm release:sync
- run: npx changelogithub
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
deploy:
uses: ./.github/workflows/docs-deploy.yaml

View File

@ -1,22 +0,0 @@
name: Add Release Tag
on:
push:
tags:
- v*
jobs:
changelog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npx changelogithub
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

View File

@ -6,6 +6,10 @@ on:
pull_request:
branches: [main]
workflow_call:
permissions:
contents: read
jobs:
unit-test:
@ -13,15 +17,15 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
cache: pnpm
- name: Install deps
@ -34,6 +38,6 @@ jobs:
- name: Upload coverage
if: github.ref == 'refs/heads/main'
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}

3
.gitignore vendored
View File

@ -15,3 +15,6 @@ dist/
coverage/
.idea
.claude/
!.claude/skills/

3
.npmrc
View File

@ -1,3 +0,0 @@
strict-peer-dependencies=false
shamefully-hoist=true
shell-emulator=true

View File

@ -76,6 +76,7 @@
"nprogress",
"pnpm",
"portfinder",
"qrcode",
"shiki",
"shikiji",
"shikijs",

File diff suppressed because it is too large Load Diff

111
CLAUDE.md Normal file
View File

@ -0,0 +1,111 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
vuepress-theme-plume is a VuePress 2 theme monorepo for building blogs, documentation, and knowledge bases.
It includes a main theme, several plugins, a CLI tool, and example implementations.
## Commands
```bash
# Install dependencies
pnpm install
# Build all packages (required after clone, outputs to lib/)
pnpm build
# Development - runs theme + docs dev servers concurrently
pnpm dev
# Lint (eslint + stylelint)
pnpm lint
pnpm lint:fix # auto-fix
# Run tests (vitest)
pnpm test
# Run a single test file
pnpm test src/path/to/file.spec.ts
# Run tests related to changed files (for pre-commit)
cross-env TZ=Etc/UTC vitest related --run
# Build docs only
pnpm docs:build
# Serve docs locally
pnpm docs:serve
# Release workflow
pnpm release # runs lint + build + version bump + changelog + git commit
```
## Monorepo Structure
```txt
├── theme/ # Main VuePress theme (vuepress-theme-plume)
├── plugins/ # VuePress plugins
│ ├── plugin-search/ # Full-text fuzzy search
│ ├── plugin-md-power/ # Markdown enhancements
│ └── plugin-fonts/ # Special character font support
├── cli/ # CLI tool (create project scaffolding)
├── docs/ # Documentation site
└── examples/ # Example implementations
├── pure-blog/
└── layout-slots/
```
## Theme Architecture
The theme is organized into three layers:
- **`src/node/`** - Build-time code (runs during `vuepress build/dev`)
- `prepare/` - Content preparation (frontmatter parsing, collection resolution)
- `plugins/` - VuePress plugin registration
- `config/` - Theme configuration handling
- `autoFrontmatter/` - Automatic frontmatter generation
- **`src/client/`** - Client-side code (runs in browser)
- `components/` - Vue components
- `composables/` - Vue composables (outline, search, etc.)
- `styles/` - CSS/SCSS styles
- `features/` - Feature-specific components and logic
- **`src/shared/`** - Shared code (used by both node and client)
- `frontmatter/` - Frontmatter schemas and utilities
- `locale/` - i18n translations
- `options.ts` - Theme options types
- `features/` - Feature flags and shared feature logic
## Build Output
Each package uses [tsdown](https://tsdown.dev/) to compile TypeScript. Build output goes to `lib/`:
- `lib/node/` - Node-side exports
- `lib/client/` - Client-side exports
- `lib/shared/` - Shared exports
The `lib/` directory is gitignored and must be built with `pnpm build`.
## Testing
Tests use Vitest with coverage enabled. Test files are located at `**/__test__/**/*.spec.ts` and are excluded from coverage reports. Run tests with timezone fixed to UTC to ensure consistent results.
## Key Dependencies
- **VuePress**: v2.0.0-rc.28 with @vuepress/bundler-vite
- **Vue**: ^3.5.30
- **Shiki**: ^4.x for syntax highlighting
- **VueUse**: ^14.x for composables
- **markdown-it**: ^14.x for Markdown processing
## Development Notes
- Node.js 20.19.0+ required
- pnpm catalogs are used for dependency management (`dev`, `peer`, `prod`, `vuepress`)
- The theme depends on `vuepress-plugin-md-power` and `@vuepress-plume/plugin-search` as workspace dependencies
- Some peer dependencies are optional (e.g., artplayer, dashjs, three.js)
- Plugins (`plugins/*`) do not have dev commands — changes require `pnpm build` to take effect
- The `lib/` directory is gitignored and must be rebuilt after `pnpm install`

View File

@ -19,7 +19,7 @@ In the `plugins` directory:
Development requirements:
- [Node.js](http://nodejs.org/) version 20.6.0+
- [Node.js](http://nodejs.org/) version 20.19.0+
- [pnpm](https://pnpm.io/zh/) version 9+
Clone the repository and install dependencies:

View File

@ -19,7 +19,7 @@
开发要求:
- [Node.js](http://nodejs.org/) version 20.6.0+
- [Node.js](http://nodejs.org/) version 20.19.0+
- [pnpm](https://pnpm.io/zh/) version 9+
克隆代码仓库,并安装依赖:

View File

@ -4,8 +4,8 @@
| Version | Supported |
| ---------------- | ------------------ |
| >= 1.0.0-rc.154 | :white_check_mark: |
| < 1.0.0-rc.154 | :x: |
| >= 1.0.0-rc.190 | :white_check_mark: |
| < 1.0.0-rc.190 | :x: |
## Reporting a Vulnerability

View File

@ -1,7 +1,7 @@
{
"name": "create-vuepress-theme-plume",
"type": "module",
"version": "1.0.0-rc.160",
"version": "1.0.0-rc.196",
"description": "The cli for create vuepress-theme-plume's project",
"author": "pengzhanbo <q942450674@outlook.com> (https://github.com/pengzhanbo/)",
"license": "MIT",
@ -27,7 +27,7 @@
"templates"
],
"scripts": {
"build": "tsdown"
"build": "tsdown --config-loader unrun"
},
"dependencies": {
"@clack/prompts": "catalog:prod",
@ -36,12 +36,17 @@
"handlebars": "catalog:prod",
"nano-spawn": "catalog:prod",
"os-locale": "catalog:prod",
"picocolors": "catalog:prod"
"picocolors": "catalog:prod",
"sort-package-json": "catalog:prod"
},
"plume-deps": {
"vuepress": "2.0.0-rc.24",
"vue": "^3.5.18",
"vuepress": "2.0.0-rc.28",
"vue": "^3.5.32",
"http-server": "^14.1.1",
"typescript": "^5.9.2"
"typescript": "^5.9.3"
},
"publishConfig": {
"access": "public",
"provenance": true
}
}

View File

@ -1,27 +1,86 @@
import type { Bundler, Langs, Options } from './types.js'
/**
* Language options for VuePress configuration
*
* VuePress
*/
export const languageOptions: Options<Langs> = [
{ label: 'English', value: 'en-US' },
{ label: '简体中文', value: 'zh-CN' },
]
/**
* Bundler options for VuePress build tool
*
* VuePress
*/
export const bundlerOptions: Options<Bundler> = [
{ label: 'Vite', value: 'vite' },
{ label: 'Webpack', value: 'webpack' },
]
/**
* Operation mode for VuePress CLI
*
* VuePress CLI
* @readonly
* @enum {number}
*/
export enum Mode {
/**
* Initialize existing directory
*
*
*/
init,
/**
* Create new project
*
*
*/
create,
}
/**
* Deployment type for VuePress site
*
* VuePress
* @readonly
* @enum {string}
*/
export enum DeployType {
/**
* GitHub Pages deployment
*
* GitHub Pages
*/
github = 'github',
/**
* Vercel deployment
*
* Vercel
*/
vercel = 'vercel',
/**
* Netlify deployment
*
* Netlify
*/
netlify = 'netlify',
/**
* Custom deployment
*
*
*/
custom = 'custom',
}
/**
* Deployment options for hosting platforms
*
*
*/
export const deployOptions: Options<DeployType> = [
{ label: 'Custom', value: DeployType.custom },
{ label: 'GitHub Pages', value: DeployType.github },

View File

@ -8,6 +8,15 @@ import { createPackageJson } from './packageJson.js'
import { createRender } from './render.js'
import { getTemplate, readFiles, readJsonFile, writeFiles } from './utils/index.js'
/**
* Generate VuePress project files
*
* VuePress
*
* @param mode - Operation mode (init or create) /
* @param data - Resolved configuration data /
* @param cwd - Current working directory /
*/
export async function generate(
mode: Mode,
data: ResolvedData,
@ -106,6 +115,14 @@ export async function generate(
})
}
/**
* Create documentation files based on configuration
*
*
*
* @param data - Resolved configuration data /
* @returns Array of file objects /
*/
async function createDocsFiles(data: ResolvedData): Promise<File[]> {
const fileList: File[] = []
if (data.multiLanguage) {
@ -131,6 +148,15 @@ async function createDocsFiles(data: ResolvedData): Promise<File[]> {
return updateFileListTarget(fileList, data.docsDir)
}
/**
* Update file list target path
*
*
*
* @param fileList - Array of files /
* @param target - Target directory path /
* @returns Updated file array /
*/
function updateFileListTarget(fileList: File[], target: string): File[] {
return fileList.map(({ filepath, content }) => ({
filepath: path.join(target, filepath),

View File

@ -1,3 +1,15 @@
/**
* VuePress Theme Plume CLI Entry Point
*
* VuePress Theme Plume CLI
*
* This module provides command-line interface for creating and initializing
* VuePress projects with vuepress-theme-plume.
*
* VuePress
*
* @module cli
*/
import cac from 'cac'
import { version } from '../package.json'
import { Mode } from './constants.js'

View File

@ -1,5 +1,10 @@
import type { Locale } from '../types.js'
/**
* English locale configuration for CLI prompts and messages.
*
* CLI
*/
export const en: Locale = {
'question.root': 'Where would you want to initialize VuePress?',
'question.site.name': 'Site Name:',

View File

@ -2,6 +2,15 @@ import type { Langs, Locale } from '../types.js'
import { en } from './en.js'
import { zh } from './zh.js'
/**
* Locale configurations for different languages.
*
*
*
* Maps language codes to their respective locale strings.
*
*
*/
export const locales: Record<Langs, Locale> = {
'zh-CN': zh,
'en-US': en,

View File

@ -1,5 +1,10 @@
import type { Locale } from '../types.js'
/**
* Chinese (Simplified) locale configuration for CLI prompts and messages.
*
* CLI
*/
export const zh: Locale = {
'question.root': '您想在哪里初始化 VuePress',
'question.site.name': '站点名称:',

View File

@ -1,9 +1,41 @@
import type { File, ResolvedData } from './types.js'
import { kebabCase } from '@pengzhanbo/utils'
import { attemptAsync, kebabCase } from '@pengzhanbo/utils'
import spawn from 'nano-spawn'
import _sortPackageJson from 'sort-package-json'
import { Mode } from './constants.js'
import { readJsonFile, resolve } from './utils/index.js'
/**
* Sort package.json fields in a consistent order.
*
* package.json
*
* @param json - Package.json object to sort / package.json
* @returns Sorted package.json object / package.json
*/
function sortPackageJson(json: Record<any, any>) {
return _sortPackageJson(json, {
sortOrder: ['name', 'type', 'version', 'private', 'description', 'packageManager', 'author', 'license', 'scripts', 'devDependencies', 'dependencies', 'pnpm'],
})
}
/**
* Create package.json file for VuePress project
*
* VuePress package.json
*
* @param mode - Operation mode (init or create) /
* @param pkg - Existing package.json data / package.json
* @param data - Resolved configuration data /
* @param data.packageManager - Package manager to use / 使
* @param data.siteName - Site name /
* @param data.siteDescription - Site description /
* @param data.docsDir - Documentation directory path /
* @param data.bundler - Bundler to use / 使
* @param data.injectNpmScripts - Whether to inject npm scripts / npm
*
* @returns File object with package.json content / package.json
*/
export async function createPackageJson(
mode: Mode,
pkg: Record<string, any>,
@ -14,7 +46,6 @@ export async function createPackageJson(
siteDescription,
bundler,
injectNpmScripts,
useTs,
}: ResolvedData,
): Promise<File> {
if (mode === Mode.create) {
@ -24,10 +55,11 @@ export async function createPackageJson(
pkg.description = siteDescription
if (packageManager !== 'npm') {
let version = await getPackageManagerVersion(packageManager)
let [, version] = await attemptAsync(getPackageManagerVersion, packageManager)
if (version) {
if (packageManager === 'yarn' && version.startsWith('1'))
version = '4.6.0'
if (packageManager === 'yarn' && version.startsWith('1')) {
version = '4.10.3'
}
pkg.packageManager = `${packageManager}@${version}`
// pnpm@10 should add `onlyBuiltDependencies`
@ -39,12 +71,12 @@ export async function createPackageJson(
}
}
const userInfo = await getUserInfo()
const [, userInfo] = await attemptAsync(getUserInfo)
if (userInfo) {
pkg.author = userInfo.username + (userInfo.email ? ` <${userInfo.email}>` : '')
}
pkg.license = 'MIT'
pkg.engines = { node: '^20.6.0 || >=22.0.0' }
pkg.engines = { node: '^20.19.0 || >=22.0.0' }
}
if (injectNpmScripts) {
@ -76,36 +108,41 @@ export async function createPackageJson(
if (!hasDep('vue'))
deps.push('vue')
if (useTs)
deps.push('typescript')
deps.push('typescript')
for (const dep of deps)
pkg.devDependencies[dep] = meta[dep]
return {
filepath: 'package.json',
content: JSON.stringify(pkg, null, 2),
content: JSON.stringify(sortPackageJson(pkg), null, 2),
}
}
/**
* Get user information from git global configuration.
*
* git
*
* @returns User information object with username and email /
* @throws Error if git command fails / git
*/
async function getUserInfo() {
try {
const { output: username } = await spawn('git', ['config', '--global', 'user.name'])
const { output: email } = await spawn('git', ['config', '--global', 'user.email'])
console.log('userInfo', username, email)
return { username, email }
}
catch {
return null
}
const { output: username } = await spawn('git', ['config', '--global', 'user.name'])
const { output: email } = await spawn('git', ['config', '--global', 'user.email'])
return { username, email }
}
/**
* Get the version of a package manager.
*
*
*
* @param pkg - Package manager name (npm, yarn, pnpm) /
* @returns Version string of the package manager /
* @throws Error if package manager command fails /
*/
async function getPackageManagerVersion(pkg: string) {
try {
const { output } = await spawn(pkg, ['--version'])
return output
}
catch {
return null
}
const { output } = await spawn(pkg, ['--version'])
return output
}

View File

@ -2,7 +2,7 @@ import type { Bundler, Langs, PromptResult } from './types.js'
import { createRequire } from 'node:module'
import process from 'node:process'
import { cancel, confirm, group, select, text } from '@clack/prompts'
import { osLocale } from 'os-locale'
import osLocale from 'os-locale'
import { bundlerOptions, deployOptions, DeployType, languageOptions, Mode } from './constants.js'
import { setLang, t } from './translate.js'
@ -10,6 +10,15 @@ const require = createRequire(process.cwd())
const REG_DIR_CHAR = /[<>:"\\|?*[\]]/
/**
* Prompt user for project configuration
*
*
*
* @param mode - Operation mode (init or create) /
* @param root - Optional root directory path /
* @returns Resolved prompt result /
*/
export async function prompt(mode: Mode, root?: string): Promise<PromptResult> {
let hasTs = false
if (mode === Mode.init) {
@ -21,7 +30,7 @@ export async function prompt(mode: Mode, root?: string): Promise<PromptResult> {
const result: PromptResult = await group({
displayLang: async () => {
const locale = await osLocale()
const locale = osLocale()
if (locale === 'zh-CN' || locale === 'zh-Hans') {
setLang('zh-CN')

View File

@ -2,16 +2,33 @@ import type { ResolvedData } from './types.js'
import { kebabCase } from '@pengzhanbo/utils'
import handlebars from 'handlebars'
/**
* Extended resolved data with additional rendering information
*
*
*/
export interface RenderData extends ResolvedData {
/** Project name in kebab-case / 项目名称kebab-case 格式) */
name: string
/** Site name / 网站名称 */
siteName: string
/** Locale configuration array / 语言配置数组 */
locales: { path: string, lang: string, isEn: boolean, prefix: string }[]
/** Whether default language is English / 默认语言是否为英语 */
isEN: boolean
}
handlebars.registerHelper('removeLeadingSlash', (path: string) => path.replace(/^\//, ''))
handlebars.registerHelper('equal', (a: string, b: string) => a === b)
/**
* Create render function with Handlebars template engine
*
* 使 Handlebars
*
* @param result - Resolved configuration data /
* @returns Render function that processes Handlebars templates / Handlebars
*/
export function createRender(result: ResolvedData) {
const data: RenderData = {
...result,

View File

@ -11,6 +11,14 @@ import { prompt } from './prompt.js'
import { t } from './translate.js'
import { getPackageManager } from './utils/index.js'
/**
* Run the CLI workflow for VuePress project initialization or creation
*
* VuePress CLI
*
* @param mode - Operation mode (init or create) /
* @param root - Root directory path /
*/
export async function run(mode: Mode, root?: string): Promise<void> {
intro(colors.cyan('Welcome to VuePress and vuepress-theme-plume !'))
@ -70,6 +78,15 @@ export async function run(mode: Mode, root?: string): Promise<void> {
}
}
/**
* Resolve prompt result into final configuration data.
*
*
*
* @param result - Prompt result from user input /
* @param mode - Operation mode (init or create) /
* @returns Resolved configuration data /
*/
function resolveData(result: PromptResult, mode: Mode): ResolvedData {
return {
...result,

View File

@ -6,6 +6,14 @@ interface Translate {
t: (key: keyof Locale) => string
}
/**
* Create a translate instance with specified language
*
*
*
* @param lang - Language code /
* @returns Translate interface /
*/
function createTranslate(lang?: Langs): Translate {
let current: Langs = lang || 'en-US'
@ -19,5 +27,21 @@ function createTranslate(lang?: Langs): Translate {
const translate = createTranslate()
/**
* Get translated string by key
*
*
*
* @param key - Locale key /
* @returns Translated string /
*/
export const t: Translate['t'] = translate.t
/**
* Set current language
*
*
*
* @param lang - Language code to set /
*/
export const setLang: Translate['setLang'] = translate.setLang

View File

@ -1,57 +1,276 @@
import type { DeployType } from './constants.js'
/**
* Supported language codes for VuePress site
*
* VuePress
*/
export type Langs = 'zh-CN' | 'en-US'
/**
* Locale configuration for CLI prompts and messages
*
* CLI
*/
export interface Locale {
/**
* Question: Project root directory name
*
*
*/
'question.root': string
/**
* Question: Site name
*
*
*/
'question.site.name': string
/**
* Question: Site description
*
*
*/
'question.site.description': string
/**
* Question: Enable multi-language support
*
*
*/
'question.multiLanguage': string
/**
* Question: Default language
*
*
*/
'question.defaultLanguage': string
/**
* Question: Build tool bundler
*
*
*/
'question.bundler': string
/**
* Question: Use TypeScript
*
* 使 TypeScript
*/
'question.useTs': string
/**
* Question: Inject npm scripts
*
* npm
*/
'question.injectNpmScripts': string
/**
* Question: Initialize git repository
*
* git
*/
'question.git': string
/**
* Question: Deployment type
*
*
*/
'question.deploy': string
/**
* Question: Install dependencies
*
*
*/
'question.installDeps': string
/**
* Spinner: Start message
*
*
*/
'spinner.start': string
/**
* Spinner: Stop message
*
*
*/
'spinner.stop': string
/**
* Spinner: Git init message
*
* Git
*/
'spinner.git': string
/**
* Spinner: Install message
*
*
*/
'spinner.install': string
/**
* Spinner: Command hint message
*
*
*/
'spinner.command': string
/**
* Hint: Cancel operation
*
*
*/
'hint.cancel': string
/**
* Hint: Root directory
*
*
*/
'hint.root': string
/**
* Hint: Illegal root directory name
*
*
*/
'hint.root.illegal': string
}
/**
* Package manager types
*
*
*/
export type PackageManager = 'npm' | 'yarn' | 'pnpm'
/**
* Build tool bundler types
*
*
*/
export type Bundler = 'vite' | 'webpack'
/**
* Generic options type for CLI prompts
*
* CLI
*
* @template Value - The value type for options
* @template Label - The label type for options
*/
export type Options<Value = string, Label = string> = { label: Label, value: Value }[]
/**
* File structure for generated project
*
*
*/
export interface File {
/**
* File path relative to project root
*
*
*/
filepath: string
/**
* File content
*
*
*/
content: string
}
/**
* Result from CLI prompts
*
* CLI
*/
export interface PromptResult {
displayLang: string // cli display language
/**
* CLI display language
*
* CLI
*/
displayLang: string
/**
* Project root directory name
*
*
*/
root: string
/**
* Site name
*
*
*/
siteName: string
/**
* Site description
*
*
*/
siteDescription: string
/**
* Build tool bundler
*
*
*/
bundler: Bundler
/**
* Enable multi-language support
*
*
*/
multiLanguage: boolean
/**
* Default language
*
*
*/
defaultLanguage: Langs
/**
* Use TypeScript
*
* 使 TypeScript
*/
useTs: boolean
/**
* Inject npm scripts
*
* npm
*/
injectNpmScripts: boolean
/**
* Deployment type
*
*
*/
deploy: DeployType
/**
* Initialize git repository
*
* git
*/
git: boolean
/**
* Install dependencies
*
*
*/
install: boolean
}
/**
* Resolved data after processing prompts
*
*
*/
export interface ResolvedData extends PromptResult {
/**
* Selected package manager
*
*
*/
packageManager: PackageManager
/**
* Documentation directory name
*
*
*/
docsDir: string
}

View File

@ -2,6 +2,14 @@ import type { File } from '../types.js'
import fs from 'node:fs/promises'
import path from 'node:path'
/**
* Read all files from a directory recursively
*
*
*
* @param root - Root directory path to read from /
* @returns Array of file objects /
*/
export async function readFiles(root: string): Promise<File[]> {
const filepaths = await fs.readdir(root, { recursive: true })
const files: File[] = []
@ -18,6 +26,15 @@ export async function readFiles(root: string): Promise<File[]> {
return files
}
/**
* Write files to target directory
*
*
*
* @param files - Array of file objects to write /
* @param target - Target directory path /
* @param rewrite - Optional function to rewrite file paths /
*/
export async function writeFiles(
files: File[],
target: string,
@ -32,6 +49,14 @@ export async function writeFiles(
}
}
/**
* Read and parse JSON file
*
* JSON
*
* @param filepath - Path to JSON file / JSON
* @returns Parsed JSON object or null if parsing fails / JSON null
*/
export async function readJsonFile<T extends Record<string, any> = Record<string, any>>(filepath: string): Promise<T | null> {
try {
const content = await fs.readFile(filepath, 'utf-8')

View File

@ -1,6 +1,19 @@
import type { PackageManager } from '../types.js'
import process from 'node:process'
/**
* Detect the current package manager from environment variables.
*
* 使
*
* @returns The detected package manager name /
* @example
* // When using pnpm
* const pm = getPackageManager() // returns 'pnpm'
*
* // When using npm
* const pm = getPackageManager() // returns 'npm'
*/
export function getPackageManager(): PackageManager {
const name = process.env?.npm_config_user_agent || 'npm'
return name.split('/')[0] as PackageManager

View File

@ -3,8 +3,24 @@ import { fileURLToPath } from 'node:url'
export const __dirname: string = path.dirname(fileURLToPath(import.meta.url))
/**
* Resolve path relative to the project root
*
*
*
* @param args - Path segments to resolve /
* @returns Resolved absolute path /
*/
export const resolve = (...args: string[]): string => path.resolve(__dirname, '../', ...args)
/**
* Get template directory path
*
*
*
* @param dir - Subdirectory name within templates / templates
* @returns Resolved template directory path /
*/
export const getTemplate = (dir: string): string => resolve('templates', dir)
export * from './fs.js'

View File

@ -0,0 +1,124 @@
/**
* @see https://theme-plume.vuejs.press/guide/collection/ 查看文档了解配置详情。
*
* Collections 配置文件,它在 `.vuepress/plume.config.{{#if useTs}}ts{{else}}js{{/if}}` 中被导入。
*
* 请注意,你应该先在这里配置好 Collections然后再启动 vuepress主题会在启动 vuepress 时,
* 读取这里配置的 Collections然后在与 Collection 相关的 Markdown 文件中,自动生成 permalink。
*
* collection 的 type 为 `post` 时,表示为 文档列表类型(即没有侧边导航栏,有文档列表页)
* 可用于实现如 博客、专栏 等以文章列表聚合形式的文档集合 (内容相对碎片化的)
*
* collection 的 type 为 `doc` 时,表示为文档类型(即有侧边导航栏)
* 可用于实现如 笔记、知识库、文档等以侧边导航栏形式的文档集合 (内容强关联、成体系的)
* 如果发现 侧边栏没有显示,那么请检查你的配置是否正确,以及 Markdown 文件中的 permalink
* 是否是以对应的 Collection 配置的 link 的前缀开头。 是否展示侧边栏是根据 页面链接 的前缀 与 `collection.link`
* 的前缀是否匹配来决定。
*/
/**
* 在受支持的 IDE 中会智能提示配置项。
*
* - `defineCollections` 是用于定义 collection 集合的帮助函数
* - `defineCollection` 是用于定义单个 collection 配置的帮助函数
*
* 通过 `defineCollection` 定义的 collection 配置,应该填入 `defineCollections` 中
*/
import { defineCollection, defineCollections } from 'vuepress-theme-plume'
{{#if multiLanguage}}
{{#each locales}}
/* =================== locale: {{ lang }} ======================= */
const {{ prefix }}Blog = defineCollection({
// post 类型,这里用于实现 博客功能
type: 'post',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'blog',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Blog',
// 文章列表页的链接,如果 `linkPrefix` 未定义,它也将作为 相关的文章的 permalink 的前缀
link: '/blog/',
// linkPrefix: '/article/', // 相关文章的链接前缀
// postList: true, // 是否启用文章列表页
// tags: true, // 是否启用标签页
// archives: true, // 是否启用归档页
// categories: true, // 是否启用分类页
// postCover: 'right', // 文章封面位置
// pagination: 15, // 每页显示文章数量
})
const {{ prefix }}DemoDoc = defineCollection({
// doc 类型,该类型带有侧边栏
type: 'doc',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `linkPrefix` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `{{ path }}` + `linkPrefix` 开头
linkPrefix: '/demo',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 collections
* ({{ prefix }}Blog 为博客示例,如果不需要博客功能,请删除)
* ({{ prefix }}DemoDoc 为参考示例,如果不需要它,请删除)
*/
export const {{ prefix }}Collections = defineCollections([
{{ prefix }}Blog,
{{ prefix }}DemoDoc,
])
{{/each}}
{{else}}
const blog = defineCollection({
// post 类型,这里用于实现 博客功能
type: 'post',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'blog',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Blog',
// 文章列表页的链接,如果 `linkPrefix` 未定义,它也将作为 相关的文章的 permalink 的前缀
link: '/blog/',
// linkPrefix: '/article/', // 相关文章的链接前缀
// postList: true, // 是否启用文章列表页
// tags: true, // 是否启用标签页
// archives: true, // 是否启用归档页
// categories: true, // 是否启用分类页
// postCover: 'right', // 文章封面位置
// pagination: 15, // 每页显示文章数量
})
const demoDoc = defineCollection({
// doc 类型,该类型带有侧边栏
type: 'doc',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `linkPrefix` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `linkPrefix` 开头
linkPrefix: '/demo',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 collections
* (blog 为博客示例,如果不需要博客功能,请删除)
* (demoDoc 为参考示例,如果不需要它,请删除)
*/
export default defineCollections([
blog,
demoDoc,
])
{{/if}}

View File

@ -54,32 +54,15 @@ export default defineUserConfig({
// contributors: true,
// changelog: false,
/**
* 博客
* @see https://theme-plume.vuejs.press/config/basic/#blog
*/
// blog: false, // 禁用博客
// blog: {
// postList: true, // 是否启用文章列表页
// tags: true, // 是否启用标签页
// archives: true, // 是否启用归档页
// categories: true, // 是否启用分类页
// postCover: 'right', // 文章封面位置
// pagination: 15, // 每页显示文章数量
// },
/* 博客文章页面链接前缀 */
article: '/article/',
/**
* 编译缓存,加快编译速度
* @see https://theme-plume.vuejs.press/config/basic/#cache
* @see https://theme-plume.vuejs.press/config/theme/#cache
*/
cache: 'filesystem',
/**
* 为 markdown 文件自动添加 frontmatter 配置
* @see https://theme-plume.vuejs.press/config/basic/#autofrontmatter
* @see https://theme-plume.vuejs.press/config/theme/#autofrontmatter
*/
// autoFrontmatter: {
// permalink: true, // 是否生成永久链接
@ -99,7 +82,7 @@ export default defineUserConfig({
// provider: 'algolia',
// appId: '',
// apiKey: '',
// indexName: '',
// indices: [''],
// },
/**
@ -116,9 +99,9 @@ export default defineUserConfig({
// readingTime: true,
/**
* markdown
* @see https://theme-plume.vuejs.press/config/markdown/
*/
* markdown
* @see https://theme-plume.vuejs.press/config/markdown/
*/
// markdown: {
// abbr: true, // 启用 abbr 语法 *[label]: content
// annotation: true, // 启用 annotation 语法 [+label]: content
@ -137,6 +120,7 @@ export default defineUserConfig({
// jsfiddle: true, // 启用嵌入 jsfiddle 语法 @[jsfiddle](user/id)
// npmTo: true, // 启用 npm-to 容器 ::: npm-to
// demo: true, // 启用 demo 容器 ::: demo
// collapse: true, // 启用折叠容器 ::: collapse
// repl: { // 启用 代码演示容器
// go: true, // ::: go-repl
// rust: true, // ::: rust-repl
@ -193,5 +177,18 @@ export default defineUserConfig({
* @see https://theme-plume.vuejs.press/guide/features/encryption/
*/
// encrypt: {},
/**
* 启用 llmstxt 插件,用于为大语言模型提供更友好的内容
* @see https://theme-plume.vuejs.press/guide/features/llmstxt/
*/
// llmstxt: {
{{#if multiLanguage}}
// locale: '/', // 默认仅为主语言生成 llms 友好内容
// locale: 'all', // 为所有语言生成 llms 友好内容
{{else}}
// locale: '/', // 默认仅为主语言生成 llms 友好内容
{{/if}}
// }
}),
})

View File

@ -15,7 +15,7 @@ export const {{prefix}}Navbar = defineNavbarConfig([
{ text: '{{#if isEn}}Archives{{else}}归档{{/if}}', link: '{{ path }}blog/archives/' },
{
text: '{{#if isEn}}Notes{{else}}笔记{{/if}}',
items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '{{ path }}notes/demo/README.md' }]
items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '{{ path }}demo/README.md' }]
},
])
@ -28,7 +28,7 @@ export default defineNavbarConfig([
{ text: '{{#if isEn}}Archives{{else}}归档{{/if}}', link: '/blog/archives/' },
{
text: '{{#if isEn}}Notes{{else}}笔记{{/if}}',
items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '/notes/demo/README.md' }]
items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '/demo/README.md' }]
},
])
{{/if}}

View File

@ -1,75 +0,0 @@
/**
* @see https://theme-plume.vuejs.press/guide/document/ 查看文档了解配置详情。
*
* Notes 配置文件,它在 `.vuepress/plume.config.{{#if useTs}}ts{{else}}js{{/if}}` 中被导入。
*
* 请注意,你应该先在这里配置好 Notes然后再启动 vuepress主题会在启动 vuepress 时,
* 读取这里配置的 Notes然后在与 Note 相关的 Markdown 文件中,自动生成 permalink。
*
* 如果你发现 侧边栏没有显示,那么请检查你的配置是否正确,以及 Markdown 文件中的 permalink
* 是否是以对应的 note 配置的 link 的前缀开头。 是否展示侧边栏是根据 页面链接 的前缀 与 `note.link`
* 的前缀是否匹配来决定。
*/
/**
* 在受支持的 IDE 中会智能提示配置项。
*
* - `defineNoteConfig` 是用于定义单个 note 配置的帮助函数
* - `defineNotesConfig` 是用于定义 notes 集合的帮助函数
*
* 通过 `defineNoteConfig` 定义的 note 配置,应该填入 `defineNotesConfig` 的 notes 数组中
*/
import { defineNoteConfig, defineNotesConfig } from 'vuepress-theme-plume'
{{#if multiLanguage}}
{{#each locales}}
/* =================== locale: {{ lang }} ======================= */
const {{ prefix }}DemoNote = defineNoteConfig({
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `link` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `link` 开头
link: '/demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 note
* 每一个 note 都应该填入到 `notes.notes` 数组中
* {{ prefix }}DemoNote 为参考示例,如果不需要它,请删除)
*/
export const {{ prefix }}Notes = defineNotesConfig({
dir: '{{ removeLeadingSlash path }}notes',
link: '{{ path }}',
notes: [{{ prefix }}DemoNote],
})
{{/each}}
{{else}}
const demoNote = defineNoteConfig({
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `link` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `link` 开头
link: '/demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 note
* 每一个 note 都应该填入到 `notes.notes` 数组中
* DemoNote 为参考示例,如果不需要它,请删除)
*/
export default defineNotesConfig({
dir: 'notes',
link: '/',
notes: [demoNote],
})
{{/if}}

View File

@ -12,15 +12,15 @@
import { defineThemeConfig } from 'vuepress-theme-plume'
{{#if multiLanguage}}
import { enCollections, zhCollections } from './collections'
import { enNavbar, zhNavbar } from './navbar'
import { enNotes, zhNotes } from './notes'
{{else}}
import navbar from './navbar'
import notes from './notes'
import collections from './collections'
{{/if}}
/**
* @see https://theme-plume.vuejs.press/config/basic/
* @see https://theme-plume.vuejs.press/config/theme/
*/
export default defineThemeConfig({
logo: 'https://theme-plume.vuejs.press/plume.png',
@ -52,7 +52,7 @@ export default defineThemeConfig({
{{#unless multiLanguage}}
/**
* @see https://theme-plume.vuejs.press/config/basic/#profile
* @see https://theme-plume.vuejs.press/config/theme/#profile
*/
profile: {
avatar: 'https://theme-plume.vuejs.press/plume.png',
@ -64,7 +64,7 @@ export default defineThemeConfig({
},
navbar,
notes,
collections,
/**
* 公告板
@ -78,7 +78,7 @@ export default defineThemeConfig({
// },
{{/unless}}
/* 过渡动画 @see https://theme-plume.vuejs.press/config/basic/#transition */
/* 过渡动画 @see https://theme-plume.vuejs.press/config/theme/#transition */
// transition: {
// page: true, // 启用 页面间跳转过渡动画
// postList: true, // 启用 博客文章列表过渡动画
@ -90,7 +90,7 @@ export default defineThemeConfig({
{{#each locales}}
'{{ path }}': {
/**
* @see https://theme-plume.vuejs.press/config/basic/#profile
* @see https://theme-plume.vuejs.press/config/theme/#profile
*/
profile: {
avatar: 'https://theme-plume.vuejs.press/plume.png',
@ -102,7 +102,7 @@ export default defineThemeConfig({
},
navbar: {{ prefix }}Navbar,
notes: {{ prefix }}Notes,
collections: {{ prefix }}Collections,
/**
* 公告板

View File

@ -56,11 +56,15 @@ jobs:
# Run the build script
{{#unless (equal packageManager "yarn")}}
- name: Build VuePress site
env:
NODE_OPTIONS: --max_old_space_size=8192
run: {{packageManager}} run docs:build
{{/unless}}
{{#if (equal packageManager "yarn")}}
- name: Build VuePress site
uses: borales/actions-yarn@v4
env:
NODE_OPTIONS: --max_old_space_size=8192
with:
cmd: docs:build
{{/if}}

View File

@ -5,7 +5,8 @@ config:
-
type: hero
full: true
background: tint-plate
forceDark: true
effect: lightning
hero:
name: Theme Plume
tagline: VuePress Next Theme

View File

@ -81,7 +81,7 @@ content right
**demo wrapper**
::: demo-wrapper title="Demo" no-padding height="200px"
::: window title="Demo" height="200px"
<style scoped>
.open-door {
display: flex;

View File

@ -5,7 +5,8 @@ config:
-
type: hero
full: true
background: tint-plate
forceDark: true
effect: lightning
hero:
name: Theme Plume
tagline: VuePress Next Theme

View File

@ -95,9 +95,9 @@ H~2~O
- vscode - <Icon name="skill-icons:vscode-dark" size="2em" />
- twitter - <Icon name="skill-icons:twitter" size="2em" />
**demo wrapper**
**示例容器**
::: demo-wrapper title="示例" no-padding height="200px"
::: window title="示例" height="200px"
<style scoped>
.open-door {
display: flex;
@ -137,68 +137,6 @@ const obj = {
}
```
**Code Blocks TwoSlash**
```ts twoslash
// @errors: 2339
const welcome = 'Tudo bem gente?'
const words = welcome.contains(' ')
```
```ts twoslash
import express from 'express'
const app = express()
app.get('/', (req, res) => {
res.send
})
app.listen(3000)
```
```ts twoslash
import { createHighlighter } from 'shiki'
const highlighter = await createHighlighter({ themes: ['nord'], langs: ['javascript'] })
// @log: Custom log message
const a = 1
// @error: Custom error message
const b = 1
// @warn: Custom warning message
const c = 1
// @annotate: Custom annotation message
```
```ts twoslash
// @errors: 2540
interface Todo {
title: string
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users'.toUpperCase(),
// ^?
}
todo.title = 'Hello'
Number.parseInt('123', 10)
// ^|
//
//
```
```vue twoslash
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
</template>
```
**代码分组:**
::: code-tabs

View File

@ -6,6 +6,8 @@
*.jpeg binary
*.ico binary
*.gif binary
*.webp binary
*.tff binary
*.woff binary
*.woff2 binary
*.pdf binary

View File

@ -1,4 +1,3 @@
import type { Options } from 'tsdown'
import { defineConfig } from 'tsdown'
export default defineConfig({
@ -7,4 +6,5 @@ export default defineConfig({
dts: true,
format: 'esm',
sourcemap: false,
}) as Options
fixedExtension: false,
})

View File

@ -1,7 +1,9 @@
import type { ClientConfig } from 'vuepress/client'
import { defineMermaidConfig } from '@vuepress/plugin-markdown-chart/client'
import { h } from 'vue'
import { defineAsyncComponent, h } from 'vue'
import { Layout } from 'vuepress-theme-plume/client'
import VPPostItem from 'vuepress-theme-plume/components/Posts/VPPostItem.vue'
import PageContextMenu from 'vuepress-theme-plume/features/PageContextMenu.vue'
import { defineClientConfig } from 'vuepress/client'
import AsideNav from '~/components/AsideNav.vue'
import { setupThemeColors } from '~/composables/theme-colors.js'
@ -14,12 +16,17 @@ defineMermaidConfig({
})
export default defineClientConfig({
enhance({ app }) {
app.component('VPPostItem', VPPostItem)
app.component('TintPlate', defineAsyncComponent(() => import('vuepress-theme-plume/components/background/TintPlate.vue')))
},
setup() {
setupThemeColors()
},
layouts: {
Layout: h(Layout, null, {
'aside-outline-after': () => h(AsideNav),
'doc-title-after': () => h(PageContextMenu),
}),
},
}) as ClientConfig

View File

@ -0,0 +1,13 @@
import { defineCollections, type ThemeCollections } from 'vuepress-theme-plume'
import { themeConfig } from './theme-config.js'
import { themeGuide } from './theme-guide.js'
import { tools } from './tools.js'
export const enCollections: ThemeCollections = defineCollections([
// 博客
{ type: 'post', dir: '/blog/', link: '/blog/', title: 'Blog' },
// 文档
themeGuide,
themeConfig,
tools,
])

View File

@ -0,0 +1,53 @@
import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineCollection } from 'vuepress-theme-plume'
export const themeConfig: ThemeCollectionItem = defineCollection({
type: 'doc',
title: 'Config',
dir: 'config',
linkPrefix: '/config/',
sidebar: [
{
text: 'Configuration',
collapsed: false,
items: [
'intro',
'theme',
'locales',
'navbar',
'sidebar',
'collections',
'markdown',
],
},
{
text: 'Page Configuration',
prefix: 'frontmatter',
collapsed: false,
items: [
'basic',
'home',
'post',
'friend',
],
},
{
text: 'Built-in Plugins',
prefix: 'plugins',
collapsed: false,
items: [
'',
'shiki',
'search',
'reading-time',
'llms',
'markdown-enhance',
'markdown-power',
'markdown-image',
'markdown-math',
'markdown-include',
'watermark',
],
},
],
})

View File

@ -0,0 +1,202 @@
import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineCollection } from 'vuepress-theme-plume'
export const themeGuide: ThemeCollectionItem = defineCollection({
type: 'doc',
dir: 'guide',
title: 'Guide',
linkPrefix: '/guide/',
sidebar: [
{
text: 'Quick Start',
collapsed: false,
icon: 'carbon:idea',
prefix: 'quick-start',
items: [
'intro',
'usage',
'project-structure',
{
text: 'Collection',
link: 'collection',
items: ['collection-post', 'collection-doc'],
},
'sidebar',
'write',
'auto-frontmatter',
'locales',
'deployment',
'optimize-build',
],
},
{
text: 'Write',
icon: 'fluent-mdl2:edit-create',
collapsed: false,
items: [
{
text: 'markdown',
icon: 'material-symbols:markdown-outline',
prefix: 'markdown',
collapsed: true,
items: [
'basic',
'extensions',
'attrs',
'emoji',
'math',
'table',
'icons',
'mark',
'plot',
'abbr',
'annotation',
'container',
'github-alerts',
'card',
'steps',
'file-tree',
'code-tree',
'field',
'tabs',
'qrcode',
'timeline',
'demo-wrapper',
'flex',
'collapse',
'npm-to',
'caniuse',
'chat',
'include',
'env',
'obsidian',
],
},
{
text: 'code block',
prefix: 'code',
icon: 'ph:code-bold',
collapsed: true,
items: [
'intro',
'features',
'copy-code',
'code-tabs',
'import',
'twoslash',
],
},
{
text: 'code repl',
prefix: 'repl',
icon: 'carbon:demo',
collapsed: true,
items: [
'frontend',
'rust',
'golang',
'kotlin',
'python',
'codepen',
'jsFiddle',
'codeSandbox',
'replit',
],
},
{
text: 'charts',
icon: 'mdi:chart-line',
prefix: 'chart',
collapsed: true,
items: [
'chart',
'echarts',
'mermaid',
'flowchart',
'markmap',
'plantuml',
],
},
{
text: 'resource embedded',
icon: 'dashicons:embed-video',
prefix: 'embed',
collapsed: true,
items: [
'pdf',
'bilibili',
'acfun',
'youtube',
'artplayer',
'audioReader',
],
},
],
},
{
text: 'Features',
icon: 'lucide:box',
collapsed: false,
prefix: 'features',
items: [
'icon',
'search',
'image-preview',
'comments',
'bulletin',
'encryption',
'contributors',
'changelog',
'copyright',
'watermark',
'friend-links',
'replace-assets',
'seo',
'sitemap',
'llmstxt',
],
},
{
text: 'Component',
prefix: 'components',
icon: 'uiw:component',
collapsed: false,
items: [
'badge',
'icon',
'plot',
'card',
'link-card',
'image-card',
'card-grid',
'card-masonry',
'home-box',
'repo-card',
'npm-badge',
'swiper',
],
},
{
text: 'Customization',
icon: 'material-symbols:dashboard-customize-outline-rounded',
collapsed: false,
prefix: 'custom',
items: [
{ text: 'Custom Homepage', link: 'home', items: ['home-hero-effect'] },
'style',
'slots',
'component-overrides',
],
},
{
text: 'API',
icon: 'mdi:api',
prefix: 'api',
collapsed: false,
items: [
'client',
'node',
],
},
],
})

View File

@ -0,0 +1,20 @@
import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineCollection } from 'vuepress-theme-plume'
export const tools: ThemeCollectionItem = defineCollection({
type: 'doc',
dir: 'tools',
title: 'Theme Tools',
linkPrefix: '/tools/',
sidebar: [
{
text: 'Tools',
icon: 'tabler:tools',
items: [
'custom-theme',
'home-hero-tint-plate',
'caniuse',
],
},
],
})

View File

@ -0,0 +1,13 @@
import { defineCollections, type ThemeCollections } from 'vuepress-theme-plume'
import { themeConfig } from './theme-config.js'
import { themeGuide } from './theme-guide.js'
import { tools } from './tools.js'
export const zhCollections: ThemeCollections = defineCollections([
// 博客
{ type: 'post', dir: '/blog/', link: '/blog/', title: '博客' },
// 文档
themeGuide,
themeConfig,
tools,
])

View File

@ -1,9 +1,11 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineCollection } from 'vuepress-theme-plume'
export const themeConfig: ThemeNote = defineNoteConfig({
dir: 'theme/config',
link: '/config/',
export const themeConfig: ThemeCollectionItem = defineCollection({
type: 'doc',
title: '配置',
dir: 'config',
linkPrefix: '/config/',
sidebar: [
{
text: '配置',
@ -13,8 +15,8 @@ export const themeConfig: ThemeNote = defineNoteConfig({
'theme',
'locales',
'navbar',
'notes',
'sidebar',
'collections',
'markdown',
],
},
@ -38,6 +40,7 @@ export const themeConfig: ThemeNote = defineNoteConfig({
'shiki',
'search',
'reading-time',
'llms',
'markdown-enhance',
'markdown-power',
'markdown-image',

View File

@ -1,9 +1,11 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineCollection } from 'vuepress-theme-plume'
export const themeGuide: ThemeNote = defineNoteConfig({
dir: 'theme/guide',
link: '/guide/',
export const themeGuide: ThemeCollectionItem = defineCollection({
type: 'doc',
dir: 'guide',
title: '指南',
linkPrefix: '/guide/',
sidebar: [
{
text: '从这里开始',
@ -14,9 +16,14 @@ export const themeGuide: ThemeNote = defineNoteConfig({
'intro',
'usage',
'project-structure',
{
text: '集合',
link: 'collection',
items: ['collection-post', 'collection-doc'],
},
'sidebar',
'write',
'blog',
'document',
'auto-frontmatter',
'locales',
'deployment',
'optimize-build',
@ -35,18 +42,24 @@ export const themeGuide: ThemeNote = defineNoteConfig({
items: [
'basic',
'extensions',
'attrs',
'emoji',
'math',
'table',
'icons',
'mark',
'plot',
'abbr',
'annotation',
'container',
'github-alerts',
'card',
'steps',
'file-tree',
'code-tree',
'field',
'tabs',
'qrcode',
'timeline',
'demo-wrapper',
'flex',
@ -55,6 +68,8 @@ export const themeGuide: ThemeNote = defineNoteConfig({
'caniuse',
'chat',
'include',
'env',
'obsidian',
],
},
{
@ -138,6 +153,7 @@ export const themeGuide: ThemeNote = defineNoteConfig({
'replace-assets',
'seo',
'sitemap',
'llmstxt',
],
},
{
@ -166,7 +182,7 @@ export const themeGuide: ThemeNote = defineNoteConfig({
collapsed: false,
prefix: 'custom',
items: [
'home',
{ text: '自定义首页', link: 'home', items: ['home-hero-effect'] },
'style',
'slots',
'component-overrides',

View File

@ -0,0 +1,20 @@
import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineCollection } from 'vuepress-theme-plume'
export const tools: ThemeCollectionItem = defineCollection({
type: 'doc',
dir: 'tools',
title: '工具',
linkPrefix: '/tools/',
sidebar: [
{
text: '工具',
icon: 'tabler:tools',
items: [
'custom-theme',
'home-hero-tint-plate',
'caniuse',
],
},
],
})

View File

@ -3,9 +3,7 @@ import fs from 'node:fs'
import path from 'node:path'
import { viteBundler } from '@vuepress/bundler-vite'
import { addViteOptimizeDepsInclude, addViteSsrExternal } from '@vuepress/helper'
import { llmsPlugin } from '@vuepress/plugin-llms'
import { defineUserConfig } from 'vuepress'
import { tocGetter } from './llmstxtTOC.js'
import { theme } from './theme.js'
const pnpmWorkspace = fs.readFileSync(path.resolve(__dirname, '../../pnpm-workspace.yaml'), 'utf-8')
@ -28,7 +26,7 @@ export default defineUserConfig({
['meta', { name: 'google-site-verification', content: 'AaTP7bapCAcoO9ZGE67ilpy99GL6tYqtD30tRHjO9Ps' }],
],
pagePatterns: ['**/*.md', '!**/*.snippet.md', '!.vuepress', '!node_modules', '!docs/notes/theme/guide/代码演示/demo/*'],
pagePatterns: ['**/*.md', '!**/*.snippet.md', '!.vuepress', '!node_modules', '!docs/guide/repl/demo/*'],
extendsBundlerOptions(bundlerOptions, app) {
addViteOptimizeDepsInclude(bundlerOptions, app, '@simonwep/pickr')
@ -47,16 +45,6 @@ export default defineUserConfig({
'~/composables': path.resolve(__dirname, './themes/composables'),
},
plugins: [
llmsPlugin({
llmsTxtTemplateGetter: {
description: '一个简约易用的,功能丰富的 vuepress 文档&博客 主题',
details: '',
toc: tocGetter,
},
}),
],
bundler: viteBundler(),
shouldPrefetch: false,

View File

@ -1,108 +0,0 @@
import type { LLMPage, LLMState } from '@vuepress/plugin-llms'
import type { ThemeSidebarItem } from 'vuepress-theme-plume'
import { generateTOCLink as rawGenerateTOCLink } from '@vuepress/plugin-llms'
import { ensureEndingSlash, ensureLeadingSlash } from 'vuepress/shared'
import { zhNotes } from './notes/zh/index.js'
const noteNames = {
'/guide/': '指南',
'/config/': '配置',
'/tools/': '工具',
}
function normalizePath(prefix: string, path = ''): string {
if (path.startsWith('/'))
return path
return `${ensureEndingSlash(prefix)}${path}`
}
export function tocGetter(llmPages: LLMPage[], llmState: LLMState): string {
let tableOfContent = ''
const usagePages: LLMPage[] = []
// Blog
tableOfContent += `### 博客\n\n`
const blogList: string[] = []
llmPages.forEach((page) => {
if (page.path.startsWith('/article/') || page.path.startsWith('/blog/')) {
usagePages.push(page)
blogList.push(rawGenerateTOCLink(page, llmState))
}
})
tableOfContent += `${blogList.filter(Boolean).join('')}\n`
const generateTOCLink = (path: string): string => {
const filepath = path.endsWith('/') ? `${path}README.md` : path.endsWith('.md') ? path : `${path || 'README'}.md`
const link = path.endsWith('/') ? `${path}index.html` : `${path}.html`
const page = llmPages.find((item) => {
return ensureLeadingSlash(item.filePathRelative || '') === filepath || link === item.path
})
if (page) {
usagePages.push(page)
return rawGenerateTOCLink(page, llmState)
}
return ''
}
const processAutoSidebar = (prefix: string): string[] => {
const list: string[] = []
llmPages.forEach((page) => {
if (ensureLeadingSlash(page.filePathRelative || '').startsWith(prefix)) {
usagePages.push(page)
list.push(rawGenerateTOCLink(page, llmState))
}
})
return list.filter(Boolean)
}
const processSidebar = (items: (string | ThemeSidebarItem)[], prefix: string): string[] => {
const result: string[] = []
items.forEach((item) => {
if (typeof item === 'string') {
result.push(generateTOCLink(normalizePath(prefix, item)))
}
else {
if (item.link) {
result.push(generateTOCLink(normalizePath(prefix, item.link)))
}
if (item.items === 'auto') {
result.push(...processAutoSidebar(normalizePath(prefix, item.prefix)))
}
else if (item.items?.length) {
result.push(...processSidebar(item.items, normalizePath(prefix, item.prefix)))
}
}
})
return result
}
// Notes
zhNotes.notes.forEach(({ dir, link, sidebar = [] }) => {
tableOfContent += `### ${noteNames[link]}\n\n`
const prefix = normalizePath('/notes/', dir)
if (sidebar === 'auto') {
tableOfContent += `${processAutoSidebar(prefix).join('')}\n`
}
else if (sidebar.length) {
const home = generateTOCLink(ensureEndingSlash(prefix))
const list = processSidebar(sidebar, prefix)
if (home && !list.includes(home)) {
list.unshift(home)
}
tableOfContent += `${list.join('')}\n`
}
})
// Others
const unUsagePages = llmPages.filter(page => !usagePages.includes(page))
if (unUsagePages.length) {
tableOfContent += '### Others\n\n'
tableOfContent += unUsagePages
.map(page => rawGenerateTOCLink(page, llmState))
.join('')
}
return tableOfContent
}

View File

@ -6,13 +6,13 @@ export const zhNavbar: ThemeNavItem[] = defineNavbarConfig([
{
text: '指南',
icon: 'icon-park-outline:guide-board',
link: '/notes/theme/guide/quick-start/intro.md',
link: '/guide/quick-start/intro.md',
activeMatch: '^/guide/',
},
{
text: '配置',
icon: 'icon-park-outline:setting-two',
link: '/notes/theme/config/intro.md',
link: '/config/intro.md',
activeMatch: '^/config/',
},
{
@ -78,11 +78,15 @@ export const enNavbar: ThemeNavItem[] = defineNavbarConfig([
text: 'More',
icon: 'icon-park-outline:more-three',
items: [
{ text: 'FAQ', link: '/en/faq/', icon: 'wpf:faq' },
{ text: 'Theme Tools', link: '/en/tools/', icon: 'jam:tools' },
{ text: 'Friend Links', link: '/en/friends/', icon: 'carbon:friendship' },
{
text: 'Vuepress',
icon: 'logos:vue',
items: [
{ text: 'Official Docs', link: 'https://v2.vuepress.vuejs.org' },
{ text: 'Ecosystem', link: 'https://ecosystem.vuejs.press/' },
{ text: 'Official Docs', link: 'https://v2.vuepress.vuejs.org', icon: 'logos:vue' },
{ text: 'Ecosystem', link: 'https://ecosystem.vuejs.press/', icon: 'logos:vue' },
],
},
],
@ -90,9 +94,10 @@ export const enNavbar: ThemeNavItem[] = defineNavbarConfig([
{
text: `${version}`,
icon: 'codicon:versions',
badge: 'New',
items: [
{ text: 'Changelog', link: '/changelog/' },
{ text: 'Contributing', link: '/contributing/' },
{ text: 'Changelog', link: '/en/changelog/' },
{ text: 'Contributing', link: '/en/contributing/' },
],
},
])

View File

@ -1,13 +0,0 @@
import type { ThemeNoteListOptions } from 'vuepress-theme-plume'
import { defineNotesConfig } from 'vuepress-theme-plume'
import { themeConfig } from './theme-config'
import { themeGuide } from './theme-guide'
export const enNotes: ThemeNoteListOptions = defineNotesConfig({
dir: 'en/notes',
link: '/',
notes: [
themeGuide,
themeConfig,
],
})

View File

@ -1,28 +0,0 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
export const themeConfig: ThemeNote = defineNoteConfig({
dir: 'theme/config',
link: '/config/',
sidebar: [
{
text: 'Config',
collapsed: false,
items: [
'intro',
'basic',
'locales',
'notes',
],
},
{
text: 'frontmatter',
prefix: 'frontmatter',
collapsed: false,
items: [
'basic',
'article',
],
},
],
})

View File

@ -1,68 +0,0 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
export const themeGuide: ThemeNote = defineNoteConfig({
dir: 'theme/guide',
link: '/guide/',
sidebar: [
{
text: 'Quick Start',
collapsed: false,
icon: 'carbon:idea',
prefix: 'quick-start',
items: [
'intro',
'usage',
'project-structure',
'write',
'blog',
'document',
'international',
'deployment',
'optimize-build',
],
},
{
text: 'Write',
icon: 'fluent-mdl2:edit-create',
collapsed: false,
items: [
{
text: 'markdown',
icon: 'material-symbols:markdown-outline',
prefix: 'markdown',
collapsed: true,
items: [
'basic',
'extensions',
'icons',
'mark',
'plot',
'abbr',
'annotation',
'card',
'steps',
'file-tree',
'tabs',
'timeline',
'demo-wrapper',
'collapse',
'npm-to',
'caniuse',
'include',
],
},
],
},
{
text: 'Customization',
icon: 'material-symbols:dashboard-customize-outline-rounded',
collapsed: false,
prefix: 'custom',
items: [
'home',
'style',
],
},
],
})

View File

@ -1,17 +0,0 @@
import type { ThemeNoteListOptions } from 'vuepress-theme-plume'
import { defineNotesConfig } from 'vuepress-theme-plume'
// import { plugins } from './plugins'
import { themeConfig } from './theme-config'
import { themeGuide } from './theme-guide'
import { tools } from './tools'
export const zhNotes: ThemeNoteListOptions = defineNotesConfig({
dir: 'notes',
link: '/',
notes: [
themeGuide,
themeConfig,
// plugins,
tools,
],
})

View File

@ -1,33 +0,0 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
export const plugins: ThemeNote = defineNoteConfig({
dir: 'plugins',
link: '/plugins/',
sidebar: [
{
text: '插件',
link: '/plugins/',
items: [
// 'caniuse',
// 'iconify',
'shiki',
'md-power',
'content-updated',
{
text: 'plugin-netlify-functions',
dir: 'netlify-functions',
link: '/plugins/plugin-netlify-functions/',
collapsed: true,
items: [
'介绍',
'使用',
'功能',
'api',
'functions',
],
},
],
},
],
})

View File

@ -1,18 +0,0 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
export const tools: ThemeNote = defineNoteConfig({
dir: 'tools',
link: '/tools/',
sidebar: [
{
text: '工具',
icon: 'tabler:tools',
items: [
'custom-theme',
'home-hero-tint-plate',
'caniuse',
],
},
],
})

View File

@ -1,8 +1,8 @@
import type { ThemeConfig } from 'vuepress-theme-plume'
import path from 'node:path'
import { defineThemeConfig } from 'vuepress-theme-plume'
import { enCollections, zhCollections } from './collections/index.js'
import { enNavbar, zhNavbar } from './navbar.js'
import { enNotes, zhNotes } from './notes/index.js'
export default defineThemeConfig({
logo: '/plume.png',
@ -15,6 +15,8 @@ export default defineThemeConfig({
organization: 'pengzhanbo',
},
transition: { appearance: 'circle-clip' },
social: [
{ icon: 'github', link: 'https://github.com/pengzhanbo/vuepress-theme-plume' },
{ icon: 'qq', link: 'https://qm.qq.com/q/FbPPoOIscE' },
@ -27,12 +29,12 @@ export default defineThemeConfig({
locales: {
'/': {
notes: zhNotes,
navbar: zhNavbar,
collections: zhCollections,
},
'/en/': {
notes: enNotes,
navbar: enNavbar,
collections: enCollections,
},
},
@ -41,7 +43,6 @@ export default defineThemeConfig({
'/article/enx7c9s/': '123456',
},
},
autoFrontmatter: { exclude: ['**/*.snippet.*'] },
bulletin: {
layout: 'top-right',

View File

@ -0,0 +1,4 @@
/llms.md /llms.txt 200!
/llms-full.md /llms-full.txt 200!
/en/llms.md /en/llms.txt 200!
/en/llms-full.md /en/llms-full.txt 200!

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 KiB

View File

@ -18,6 +18,15 @@ export const theme: Theme = plumeTheme({
},
markdown: {
icon: {
provider: 'iconify',
preload: [
// used within <AsideNae />
'tabler:star',
'octicon:issue-opened-16',
'ep:milk-tea',
],
},
chartjs: true,
echarts: true,
markmap: true,
@ -34,7 +43,9 @@ export const theme: Theme = plumeTheme({
codeTree: true,
field: true,
imageSize: 'all',
mark: 'lazy',
pdf: true,
qrcode: true,
caniuse: true,
acfun: true,
bilibili: true,
@ -46,6 +57,8 @@ export const theme: Theme = plumeTheme({
codeSandbox: true,
jsfiddle: true,
demo: true,
encrypt: true,
obsidian: true,
npmTo: ['pnpm', 'yarn', 'npm'],
repl: {
go: true,
@ -75,4 +88,16 @@ export const theme: Theme = plumeTheme({
content: 'vuepress-theme-plume',
},
},
llmstxt: {
locale: 'all',
llmsTxtTemplateGetter: {
description: (_, { currentLocale }) => {
return currentLocale === '/'
? '一个简约易用的,功能丰富的 vuepress 文档&博客 主题'
: 'An easy-to-use and feature-rich vuepress documentation and blog theme'
},
details: '',
},
},
})

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed } from 'vue'
import { VPLink } from 'vuepress-theme-plume/client'
import { VPIcon, VPLink } from 'vuepress-theme-plume/client'
import { useRouteLocale } from 'vuepress/client'
interface Locale {
@ -21,17 +21,17 @@ const locale = computed(() => locales[lang.value])
<template>
<div class="aside-nav-wrapper">
<VPLink class="link" no-icon href="https://github.com/pengzhanbo/vuepress-theme-plume">
<span class="vpi-github-star" />
<VPIcon name="tabler:star" />
<span class="link-text">{{ locale.star }}</span>
<span class="vpi-arrow-right" />
</VPLink>
<VPLink class="link" no-icon href="https://github.com/pengzhanbo/vuepress-theme-plume/issues/new/choose">
<span class="vpi-github-issue" />
<VPIcon name="octicon:issue-opened-16" />
<span class="link-text">{{ locale.issue }}</span>
<span class="vpi-arrow-right" />
</VPLink>
<VPLink class="link" href="/sponsor/">
<span class="vpi-bubble-tea" />
<VPIcon name="ep:milk-tea" />
<span class="link-text">{{ locale.sponsor }}</span>
<span class="vpi-arrow-right" />
</VPLink>
@ -65,15 +65,7 @@ const locale = computed(() => locales[lang.value])
font-size: 12px;
}
.vpi-github-star {
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m12 1.5l3.1 6.3l6.9 1l-5 4.8l1.2 6.9l-6.2-3.2l-6.2 3.2L7 13.6L2 8.8l6.9-1z'/%3E%3C/svg%3E");
}
.vpi-github-issue {
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' d='M8 9.5a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3'/%3E%3Cpath fill='%23000' d='M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0M1.5 8a6.5 6.5 0 1 0 13 0a6.5 6.5 0 0 0-13 0'/%3E%3C/svg%3E");
}
.vpi-bubble-tea {
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m17.95 9l-1.478 8.69c-.25 1.463-.374 2.195-.936 2.631c-1.2.931-6.039.88-7.172 0c-.562-.436-.687-1.168-.936-2.632L5.95 9M6 9l.514-1.286a5.908 5.908 0 0 1 10.972 0L18 9M5 9h14m-7 0l4-7m-5.99 12h.01m1 4h.01m1.99-2h.01'/%3E%3C/svg%3E");
.aside-nav-wrapper :deep([class*=" vpi-"]) {
margin: 0;
}
</style>

View File

@ -1,22 +1,48 @@
<script setup lang="ts">
import { shallowRef, useId } from 'vue'
import type { LocaleConfig } from 'vuepress'
import { computed, shallowRef, useId } from 'vue'
import { useRouteLocale } from 'vuepress/client'
import { useCaniuse, useCaniuseFeaturesSearch, useCaniuseVersionSelect } from '../composables/caniuse.js'
import CodeViewer from './CodeViewer.vue'
const LOCALES: LocaleConfig<
Record<'select-feature' | 'placeholder' | 'embed-type' | 'output' | 'browser-version' | 'no-recommend', string>
> = {
'/': {
'select-feature': '选择特性:',
'placeholder': '输入特性',
'embed-type': '嵌入方式:',
'output': '输出:',
'browser-version': '浏览器版本:',
'no-recommend': '不推荐',
},
'/en/': {
'select-feature': 'Select feature:',
'placeholder': 'Input feature',
'embed-type': 'Embed type: ',
'output': 'Output:',
'browser-version': 'Browser version: ',
'no-recommend': 'Not recommended',
},
}
const listEl = shallowRef<HTMLUListElement | null>(null)
const inputEl = shallowRef<HTMLInputElement | null>(null)
const id = useId()
const routeLocale = useRouteLocale()
const locale = computed(() => LOCALES[routeLocale.value])
const { feature, featureList, onSelect, isFocus } = useCaniuseFeaturesSearch(inputEl, listEl)
const { past, pastList, future, futureList, embedType, embedTypeList } = useCaniuseVersionSelect()
const { output, rendered } = useCaniuse({ feature, embedType, past, future })
const { output } = useCaniuse({ feature, embedType, past, future })
</script>
<template>
<div class="caniuse-config-wrapper">
<form>
<label class="caniuse-form-item" :for="`caniuse-feature-input-${id}`">
<span>选择特性</span>
<span>{{ locale['select-feature'] }}</span>
<div class="feature-input">
<input
:id="`caniuse-feature-input-${id}`"
@ -24,7 +50,7 @@ const { output, rendered } = useCaniuse({ feature, embedType, past, future })
class="feature-input__input"
type="text"
name="feature"
placeholder="输入特性"
:placeholder="locale.placeholder"
>
<span class="vpi-chevron-down" />
<ul v-show="isFocus" ref="listEl" class="feature-list">
@ -37,15 +63,14 @@ const { output, rendered } = useCaniuse({ feature, embedType, past, future })
class="feature-list-item"
@click="onSelect(item)"
@keydown.enter="onSelect(item)"
>
{{ item.label }}
</button>
v-html="item.label"
/>
</li>
</ul>
</div>
</label>
<div class="caniuse-form-item">
<span>嵌入方式</span>
<span>{{ locale['embed-type'] }}</span>
<div class="caniuse-embed-type">
<label
v-for="(item, index) in embedTypeList"
@ -54,12 +79,11 @@ const { output, rendered } = useCaniuse({ feature, embedType, past, future })
>
<input :id="`caniuse-embed-${id}-${index}`" v-model="embedType" type="radio" name="embedType" :value="item.value">
<span>{{ item.label }}</span>
<Badge v-if="item.value === 'image'" type="warning" text="不推荐" />
</label>
</div>
</div>
<div v-if="!embedType" class="caniuse-form-item">
<span>浏览器版本</span>
<span>{{ locale['browser-version'] }}</span>
<div class="caniuse-browser-version">
<label :for="`caniuse-past-${id}`">
<select :id="`caniuse-past-${id}`" v-model="past" name="past">
@ -80,11 +104,10 @@ const { output, rendered } = useCaniuse({ feature, embedType, past, future })
</div>
</form>
<div class="caniuse-output">
<h4>输出</h4>
<h4>{{ locale.output }}</h4>
<CodeViewer lang="md" :content="output" />
</div>
<div v-if="embedType === 'image'" v-html="rendered" />
<CanIUseViewer v-else-if="feature" :feature="feature" :past="past" :future="future" />
<CanIUseViewer v-if="feature" :feature="feature" :past="past" :future="future" :baseline="embedType === 'baseline'" />
</div>
</template>

View File

@ -1,12 +1,20 @@
<script setup lang="ts">
import type { PlumeThemeHomeHeroTintPlate } from 'vuepress-theme-plume/client'
import { computed, watch } from 'vue'
import InputRange from './InputRange.vue'
const min = 20
const max = 240
const tintPlate = defineModel<PlumeThemeHomeHeroTintPlate>({
interface PlateItem {
value: number
offset: number
}
const tintPlate = defineModel<{
r: PlateItem
g: PlateItem
b: PlateItem
}>({
required: true,
})

View File

@ -28,7 +28,7 @@ defineProps<{
<a :href="demo.url" target="_blank" rel="noopener noreferrer" :aria-label="demo.name" :title="demo.name">{{ demo.name }}</a>
</span>
<a v-if="demo.repo" :href="demo.repo" class="github" target="_blank" rel="noopener noreferrer" :aria-label="`Link to GitHub: ${demo.name}`">
<span class="vpi-social-github" />
<span class="vpi-simple-icons-github" />
</a>
</h3>
<p :title="demo.desc">

View File

@ -0,0 +1,87 @@
<script setup lang="ts">
import { useClipboard } from '@vueuse/core'
import { computed } from 'vue'
const { list } = defineProps<{
list: Record<string, string>
}>()
const emojiList = computed(() => {
return Object.entries(list).map(([key, value]) => ({
source: `:${key}:`,
rendered: value,
}))
})
const { copy, copied, text } = useClipboard()
</script>
<template>
<div class="emoji-wrapper">
<ul>
<li
v-for="{ source, rendered } in emojiList" :key="source"
:class="{ copied: copied && text === source }"
>
<Abbreviation @click="copy(source)">
{{ rendered }}
<template #tooltip>
{{ source }}
</template>
</Abbreviation>
</li>
</ul>
</div>
</template>
<style scoped>
.emoji-wrapper ul {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
justify-content: flex-start;
padding: 0;
list-style: none;
}
.emoji-wrapper ul li {
display: flex;
align-items: center;
justify-content: center;
width: 54px;
height: 54px;
margin: 0;
font-size: 28px;
cursor: pointer;
border: solid 1px var(--vp-c-divider);
border-radius: 4px;
transition: border-color var(--vp-t-color);
}
.emoji-wrapper ul li.copied {
position: relative;
border-color: var(--vp-c-brand);
}
.emoji-wrapper ul li.copied::after {
position: absolute;
right: 0;
bottom: 0;
display: inline-block;
width: 14px;
height: 14px;
font-size: 14px;
line-height: 14px;
color: var(--vp-c-success-1);
text-align: center;
vertical-align: -0.125em;
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M21 7L9 19l-5.5-5.5l1.41-1.41L9 16.17L19.59 5.59z'/%3E%3C/svg%3E");
background-color: var(--vp-c-success-soft);
}
.emoji-wrapper ul li .vp-abbr {
text-decoration: none;
cursor: inherit;
}
</style>

View File

@ -1,5 +1,4 @@
<script setup lang="ts">
import type { PlumeThemeHomeHeroTintPlate } from 'vuepress-theme-plume/client'
import { computed, ref, watch } from 'vue'
import VPHomeHero from 'vuepress-theme-plume/components/Home/VPHomeHero.vue'
import { useDarkMode } from 'vuepress-theme-plume/composables'
@ -10,6 +9,11 @@ import SingleTintPlate from './SingleTintPlate.vue'
import TripletTintPlate from './TripletTintPlate.vue'
type Mode = 'single' | 'triplet' | 'custom'
interface HeroTripletTintPlate {
r: { value: number, offset: number }
g: { value: number, offset: number }
b: { value: number, offset: number }
}
const hero = { name: 'Theme Plume', tagline: 'Next Theme', text: '简约的,功能丰富', actions: [] }
const modeList: { value: Mode, label: string }[] = [
@ -21,7 +25,7 @@ const modeList: { value: Mode, label: string }[] = [
const mode = ref<Mode>('single')
const singleTintPlate = ref<number>(220)
const tripletTintPlate = ref<[number, number, number]>([220, 220, 220])
const customTintPlate = ref<PlumeThemeHomeHeroTintPlate>({
const customTintPlate = ref<HeroTripletTintPlate>({
r: { value: 220, offset: 36 },
g: { value: 220, offset: 36 },
b: { value: 220, offset: 36 },
@ -30,13 +34,13 @@ const customTintPlate = ref<PlumeThemeHomeHeroTintPlate>({
const tintPlate = computed(() => {
switch (mode.value) {
case 'single':
return singleTintPlate.value
return { rgb: singleTintPlate.value }
case 'triplet':
return tripletTintPlate.value.join(',')
return { rgb: tripletTintPlate.value.join(',') }
case 'custom':
return customTintPlate.value
default:
return ''
return { rgb: '' }
}
})
@ -48,11 +52,11 @@ watch(useDarkMode(), (value) => {
const output = computed(() => {
const tint = tintPlate.value
let content = `---\nhome: true\nconfig:\n -\n type: hero\n background: tint-plate\n tintPlate:`
if (typeof tint === 'number' || typeof tint === 'string')
content += ` ${tint}`
if (typeof tint === 'object') {
let content = `---\nhome: true\nconfig:\n -\n type: hero\n effect: tint-plate\n effectConfig:`
if ('rgb' in tint) {
content += ` ${tint.rgb}`
}
else if (typeof tint === 'object') {
content += `
r:
value: ${tint.r.value}
@ -72,9 +76,9 @@ const output = computed(() => {
<template>
<div class="hero-tint-plate-wrapper">
<h4>效果预览</h4>
<div :class="{ dark: isDark }">
<div :data-theme="isDark ? 'dark' : 'light'">
<DemoWrapper>
<VPHomeHero type="hero" background="tint-plate" :tint-plate="tintPlate" :hero="hero" />
<VPHomeHero type="hero" effect="TintPlate" :effect-config="tintPlate" :hero="hero" :index="0" />
</DemoWrapper>
</div>
<p>

View File

@ -1,16 +1,41 @@
<script setup lang="ts">
import VPButton from '@theme/VPButton.vue'
import type { LocaleConfig } from 'vuepress'
import { computed } from 'vue'
import VPButton from 'vuepress-theme-plume/components/VPButton.vue'
import { useRouteLocale } from 'vuepress/client'
import { useThemeColors } from '../composables/theme-colors.js'
import CodeViewer from './CodeViewer.vue'
import ColorPick from './ColorPick.vue'
const locales: LocaleConfig<
Record<'reset' | 'light' | 'dark' | 'desc' | 'tip', string>
> = {
'/': {
reset: '重置',
light: '浅色主题',
dark: '深色主题',
desc: '复制下方的代码到您的项目中,请参考',
tip: '主题定制',
},
'/en/': {
reset: 'Reset',
light: 'Light theme',
dark: 'Dark theme',
desc: 'Copy the code below and paste it into your project, please refer to',
tip: 'Theme customization',
},
}
const routeLocale = useRouteLocale()
const locale = computed(() => locales[routeLocale.value])
const { lightColors, darkColors, css, reset } = useThemeColors()
</script>
<template>
<VPButton theme="alt" text="重置" @click="reset" />
<VPButton theme="alt" :text="locale.reset" @click="reset" />
<h2>浅色主题</h2>
<h2>{{ locale.light }}</h2>
<div class="theme-colors-wrapper">
<div v-for="({ name, group }, index) in lightColors" :key="index" class="group">
<h4>{{ name }}</h4>
@ -23,7 +48,7 @@ const { lightColors, darkColors, css, reset } = useThemeColors()
</section>
</div>
</div>
<h2>深色主题</h2>
<h2>{{ locale.dark }}</h2>
<div class="theme-colors-wrapper">
<div v-for="({ name, group }, index) in darkColors" :key="index" class="group">
<h4>{{ name }}</h4>
@ -36,7 +61,7 @@ const { lightColors, darkColors, css, reset } = useThemeColors()
</section>
</div>
</div>
<p>复制下方的代码到您的项目中请参考 <a href="/guide/custom-style/">主题定制</a> </p>
<p>{{ locale.desc }} <a href="/guide/custom-style/">{{ locale.tip }}</a> </p>
<CodeViewer :content="css" lang="css" />
</template>

View File

@ -1,6 +1,8 @@
import type { ComputedRef, Ref } from 'vue'
import type { LocaleConfig } from 'vuepress'
import { onClickOutside, useDebounceFn, useEventListener, useLocalStorage } from '@vueuse/core'
import { computed, onMounted, readonly, ref, watch } from 'vue'
import { useRouteLocale } from 'vuepress/client'
interface Feature {
label: string
@ -14,41 +16,60 @@ interface SelectItem {
const api = 'https://caniuse.pengzhanbo.cn/features.json'
const pastVersions: SelectItem[] = [
{ label: '不显示旧版本', value: '0' },
...Array.from({ length: 5 }).fill(0).map((_, i) => ({
label: `旧版本(当前版本 - ${i + 1}`,
value: `${i + 1}`,
})),
]
const futureVersions: SelectItem[] = [
{ label: '不显示未来版本', value: '0' },
...Array.from({ length: 3 }).fill(0).map((_, i) => ({
label: `未来版本(当前版本 + ${i + 1}`,
value: `${i + 1}`,
})),
]
const locales: LocaleConfig<
Record<'past0' | 'pastIndex' | 'future0' | 'futureIndex', string>
> = {
'/': {
past0: '不显示旧版本',
pastIndex: '旧版本(当前版本 - {index}',
future0: '不显示未来版本',
futureIndex: '未来版本(当前版本 + {index}',
},
'/en/': {
past0: 'Do not show old versions',
pastIndex: 'Old version (current version - {index})',
future0: 'Do not show future versions',
futureIndex: 'Future version (current version + {index})',
},
}
const embedTypes: SelectItem[] = [
{ label: 'iframe', value: '' },
{ label: 'image', value: 'image' },
{ label: 'caniuse', value: '' },
{ label: 'baseline', value: 'baseline' },
]
export function useCaniuseVersionSelect(): {
past: Ref<string>
future: Ref<string>
embedType: Ref<string>
pastList: Readonly<SelectItem[]>
futureList: Readonly<SelectItem[]>
pastList: ComputedRef<SelectItem[]>
futureList: ComputedRef<SelectItem[]>
embedTypeList: Readonly<SelectItem[]>
} {
const routeLocale = useRouteLocale()
const past = ref('2')
const future = ref('1')
const embedType = ref('')
const pastList = readonly(pastVersions)
const futureList = readonly(futureVersions)
const pastList = computed(() => {
return [
{ label: locales[routeLocale.value].past0 || '', value: '0' },
...Array.from({ length: 5 }).fill(0).map((_, i) => ({
label: locales[routeLocale.value]?.pastIndex?.replace('{index}', `${i + 1}`) ?? '',
value: `${i + 1}`,
})),
]
})
const futureList = computed(() => {
return [
{ label: locales[routeLocale.value].future0 || '', value: '0' },
...Array.from({ length: 3 }).fill(0).map((_, i) => ({
label: locales[routeLocale.value]?.futureIndex?.replace('{index}', `${i + 1}`) ?? '',
value: `${i + 1}`,
})),
]
})
const embedTypeList = readonly(embedTypes)
return {
@ -65,11 +86,11 @@ export function useCaniuseFeaturesSearch(
inputEl: Ref<HTMLInputElement | null>,
listEl: Ref<HTMLUListElement | null>,
): {
featureList: Ref<Feature[] | undefined>
isFocus: Ref<boolean>
feature: ComputedRef<string>
onSelect: (item: Feature) => void
} {
featureList: Ref<Feature[] | undefined>
isFocus: Ref<boolean>
feature: ComputedRef<string>
onSelect: (item: Feature) => void
} {
const features = useLocalStorage('plume:caniuse-feature-list', [] as Feature[])
const featuresUpdated = useLocalStorage('plume:caniuse-feature-list-updated', Date.now())
const maxAge = 1000 * 60 * 60 * 24 * 3 // 3 days
@ -137,19 +158,20 @@ export function useCaniuse({ feature, embedType, past, future }: {
past: Ref<string>
future: Ref<string>
}): {
output: ComputedRef<string>
rendered: ComputedRef<string>
} {
output: ComputedRef<string>
} {
const output = computed(() => {
let content = '@[caniuse'
if (embedType.value)
content += ` ${embedType.value}`
if (past.value !== '-2' || future.value !== '1') {
if (past.value === '0' && future.value === '0')
content += '{0}'
else
content += `{-${past.value},${future.value}}`
if (embedType.value !== 'baseline') {
if (past.value !== '-2' || future.value !== '1') {
if (past.value === '0' && future.value === '0')
content += '{0}'
else
content += `{-${past.value},${future.value}}`
}
}
content += ']('
@ -160,21 +182,5 @@ export function useCaniuse({ feature, embedType, past, future }: {
return `${content})`
})
const rendered = computed(() => {
if (!feature.value || !embedType.value)
return ''
return resolveCanIUse(feature.value)
})
return { output, rendered }
}
function resolveCanIUse(feature: string): string {
const link = 'https://caniuse.bitsofco.de/image/'
const alt = `Data on support for the ${feature} feature across the major browsers from caniuse.com`
return `<p><picture>
<source type="image/webp" srcset="${link}${feature}.webp">
<source type="image/png" srcset="${link}${feature}.png">
<img src="${link}${feature}.jpg" alt="${alt}" width="100%">
</picture></p>`
return { output }
}

File diff suppressed because it is too large Load Diff

View File

@ -1,135 +0,0 @@
---
title: 示例文章9
createTime: 2024/03/01 22:56:03
permalink: /article/z8zvx0ru/
---
:::go-repl
```go
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World")
}
```
:::
:::go-repl
```go
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
for i := 0; i < 10; i++ {
dur := time.Duration(rand.Intn(1000)) * time.Millisecond
fmt.Printf("Sleeping for %v\n", dur)
// Sleep for a random duration between 0-1000ms
time.Sleep(dur)
}
fmt.Println("Done!")
}
```
:::
::: go-repl
```go
package main
import (
"fmt"
"io"
"log"
"net"
"net/http"
"os"
)
func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, playground")
})
log.Println("Starting server...")
l, err := net.Listen("tcp", "localhost:8080")
if err != nil {
log.Fatal(err)
}
go func() {
log.Fatal(http.Serve(l, nil))
}()
log.Println("Sending request...")
res, err := http.Get("http://localhost:8080/hello")
if err != nil {
log.Fatal(err)
}
log.Println("Reading response...")
if _, err := io.Copy(os.Stdout, res.Body); err != nil {
log.Fatal(err)
}
}
```
:::
::: kotlin-repl
```kotlin
class Contact(val id: Int, var email: String)
fun main(args: Array<String>) {
val contact = Contact(1, "mary@gmail.com")
println(contact.id)
}
```
:::
::: kotlin-repl
```kotlin
fun mul(a: Int, b: Int): Int {
return a * b
}
fun main(args: Array<String>) {
print(mul(-2, 4))
}
```
:::
::: rust-repl
```rust
fn main() {
println!("Hello, world!");
}
```
:::
::: rust-repl
```rust
fn main() {
printlnl!("Hello, world!");
}
```
:::

View File

@ -5,7 +5,8 @@ config:
-
type: hero
full: true
background: tint-plate
effect: hyper-speed
forceDark: true
hero:
name: Theme Plume
tagline: VuePress Next Theme
@ -158,21 +159,7 @@ npm run docs:dev
感谢所有的贡献者!
<Contributors
:contributors="[
'pengzhanbo',
{ github: 'huankong233', name: 'huan_kong' },
{ github: 'northword', name: 'Northword' },
'KrLite',
'shylock-wu',
'hrradev',
{ github: 'TheCoderAlex', name: 'Tang Zifeng' },
{ github: 'HydroGest', name: 'MarkChai' },
{ github: 'sunnyboy-mu', name: '小沐沐吖' },
{ github: 'zhenghaoyang24', name: 'zhenghaoyang24' },
{ github: 'shuoliuchn', name: 'Shuo Liu' },
]"
/>
<Contributors :contributors="data" />
</div>
@ -184,4 +171,5 @@ npm run docs:dev
<script setup>
import Contributors from '~/components/Contributors.vue'
import data from '@source/contributors.json'
</script>

Some files were not shown because too many files have changed in this diff Show More