@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
|
|
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
|
|
98
|
+
function _(e) {
|
|
99
99
|
return y() ? e.dark || e.light : e.light || e.dark;
|
|
100
100
|
}
|
|
101
|
-
function
|
|
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
|
|
105
|
+
function C() {
|
|
106
106
|
let e = u();
|
|
107
107
|
if (!e) return !1;
|
|
108
|
-
let t =
|
|
108
|
+
let t = _(e);
|
|
109
109
|
return t ? (x(t), !0) : !1;
|
|
110
110
|
}
|
|
111
|
-
function
|
|
111
|
+
function w() {
|
|
112
112
|
let e = u();
|
|
113
113
|
if (!e) return !1;
|
|
114
|
-
let t =
|
|
114
|
+
let t = _(e);
|
|
115
115
|
return t ? (S(t), !0) : !1;
|
|
116
116
|
}
|
|
117
|
-
function
|
|
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 =
|
|
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 +
|
|
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 })) : (
|
|
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
|
-
|
|
172
|
+
v(T()), C() || k(), A(), f = new MutationObserver((e) => {
|
|
200
173
|
for (let t of e) if (t.attributeName === "class") {
|
|
201
|
-
|
|
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(),
|
|
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-
|
|
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.
|
|
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": {
|