@fuxishi/vitepress-theme 2.0.0-alpha.3 → 2.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README_EN.md ADDED
@@ -0,0 +1,140 @@
1
+ # @fuxishi/vitepress-theme
2
+
3
+ A beautiful VitePress theme extension with frosted glass effects, purple-blue gradients, rich animations, and ready to use.
4
+
5
+ [中文](./README.md)
6
+
7
+ ## Features
8
+
9
+ - 🎵 **Floating Music Ball** — Frosted glass floating player with single/playlist mode, purple-blue gradient progress ring and four playback animations
10
+ - 🎊 **Click Confetti** — Global click confetti effect with gold stars, colored paper pieces, and custom Emoji
11
+ - 🎨 **Hero Image Color** — Auto-extract colors from hero image for background glow, title gradient, code block beams, and music ball
12
+ - ✨ **Feature Glow** — Mouse-tracking glow effect on homepage Feature cards
13
+ - ✨ **Beam Border** — Purple-cyan brand color beam border on code blocks, code groups, and navigation in dark mode on hover
14
+ - 🔄 **Theme Switch Animation** — Circular spread animation for light/dark mode switching using View Transition API
15
+ - 📜 **Smooth Scroll** — Smooth scrolling when clicking outline navigation with silky marker transition
16
+ - 🎨 **Heading Decorations** — Different colored underlines for h1-h4 headings
17
+ - 📦 **Code Block Fold** — Auto-fold code blocks exceeding a line threshold with frosted glass blur overlay, configurable fold line count
18
+ - ⚙️ **Type-safe** — Complete TypeScript type definitions, IDE friendly
19
+
20
+ > **Note:** This version (v2.x) is built on VitePress `2.0` and is not backward compatible with VitePress 1.x.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @fuxishi/vitepress-theme
26
+ ```
27
+
28
+ Install peerDependencies:
29
+
30
+ ```bash
31
+ npm install vitepress
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ### 1. Register Theme
37
+
38
+ Create `.vitepress/theme/index.ts`:
39
+
40
+ ```ts
41
+ import FxTheme from "@fuxishi/vitepress-theme"
42
+ import "@fuxishi/vitepress-theme/style.css"
43
+
44
+ export default FxTheme
45
+ ```
46
+
47
+ ### 2. Extend Configuration
48
+
49
+ Create `.vitepress/config.mts`:
50
+
51
+ ```ts
52
+ import { defineConfig } from "vitepress"
53
+ import type { DefaultTheme } from "vitepress"
54
+ import fxConfig from "@fuxishi/vitepress-theme/config"
55
+ import type { FxThemeCustomConfig } from "@fuxishi/vitepress-theme"
56
+
57
+ type ThemeConfig = DefaultTheme.Config & FxThemeCustomConfig
58
+
59
+ export default defineConfig<ThemeConfig>({
60
+ extends: fxConfig,
61
+ lang: "en",
62
+ title: "My Docs",
63
+ themeConfig: {
64
+ nav: [{ text: "Guide", link: "/guide/" }],
65
+ sidebar: {
66
+ "/guide/": [{ text: "Getting Started", link: "/guide/" }],
67
+ },
68
+ // Enable music ball
69
+ musicBall: {
70
+ enable: true,
71
+ autoplay: false,
72
+ loop: true,
73
+ src: "/music/my-song.mp3",
74
+ },
75
+ // Enable confetti
76
+ confetti: true,
77
+ // Colored paper pieces
78
+ // confetti: { shape: "colored-paper" },
79
+ // Custom Emoji
80
+ // confetti: { shapes: ["🌸", "🎀"] },
81
+ // Enable hero image color extraction
82
+ heroImageColor: true,
83
+ // Enable smooth scroll
84
+ smoothScroll: true,
85
+ // Code block fold (enabled by default, 10 lines threshold)
86
+ codeBlockFold: true,
87
+ // Custom fold line threshold
88
+ // codeBlockFold: { lines: 20 },
89
+ },
90
+ })
91
+ ```
92
+
93
+ ### 3. Start Dev Server
94
+
95
+ ```bash
96
+ npx vitepress dev
97
+ ```
98
+
99
+ ## Configuration
100
+
101
+ ### FxThemeCustomConfig
102
+
103
+ Extends VitePress `DefaultTheme.Config` via intersection type `DefaultTheme.Config & FxThemeCustomConfig`, adding the following fields:
104
+
105
+ | Option | Type | Default | Description |
106
+ | --------------------- | --------------------------- | -------- | ----------------------------------------------------------------- |
107
+ | `musicBall.enable` | `boolean` | `true` | Enable music ball |
108
+ | `musicBall.visible` | `boolean` | `true` | Visibility |
109
+ | `musicBall.autoplay` | `boolean` | `false` | Autoplay |
110
+ | `musicBall.loop` | `boolean` | `true` | Loop playback (single mode) |
111
+ | `musicBall.src` | `string` | `''` | Single music URL |
112
+ | `musicBall.list` | `MusicItem[]` | — | Multi-song playlist |
113
+ | `confetti` | `boolean \| object` | `true` | Enable confetti |
114
+ | `confetti.shape` | `'star' \| 'colored-paper'` | `'star'` | Preset shape |
115
+ | `confetti.shapes` | `string \| string[]` | — | Custom Emoji shapes |
116
+ | `confetti.secondary` | `boolean` | `true` | Whether to add secondary particles |
117
+ | `heroImageColor` | `boolean` | `false` | Auto-extract hero image colors (affects glow, title, beams, ball) |
118
+ | `smoothScroll` | `boolean` | `false` | Enable smooth scrolling and outline marker transition |
119
+ | `codeBlockFold` | `boolean \| object` | `true` | Enable code block folding |
120
+ | `codeBlockFold.lines` | `number` | `10` | Line count threshold for folding |
121
+
122
+ ## Exports
123
+
124
+ | Export Path | Description |
125
+ | ------------------------------------ | ---------------------------- |
126
+ | `@fuxishi/vitepress-theme` | Theme (Layout + Styles) |
127
+ | `@fuxishi/vitepress-theme/config` | VitePress base config preset |
128
+ | `@fuxishi/vitepress-theme/style.css` | Standalone style file |
129
+
130
+ ## Documentation
131
+
132
+ Full documentation:
133
+
134
+ [https://fuxishi-vitepress-theme.fuxizjxzy.cn](https://fuxishi-vitepress-theme.fuxizjxzy.cn)
135
+
136
+ ## License
137
+
138
+ [MIT](./LICENSE)
139
+
140
+ > Will be open-sourced on GitHub in the future.
@@ -90,50 +90,33 @@ var C = e({
90
90
  render: () => null,
91
91
  setup(e) {
92
92
  if (!e.heroImageColor) return;
93
- let f = null, p = o(), { frontmatter: m } = a();
94
- function h() {
93
+ let f = null, p = o(), { frontmatter: m, site: h } = a();
94
+ function g() {
95
95
  let e = document.documentElement;
96
96
  e.style.removeProperty("--vp-home-hero-image-background-image"), e.style.removeProperty("--vp-home-hero-name-background"), e.style.removeProperty("--fx-beam-c1"), e.style.removeProperty("--fx-beam-c2");
97
97
  }
98
- function g(e) {
98
+ function _(e) {
99
99
  return y() ? e.dark || e.light : e.light || e.dark;
100
100
  }
101
- function _(e) {
101
+ function v(e) {
102
102
  let t = u();
103
103
  return !t || !t.images ? !1 : e && (e.light && t.images.light && e.light !== t.images.light || e.dark && t.images.dark && e.dark !== t.images.dark) ? (localStorage.removeItem(l), !0) : !1;
104
104
  }
105
- function v() {
105
+ function C() {
106
106
  let e = u();
107
107
  if (!e) return !1;
108
- let t = g(e);
108
+ let t = _(e);
109
109
  return t ? (x(t), !0) : !1;
110
110
  }
111
- function C() {
111
+ function w() {
112
112
  let e = u();
113
113
  if (!e) return !1;
114
- let t = g(e);
114
+ let t = _(e);
115
115
  return t ? (S(t), !0) : !1;
116
116
  }
117
- function w() {
117
+ function T() {
118
118
  return m.value.fxHeroImages || {};
119
119
  }
120
- async function T() {
121
- try {
122
- let e = await import(
123
- /* @vite-ignore */
124
- "/index.md"
125
- ), t = (typeof e.__pageData == "string" ? JSON.parse(e.__pageData) : e.__pageData)?.frontmatter?.hero?.image;
126
- return t ? typeof t == "string" ? {
127
- light: t,
128
- dark: t
129
- } : {
130
- light: t.light,
131
- dark: t.dark
132
- } : null;
133
- } catch {
134
- return null;
135
- }
136
- }
137
120
  async function E(e, t) {
138
121
  let n = e.src;
139
122
  if (n) try {
@@ -168,18 +151,13 @@ var C = e({
168
151
  }
169
152
  }
170
153
  async function k() {
171
- let e = w();
154
+ let e = T();
172
155
  if (e.light || e.dark) {
173
156
  await O(e);
174
157
  return;
175
158
  }
176
- let t = await T();
177
- if (t) {
178
- await O(t);
179
- return;
180
- }
181
159
  try {
182
- let e = await (await fetch(window.location.origin + "/")).text(), t = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".VPHero .image-container img.VPImage"), n = {};
160
+ let e = await (await fetch(window.location.origin + h.value.base)).text(), t = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".VPHero .image-container img.VPImage"), n = {};
183
161
  t.forEach((e) => {
184
162
  let t = e.getAttribute("src");
185
163
  t && (e.classList.contains("dark") ? n.dark = t : n.light = t);
@@ -188,17 +166,12 @@ var C = e({
188
166
  }
189
167
  function A() {
190
168
  let e = document.querySelector(".VPHero .image-container img.VPImage.light"), t = document.querySelector(".VPHero .image-container img.VPImage.dark");
191
- e || t ? (e && e.complete && e.naturalWidth > 0 ? E(e, "light") : e && e.addEventListener("load", () => E(e, "light"), { once: !0 }), t && t.complete && t.naturalWidth > 0 ? E(t, "dark") : t && t.addEventListener("load", () => E(t, "dark"), { once: !0 })) : (h(), C(), T().then((e) => {
192
- if (e && (e.light || e.dark)) {
193
- let t = u();
194
- t?.images && (e.light && t.images.light && e.light !== t.images.light || e.dark && t.images.dark && e.dark !== t.images.dark) && (localStorage.removeItem(l), O(e));
195
- }
196
- }), k());
169
+ e || t ? (e && e.complete && e.naturalWidth > 0 ? E(e, "light") : e && e.addEventListener("load", () => E(e, "light"), { once: !0 }), t && t.complete && t.naturalWidth > 0 ? E(t, "dark") : t && t.addEventListener("load", () => E(t, "dark"), { once: !0 })) : (g(), w(), k());
197
170
  }
198
171
  r(() => {
199
- _(w()), v() || k(), A(), f = new MutationObserver((e) => {
172
+ v(T()), C() || k(), A(), f = new MutationObserver((e) => {
200
173
  for (let t of e) if (t.attributeName === "class") {
201
- C(), A();
174
+ w(), A();
202
175
  break;
203
176
  }
204
177
  }), f.observe(document.documentElement, {
@@ -208,7 +181,7 @@ var C = e({
208
181
  }), i(() => p.path, () => {
209
182
  t(A);
210
183
  }), n(() => {
211
- f?.disconnect(), h();
184
+ f?.disconnect(), g();
212
185
  });
213
186
  }
214
187
  });
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ var d = {
32
32
  }, t = document.querySelector(".VPNavBarTitle .title");
33
33
  t && (x = new ResizeObserver(e), x.observe(t)), e();
34
34
  }), a(() => x?.disconnect());
35
- let w = c(() => import("./chunk/FxMusicBall-CTP51ydo.js"), [{ style: { display: g.musicBall && g.musicBall.visible ? "" : "none" } }]), T = c(() => import("./chunk/FxHomeFeatureBefore-Cd9m9wit.js")), E = c(() => import("./chunk/FxConfetti-DFRD5KKS.js"), [{ confetti: g.confetti }]), D = c(() => import("./chunk/FxHeroImageBg-Ge75loti.js"), [{ heroImageColor: g.heroImageColor }]), O = c(() => import("./chunk/FxCodeBlockFold-BZw-1rNl.js"), [{ lines: C }]);
35
+ let w = c(() => import("./chunk/FxMusicBall-CTP51ydo.js"), [{ style: { display: g.musicBall && g.musicBall.visible ? "" : "none" } }]), T = c(() => import("./chunk/FxHomeFeatureBefore-Cd9m9wit.js")), E = c(() => import("./chunk/FxConfetti-DFRD5KKS.js"), [{ confetti: g.confetti }]), D = c(() => import("./chunk/FxHeroImageBg-DyiZOKOD.js"), [{ heroImageColor: g.heroImageColor }]), O = c(() => import("./chunk/FxCodeBlockFold-BZw-1rNl.js"), [{ lines: C }]);
36
36
  return () => [
37
37
  S && n("style", `:root{--fx-code-fold-lines:${C || 10}}`),
38
38
  g.heroImageColor && n("style", ":root{--vp-home-hero-image-background-image:none;--vp-home-hero-name-color:transparent;--vp-home-hero-name-background:none}"),
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@fuxishi/vitepress-theme",
3
3
  "displayName": "@fuxishi/vitepress-theme",
4
4
  "private": false,
5
- "version": "2.0.0-alpha.3",
5
+ "version": "2.0.0-alpha.5",
6
6
  "license": "MIT",
7
7
  "description": "一款精美的 VitePress 主题",
8
8
  "keywords": [
@@ -14,7 +14,11 @@
14
14
  ],
15
15
  "type": "module",
16
16
  "files": [
17
- "dist"
17
+ "dist",
18
+ "LICENSE",
19
+ "README.md",
20
+ "README_EN.md",
21
+ "package.json"
18
22
  ],
19
23
  "main": "./dist/index.js",
20
24
  "module": "./dist/index.js",
@@ -44,6 +48,7 @@
44
48
  "ncu": "ncu -u && npm install",
45
49
  "login": "npm login --registry=https://registry.npmjs.org/",
46
50
  "pub": "npm publish --access public --registry=https://registry.npmjs.org/",
51
+ "pub-tag": "npm publish --access public --tag alpha --registry=https://registry.npmjs.org/",
47
52
  "deprecate": "node -e \"const v=process.argv[1],m=process.argv[2]||'';require('child_process').execSync('npm deprecate @fuxishi/vitepress-theme@'+v+' \\\"'+m+'\\\" --registry=https://registry.npmjs.org/',{stdio:'inherit'})\""
48
53
  },
49
54
  "dependencies": {