@windrun-huaiin/diaomao 2.6.1 → 10.0.0
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/.env.local.txt +1 -1
- package/.gitignore +4 -0
- package/messages/en.json +169 -42
- package/next-env.d.ts +1 -0
- package/package.json +56 -47
- package/patches/fumadocs-core@16.0.9.patch +15 -0
- package/patches/fumadocs-ui@16.0.9.patch +159 -0
- package/source.config.ts +0 -1
- package/src/app/[locale]/(clerk)/layout.tsx +26 -20
- package/src/app/[locale]/(clerk)/sign-in/[[...sign-in]]/page.tsx +2 -2
- package/src/app/[locale]/(clerk)/sign-up/[[...sign-up]]/page.tsx +2 -2
- package/src/app/[locale]/(clerk)/waitlist/[[...waitlist]]/page.tsx +1 -1
- package/src/app/[locale]/(home)/blog/[[...slug]]/page.tsx +3 -0
- package/src/app/[locale]/(home)/blog/layout.tsx +1 -1
- package/src/app/[locale]/(home)/layout.tsx +25 -23
- package/src/app/[locale]/(home)/legal/[[...slug]]/page.tsx +3 -0
- package/src/app/[locale]/(home)/legal/layout.tsx +1 -1
- package/src/app/[locale]/(home)/page.tsx +15 -12
- package/src/app/[locale]/(home)/pricing/page.tsx +40 -0
- package/src/app/[locale]/layout.config.tsx +17 -8
- package/src/app/[locale]/layout.tsx +17 -12
- package/src/app/api/blog/llm-content/route.ts +3 -8
- package/src/app/api/stripe/checkout/route.ts +145 -0
- package/src/app/api/stripe/customer-portal/route.ts +83 -0
- package/src/app/api/user/anonymous/init/route.ts +175 -0
- package/src/app/api/webhook/clerk/user/route.ts +249 -0
- package/src/app/api/webhook/stripe/route.ts +93 -0
- package/src/components/credit-popover.tsx +137 -0
- package/src/components/hero.tsx +13 -13
- package/src/components/mdx-components.tsx +1 -1
- package/src/lib/appConfig.ts +11 -3
- package/src/lib/auth-utils.ts +101 -0
- package/src/lib/fingerprint-config.ts +6 -0
- package/src/lib/fonts.ts +1 -0
- package/src/lib/money-price-config.ts +263 -0
- package/src/lib/money-price-helper.ts +61 -0
- package/src/lib/price-config.ts +1 -1
- package/src/lib/source-blog.ts +1 -1
- package/src/lib/source-legal.ts +1 -1
- package/src/lib/stripe-config.ts +333 -0
- package/src/mdx/blog/index.mdx +1 -1
- package/src/mdx/blog/ioc.mdx +1 -1
- package/src/mdx/blog/paid-system-design.mdx +640 -72
- package/src/proxy.ts +124 -0
- package/src/services/aggregate/billing.aggregate.service.ts +498 -0
- package/src/services/aggregate/index.ts +2 -0
- package/src/services/aggregate/user.aggregate.service.ts +164 -0
- package/src/services/context/index.ts +1 -0
- package/src/services/context/user-context-service.ts +200 -0
- package/src/services/database/apilog.service.ts +185 -0
- package/src/services/database/constants.ts +148 -0
- package/src/services/database/credit.service.ts +747 -0
- package/src/services/database/creditAuditLog.service.ts +402 -0
- package/src/services/database/index.ts +41 -0
- package/src/services/database/prisma-model-type.ts +13 -0
- package/src/services/database/prisma-transaction-util.ts +24 -0
- package/src/services/database/prisma.ts +122 -0
- package/src/services/database/subscription.service.ts +319 -0
- package/src/services/database/transaction.service.ts +447 -0
- package/src/services/database/user.service.ts +216 -0
- package/src/services/database/userBackup.service.ts +290 -0
- package/src/services/stripe/webhook-handler.ts +648 -0
- package/tsconfig.json +23 -6
- package/patches/fumadocs-ui@15.3.3.patch +0 -174
- package/src/middleware.ts +0 -47
package/.env.local.txt
CHANGED
|
@@ -13,7 +13,7 @@ NEXT_PUBLIC_STYLE_CDN_PROXY_URL=https://r2-explorer-template.zcy777et.workers.de
|
|
|
13
13
|
# 网站icon图标统一颜色(可选), 紫色
|
|
14
14
|
NEXT_PUBLIC_STYLE_ICON_COLOR=text-purple-500
|
|
15
15
|
# 网站svg图标统一颜色(可选), 紫色
|
|
16
|
-
NEXT_PUBLIC_STYLE_SVG_ICON_COLOR
|
|
16
|
+
NEXT_PUBLIC_STYLE_SVG_ICON_COLOR="#AC62FD"
|
|
17
17
|
# 网站svg图标大小适配(可选)
|
|
18
18
|
NEXT_PUBLIC_STYLE_SVG_ICON_SIZE=18
|
|
19
19
|
|
package/.gitignore
CHANGED
|
@@ -6,6 +6,8 @@ yarn-debug.log*
|
|
|
6
6
|
yarn-error.log*
|
|
7
7
|
lerna-debug.log*
|
|
8
8
|
.pnpm-debug.log*
|
|
9
|
+
.claude*
|
|
10
|
+
.codex*
|
|
9
11
|
|
|
10
12
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
11
13
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
@@ -132,3 +134,5 @@ dist
|
|
|
132
134
|
.source/index.ts
|
|
133
135
|
.source/source.config.mjs
|
|
134
136
|
|
|
137
|
+
|
|
138
|
+
/generated/prisma
|
package/messages/en.json
CHANGED
|
@@ -83,55 +83,167 @@
|
|
|
83
83
|
}
|
|
84
84
|
]
|
|
85
85
|
},
|
|
86
|
-
|
|
86
|
+
|
|
87
|
+
"moneyPrice": {
|
|
87
88
|
"title": "Choose Your Plan",
|
|
88
|
-
"subtitle": "
|
|
89
|
+
"subtitle": "Select the best option for your needs",
|
|
89
90
|
"billingSwitch": {
|
|
90
91
|
"options": [
|
|
91
|
-
{
|
|
92
|
-
|
|
92
|
+
{
|
|
93
|
+
"key": "monthly",
|
|
94
|
+
"name": "Monthly",
|
|
95
|
+
"unit": "/month",
|
|
96
|
+
"discountText": "",
|
|
97
|
+
"subTitle": "Billed Monthly"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"key": "yearly",
|
|
101
|
+
"name": "Yearly",
|
|
102
|
+
"unit": "/month",
|
|
103
|
+
"discountText": "Save {percent}%",
|
|
104
|
+
"subTitle": "Billed Annually"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"key": "onetime",
|
|
108
|
+
"name": "One-Time",
|
|
109
|
+
"unit": "Credit Pack",
|
|
110
|
+
"discountText": "Credit Pack",
|
|
111
|
+
"subTitle": "Pay Once"
|
|
112
|
+
}
|
|
93
113
|
],
|
|
94
114
|
"defaultKey": "yearly"
|
|
95
115
|
},
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
116
|
+
"subscription": {
|
|
117
|
+
"plans": [
|
|
118
|
+
{
|
|
119
|
+
"key": "F1",
|
|
120
|
+
"title": "Hobby",
|
|
121
|
+
"showBillingSubTitle": false,
|
|
122
|
+
"features": [
|
|
123
|
+
{ "description": "Basic features" },
|
|
124
|
+
{ "description": "Community support" },
|
|
125
|
+
{ "description": "Limited usage" },
|
|
126
|
+
{ "description": "No credit card required" }
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"key": "P2",
|
|
131
|
+
"title": "Pro",
|
|
132
|
+
"showBillingSubTitle": true,
|
|
133
|
+
"features": [
|
|
134
|
+
{
|
|
135
|
+
"description": "All Free features",
|
|
136
|
+
"tag": "Hobby"
|
|
137
|
+
},
|
|
138
|
+
{ "description": "Priority support" },
|
|
139
|
+
{
|
|
140
|
+
"description": "100 credits/month",
|
|
141
|
+
"tooltip": "1 credit = 1 AI generation"
|
|
142
|
+
},
|
|
143
|
+
{ "description": "Advanced analytics" }
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"key": "U3",
|
|
148
|
+
"title": "Ultra",
|
|
149
|
+
"showBillingSubTitle": true,
|
|
150
|
+
"titleTags": ["Most Popular"],
|
|
151
|
+
"features": [
|
|
152
|
+
{
|
|
153
|
+
"description": "All Pro features",
|
|
154
|
+
"tag": "Pro"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"description": "800 credits/month",
|
|
158
|
+
"tooltip": "1 credit = 1 AI generation"
|
|
159
|
+
},
|
|
160
|
+
{ "description": "Early access to new features" },
|
|
161
|
+
{
|
|
162
|
+
"description": "Dedicated support",
|
|
163
|
+
"tooltip": "24/7 priority support with dedicated account manager"
|
|
164
|
+
},
|
|
165
|
+
{ "description": "Custom integrations" }
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
"credits": {
|
|
171
|
+
"plans": [
|
|
172
|
+
{
|
|
173
|
+
"key": "F1",
|
|
174
|
+
"title": "Starter",
|
|
175
|
+
"subtitle": "5 Credits",
|
|
176
|
+
"showBillingSubTitle": true,
|
|
177
|
+
"features": [
|
|
178
|
+
{ "description": "5 AI generations" },
|
|
179
|
+
{ "description": "Perfect for trying out" },
|
|
180
|
+
{ "description": "No expiration" },
|
|
181
|
+
{ "description": "Instant activation" }
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"key": "P2",
|
|
186
|
+
"title": "Popular",
|
|
187
|
+
"subtitle": "10 Credits",
|
|
188
|
+
"showBillingSubTitle": true,
|
|
189
|
+
"titleTags": ["Preferred"],
|
|
190
|
+
"features": [
|
|
191
|
+
{ "description": "10 AI generations" },
|
|
192
|
+
{ "description": "Great for regular use" },
|
|
193
|
+
{ "description": "No expiration" },
|
|
194
|
+
{ "description": "Instant activation" },
|
|
195
|
+
{ "description": "Support batch processing" }
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"key": "U3",
|
|
200
|
+
"title": "Power",
|
|
201
|
+
"subtitle": "20 Credits",
|
|
202
|
+
"showBillingSubTitle": true,
|
|
203
|
+
"features": [
|
|
204
|
+
{ "description": "20 AI generations" },
|
|
205
|
+
{ "description": "Perfect for heavy users" },
|
|
206
|
+
{ "description": "No expiration" },
|
|
207
|
+
{ "description": "Instant activation" }
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
"buttonTexts": {
|
|
213
|
+
"buyCredits": "Buy Credits",
|
|
214
|
+
"getStarted": "Get Started",
|
|
215
|
+
"getPro": "Get Pro",
|
|
216
|
+
"getUltra": "Get Ultra",
|
|
217
|
+
"currentPlan": "Current Plan",
|
|
218
|
+
"upgrade": "Upgrade"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"credit": {
|
|
222
|
+
"summary": {
|
|
223
|
+
"description": "Sum of all available credits",
|
|
224
|
+
"totalLabel": "Total Credits"
|
|
225
|
+
},
|
|
226
|
+
"buckets": {
|
|
227
|
+
"title": "Credit Breakdown",
|
|
228
|
+
"empty": "No credits yet",
|
|
229
|
+
"expiredAtLabel": "Expires",
|
|
230
|
+
"expandDetail": "Click to show credit details",
|
|
231
|
+
"hiddenDetail": "Click to hide credit details",
|
|
232
|
+
"labels": {
|
|
233
|
+
"free": "Free",
|
|
234
|
+
"subscription": "Subscription",
|
|
235
|
+
"onetime": "One-Time"
|
|
133
236
|
}
|
|
134
|
-
|
|
237
|
+
},
|
|
238
|
+
"subscription": {
|
|
239
|
+
"periodLabel": "Current Plan",
|
|
240
|
+
"manage": "Manage Subscription",
|
|
241
|
+
"inactive": "Free",
|
|
242
|
+
"pay": "Subscribe Now"
|
|
243
|
+
},
|
|
244
|
+
"onetime": {
|
|
245
|
+
"buy": "Buy Credit Pack"
|
|
246
|
+
}
|
|
135
247
|
},
|
|
136
248
|
"features": {
|
|
137
249
|
"title": "Why Choose",
|
|
@@ -271,5 +383,20 @@
|
|
|
271
383
|
"pricing": "Pricing",
|
|
272
384
|
"legal": "Legal",
|
|
273
385
|
"docs": "Docs"
|
|
386
|
+
},
|
|
387
|
+
"fuma": {
|
|
388
|
+
"search": "Search",
|
|
389
|
+
"searchNoResult": "No results found",
|
|
390
|
+
"toc": "On this page",
|
|
391
|
+
"tocNoHeadings": "No Headings",
|
|
392
|
+
"lastUpdate": "Last updated on",
|
|
393
|
+
"emptyLastUpdate": "Ooops, Ages ago!",
|
|
394
|
+
"chooseLanguage": "Choose a language",
|
|
395
|
+
"nextPage": "Next Page",
|
|
396
|
+
"previousPage": "Previous Page",
|
|
397
|
+
"chooseTheme": "Theme",
|
|
398
|
+
"copyMarkdown": "Copy page as Markdown",
|
|
399
|
+
"copyMarkdownDone": "Copied!",
|
|
400
|
+
"editOnGithub": "Edit this page on GitHub"
|
|
274
401
|
}
|
|
275
402
|
}
|
package/next-env.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/diaomao",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -14,67 +14,77 @@
|
|
|
14
14
|
"react"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@clerk/localizations": "^3.
|
|
18
|
-
"@clerk/nextjs": "^6.
|
|
19
|
-
"@clerk/themes": "^2.
|
|
20
|
-
"@clerk/types": "^4.
|
|
17
|
+
"@clerk/localizations": "^3.28.0",
|
|
18
|
+
"@clerk/nextjs": "^6.35.1",
|
|
19
|
+
"@clerk/themes": "^2.4.36",
|
|
20
|
+
"@clerk/types": "^4.100.0",
|
|
21
|
+
"@fingerprintjs/fingerprintjs": "^4.6.2",
|
|
21
22
|
"@hookform/resolvers": "^3.10.0",
|
|
22
|
-
"@radix-ui/react-alert-dialog": "^1.1.
|
|
23
|
-
"@radix-ui/react-dropdown-menu": "^2.1.
|
|
24
|
-
"@radix-ui/react-label": "^2.1.
|
|
25
|
-
"@radix-ui/react-slot": "^1.2.
|
|
26
|
-
"@tailwindcss/typography": "
|
|
23
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
24
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
25
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
26
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
27
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
27
28
|
"@types/mdx": "^2.0.13",
|
|
28
|
-
"@windrun-huaiin/base-ui": "^
|
|
29
|
-
"@windrun-huaiin/lib": "^
|
|
30
|
-
"@windrun-huaiin/third-ui": "^
|
|
31
|
-
"autoprefixer": "^10.4.
|
|
29
|
+
"@windrun-huaiin/base-ui": "^10.1.0",
|
|
30
|
+
"@windrun-huaiin/lib": "^10.1.0",
|
|
31
|
+
"@windrun-huaiin/third-ui": "^10.1.0",
|
|
32
|
+
"autoprefixer": "^10.4.22",
|
|
32
33
|
"class-variance-authority": "^0.7.1",
|
|
33
34
|
"clsx": "^2.1.1",
|
|
34
|
-
"date-fns": "2.30.0",
|
|
35
|
-
"fumadocs-core": "
|
|
36
|
-
"fumadocs-
|
|
37
|
-
"fumadocs-
|
|
38
|
-
"
|
|
35
|
+
"date-fns": "^2.30.0",
|
|
36
|
+
"fumadocs-core": "16.0.9",
|
|
37
|
+
"fumadocs-docgen": "3.0.4",
|
|
38
|
+
"fumadocs-mdx": "13.0.6",
|
|
39
|
+
"fumadocs-typescript": "4.0.13",
|
|
40
|
+
"fumadocs-ui": "16.0.9",
|
|
41
|
+
"katex": "^0.16.25",
|
|
39
42
|
"lucide-react": "^0.525.0",
|
|
40
|
-
"mermaid": "^11.
|
|
41
|
-
"next": "
|
|
42
|
-
"next-intl": "^
|
|
43
|
+
"mermaid": "^11.12.1",
|
|
44
|
+
"next": "16.0.0",
|
|
45
|
+
"next-intl": "^4.4.0",
|
|
43
46
|
"next-themes": "^0.4.6",
|
|
44
|
-
"react": "19.
|
|
45
|
-
"react-dom": "19.
|
|
46
|
-
"react-medium-image-zoom": "^5.
|
|
47
|
+
"react": "19.2.0",
|
|
48
|
+
"react-dom": "19.2.0",
|
|
49
|
+
"react-medium-image-zoom": "^5.4.0",
|
|
47
50
|
"rehype-katex": "^7.0.1",
|
|
48
51
|
"remark": "^15.0.1",
|
|
52
|
+
"remark-frontmatter": "^5.0.0",
|
|
49
53
|
"remark-gfm": "^4.0.1",
|
|
50
54
|
"remark-math": "^6.0.0",
|
|
51
|
-
"remark-mdx": "^3.1.
|
|
52
|
-
"shiki": "^3.
|
|
53
|
-
"
|
|
55
|
+
"remark-mdx": "^3.1.1",
|
|
56
|
+
"shiki": "^3.15.0",
|
|
57
|
+
"stripe": "19.3.0",
|
|
58
|
+
"svix": "^1.81.0",
|
|
59
|
+
"swiper": "^12.0.3",
|
|
60
|
+
"tailwind-merge": "^3.4.0",
|
|
54
61
|
"tailwindcss-animate": "^1.0.7",
|
|
55
|
-
"
|
|
62
|
+
"uuid": "^11.1.0",
|
|
63
|
+
"zod": "^4.1.12"
|
|
56
64
|
},
|
|
57
65
|
"devDependencies": {
|
|
58
66
|
"@changesets/cli": "^2.29.5",
|
|
59
|
-
"@
|
|
60
|
-
"@tailwindcss/
|
|
67
|
+
"@prisma/client": "^6.19.0",
|
|
68
|
+
"@tailwindcss/cli": "^4.1.17",
|
|
69
|
+
"@tailwindcss/postcss": "^4.1.17",
|
|
61
70
|
"@types/hast": "^3.0.4",
|
|
62
|
-
"@types/node": "^22.
|
|
71
|
+
"@types/node": "^22.17.2",
|
|
63
72
|
"@types/nprogress": "^0.2.3",
|
|
64
|
-
"@types/react": "19.1.2",
|
|
65
|
-
"@types/react-dom": "19.1.3",
|
|
73
|
+
"@types/react": "^19.1.2",
|
|
74
|
+
"@types/react-dom": "^19.1.3",
|
|
66
75
|
"@types/react-medium-image-zoom": "^3.0.3",
|
|
67
|
-
"@
|
|
68
|
-
"@
|
|
69
|
-
"
|
|
70
|
-
"eslint
|
|
71
|
-
"eslint-
|
|
76
|
+
"@types/uuid": "^10.0.0",
|
|
77
|
+
"@typescript-eslint/parser": "^8.46.4",
|
|
78
|
+
"@windrun-huaiin/dev-scripts": "^10.1.0",
|
|
79
|
+
"eslint": "^9.39.1",
|
|
80
|
+
"eslint-config-next": "^16.0.0",
|
|
81
|
+
"eslint-plugin-unused-imports": "^4.3.0",
|
|
72
82
|
"fast-glob": "^3.3.3",
|
|
73
83
|
"nprogress": "^0.2.0",
|
|
74
|
-
"postcss": "^8.5.
|
|
75
|
-
"
|
|
76
|
-
"tailwindcss": "^4.1.
|
|
77
|
-
"ts-morph": "
|
|
84
|
+
"postcss": "^8.5.6",
|
|
85
|
+
"prisma": "^6.19.0",
|
|
86
|
+
"tailwindcss": "^4.1.17",
|
|
87
|
+
"ts-morph": "^27.0.2",
|
|
78
88
|
"ts-node": "^10.9.2",
|
|
79
89
|
"typescript": "^5.8.3",
|
|
80
90
|
"unist-util-visit": "^5.0.0"
|
|
@@ -104,12 +114,10 @@
|
|
|
104
114
|
"!**/*.log"
|
|
105
115
|
],
|
|
106
116
|
"scripts": {
|
|
107
|
-
"postinstall": "fumadocs-mdx",
|
|
108
|
-
"predev": "pnpm run lint",
|
|
109
117
|
"dev": "next dev --turbopack",
|
|
110
118
|
"build": "pnpm generate-blog-index && next build",
|
|
111
119
|
"build:dev": "pnpm generate-blog-index && next build",
|
|
112
|
-
"build:prod": "next build",
|
|
120
|
+
"build:prod": "prisma generate && next build",
|
|
113
121
|
"start": "next start",
|
|
114
122
|
"lint": "next lint",
|
|
115
123
|
"deep-clean": "dev-scripts deep-clean",
|
|
@@ -123,6 +131,7 @@
|
|
|
123
131
|
"clean-translations": "dev-scripts clean-translations -v",
|
|
124
132
|
"remove-translations": "dev-scripts clean-translations --remove -v",
|
|
125
133
|
"whoareyou": "dev-scripts generate-nextjs-architecture -v",
|
|
126
|
-
"windrun": "pnpm remove @windrun-huaiin/base-ui @windrun-huaiin/lib @windrun-huaiin/third-ui @windrun-huaiin/dev-scripts && pnpm add @windrun-huaiin/base-ui@latest @windrun-huaiin/lib@latest @windrun-huaiin/third-ui@latest && pnpm add -D @windrun-huaiin/dev-scripts@latest"
|
|
134
|
+
"windrun": "pnpm remove @windrun-huaiin/base-ui @windrun-huaiin/lib @windrun-huaiin/third-ui @windrun-huaiin/dev-scripts && pnpm add @windrun-huaiin/base-ui@latest @windrun-huaiin/lib@latest @windrun-huaiin/third-ui@latest && pnpm add -D @windrun-huaiin/dev-scripts@latest",
|
|
135
|
+
"windrun3": "pnpm remove @windrun-huaiin/third-ui && pnpm add @windrun-huaiin/third-ui@latest"
|
|
127
136
|
}
|
|
128
137
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
diff --git a/dist/toc.js b/dist/toc.js
|
|
2
|
+
index 7d1336e9b4e54d862739ed02019505e7f3c2589d..e3d504e38a0d07cf6341704898e570dbf58b9002 100644
|
|
3
|
+
--- a/dist/toc.js
|
|
4
|
+
+++ b/dist/toc.js
|
|
5
|
+
@@ -100,7 +100,9 @@ function useAnchorObserver(watch, single) {
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
if (state.visible.size === 0) {
|
|
9
|
+
- const viewTop = entries[0].rootBounds.top;
|
|
10
|
+
+ const rootBounds = entries[0]?.rootBounds;
|
|
11
|
+
+ if (!rootBounds) return;
|
|
12
|
+
+ const viewTop = rootBounds.top;
|
|
13
|
+
let fallback;
|
|
14
|
+
let min = -1;
|
|
15
|
+
for (const id of watch) {
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
diff --git a/dist/components/layout/toc-clerk.d.ts.map b/dist/components/layout/toc-clerk.d.ts.map
|
|
2
|
+
index 9156ea92f045791b8600661d8dac7ef17e8659bc..aec472b0c2387fea6c5ee0f2668087de2530398e 100644
|
|
3
|
+
--- a/dist/components/layout/toc-clerk.d.ts.map
|
|
4
|
+
+++ b/dist/components/layout/toc-clerk.d.ts.map
|
|
5
|
+
@@ -1 +1 @@
|
|
6
|
+
-{"version":3,"file":"toc-clerk.d.ts","sourceRoot":"","sources":["../../../src/components/layout/toc-clerk.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAA+B,MAAM,OAAO,CAAC;AAOzE,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,GAAG,EACH,SAAS,EACT,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,KAAK,CAAC,2CAsGvB"}
|
|
7
|
+
|
|
8
|
+
+{"version":3,"file":"toc-clerk.d.ts","sourceRoot":"","sources":["../../../src/components/layout/toc-clerk.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,OAAO,CAAC;AAMpE,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,GAAG,EACH,SAAS,EACT,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,KAAK,CAAC,2CA4BvB"}
|
|
9
|
+
|
|
10
|
+
diff --git a/dist/components/layout/toc-clerk.js b/dist/components/layout/toc-clerk.js
|
|
11
|
+
index 40f8b2b191cd2817a51de0aaf9c492a3077aac60..f36b807e5eea299e18818b9d938aa506cbaad406 100644
|
|
12
|
+
--- a/dist/components/layout/toc-clerk.js
|
|
13
|
+
+++ b/dist/components/layout/toc-clerk.js
|
|
14
|
+
@@ -1,9 +1,8 @@
|
|
15
|
+
'use client';
|
|
16
|
+
-import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
|
+
+import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import * as Primitive from 'fumadocs-core/toc';
|
|
19
|
+
-import { useEffect, useRef, useState } from 'react';
|
|
20
|
+
+import { useRef } from 'react';
|
|
21
|
+
import { cn } from '../../utils/cn.js';
|
|
22
|
+
-import { TocThumb } from '../../components/layout/toc-thumb.js';
|
|
23
|
+
import { useTOCItems } from '../../components/layout/toc.js';
|
|
24
|
+
import { mergeRefs } from '../../utils/merge-refs.js';
|
|
25
|
+
import { useI18n } from '../../contexts/i18n.js';
|
|
26
|
+
@@ -11,51 +10,9 @@ export default function ClerkTOCItems({ ref, className, ...props }) {
|
|
27
|
+
const containerRef = useRef(null);
|
|
28
|
+
const items = useTOCItems();
|
|
29
|
+
const { text } = useI18n();
|
|
30
|
+
- const [svg, setSvg] = useState();
|
|
31
|
+
- useEffect(() => {
|
|
32
|
+
- if (!containerRef.current)
|
|
33
|
+
- return;
|
|
34
|
+
- const container = containerRef.current;
|
|
35
|
+
- function onResize() {
|
|
36
|
+
- if (container.clientHeight === 0)
|
|
37
|
+
- return;
|
|
38
|
+
- let w = 0, h = 0;
|
|
39
|
+
- const d = [];
|
|
40
|
+
- for (let i = 0; i < items.length; i++) {
|
|
41
|
+
- const element = container.querySelector(`a[href="#${items[i].url.slice(1)}"]`);
|
|
42
|
+
- if (!element)
|
|
43
|
+
- continue;
|
|
44
|
+
- const styles = getComputedStyle(element);
|
|
45
|
+
- const offset = getLineOffset(items[i].depth) + 1, top = element.offsetTop + parseFloat(styles.paddingTop), bottom = element.offsetTop +
|
|
46
|
+
- element.clientHeight -
|
|
47
|
+
- parseFloat(styles.paddingBottom);
|
|
48
|
+
- w = Math.max(offset, w);
|
|
49
|
+
- h = Math.max(h, bottom);
|
|
50
|
+
- d.push(`${i === 0 ? 'M' : 'L'}${offset} ${top}`);
|
|
51
|
+
- d.push(`L${offset} ${bottom}`);
|
|
52
|
+
- }
|
|
53
|
+
- setSvg({
|
|
54
|
+
- path: d.join(' '),
|
|
55
|
+
- width: w + 1,
|
|
56
|
+
- height: h,
|
|
57
|
+
- });
|
|
58
|
+
- }
|
|
59
|
+
- const observer = new ResizeObserver(onResize);
|
|
60
|
+
- onResize();
|
|
61
|
+
- observer.observe(container);
|
|
62
|
+
- return () => {
|
|
63
|
+
- observer.disconnect();
|
|
64
|
+
- };
|
|
65
|
+
- }, [items]);
|
|
66
|
+
if (items.length === 0)
|
|
67
|
+
return (_jsx("div", { className: "rounded-lg border bg-fd-card p-3 text-xs text-fd-muted-foreground", children: text.tocNoHeadings }));
|
|
68
|
+
- return (_jsxs(_Fragment, { children: [svg ? (_jsx("div", { className: "absolute start-0 top-0 rtl:-scale-x-100", style: {
|
|
69
|
+
- width: svg.width,
|
|
70
|
+
- height: svg.height,
|
|
71
|
+
- maskImage: `url("data:image/svg+xml,${
|
|
72
|
+
- // Inline SVG
|
|
73
|
+
- encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${svg.width} ${svg.height}"><path d="${svg.path}" stroke="black" stroke-width="1" fill="none" /></svg>`)}")`,
|
|
74
|
+
- }, children: _jsx(TocThumb, { containerRef: containerRef, className: "mt-(--fd-top) h-(--fd-height) bg-fd-primary transition-all" }) })) : null, _jsx("div", { ref: mergeRefs(containerRef, ref), className: cn('flex flex-col', className), ...props, children: items.map((item, i) => (_jsx(TOCItem, { item: item, upper: items[i - 1]?.depth, lower: items[i + 1]?.depth }, item.url))) })] }));
|
|
75
|
+
+ return (_jsx("div", { ref: mergeRefs(containerRef, ref), className: cn('flex flex-col relative', className), ...props, children: items.map((item, i) => (_jsx(EnhancedClerkTOCItemInternal, { item: item, upperDepth: items[i - 1]?.depth, lowerDepth: items[i + 1]?.depth }, item.url))) }));
|
|
76
|
+
}
|
|
77
|
+
function getItemOffset(depth) {
|
|
78
|
+
if (depth <= 2)
|
|
79
|
+
@@ -67,11 +24,74 @@ function getItemOffset(depth) {
|
|
80
|
+
function getLineOffset(depth) {
|
|
81
|
+
return depth >= 3 ? 10 : 0;
|
|
82
|
+
}
|
|
83
|
+
-function TOCItem({ item, upper = item.depth, lower = item.depth, }) {
|
|
84
|
+
- const offset = getLineOffset(item.depth), upperOffset = getLineOffset(upper), lowerOffset = getLineOffset(lower);
|
|
85
|
+
+function getVisualLinePosition(depth) {
|
|
86
|
+
+ return getLineOffset(depth);
|
|
87
|
+
+}
|
|
88
|
+
+function EnhancedClerkTOCItemInternal({ item, upperDepth = item.depth, lowerDepth = item.depth, }) {
|
|
89
|
+
+ const isH3 = item.depth === 3;
|
|
90
|
+
+ const rawTitle = typeof item.title === 'string' ? item.title : '';
|
|
91
|
+
+ const { isStep, displayStep, content } = getStepInfoFromTitle(rawTitle);
|
|
92
|
+
+ let stepNumber = isH3 && isStep ? String(displayStep) : null;
|
|
93
|
+
+ let resolvedContent = item.title;
|
|
94
|
+
+ if (isH3 && isStep) {
|
|
95
|
+
+ resolvedContent = content ?? item.title;
|
|
96
|
+
+ }
|
|
97
|
+
+ if (isH3 && !stepNumber) {
|
|
98
|
+
+ const urlNum = _getDigitsFromUrl(item.url);
|
|
99
|
+
+ if (urlNum != null) {
|
|
100
|
+
+ const clamped = Math.max(0, Math.min(19, urlNum));
|
|
101
|
+
+ stepNumber = String(clamped);
|
|
102
|
+
+ if (typeof rawTitle === 'string') {
|
|
103
|
+
+ const m = rawTitle.match(/^(\d+(?:\.\d+)*\.?)\s+(.+)$/);
|
|
104
|
+
+ if (m && m[2]) {
|
|
105
|
+
+ resolvedContent = m[2];
|
|
106
|
+
+ }
|
|
107
|
+
+ }
|
|
108
|
+
+ }
|
|
109
|
+
+ }
|
|
110
|
+
+ const shouldRenderCircle = isH3 && stepNumber !== null;
|
|
111
|
+
+ const lineOffsetWithinItem = getLineOffset(item.depth);
|
|
112
|
+
+ const upperLineOffsetWithinItem = getLineOffset(upperDepth);
|
|
113
|
+
+ const lowerLineOffsetWithinItem = getLineOffset(lowerDepth);
|
|
114
|
+
+ const itemPadding = getItemOffset(item.depth);
|
|
115
|
+
+ const visualElementX = getVisualLinePosition(item.depth);
|
|
116
|
+
+ const CIRCLE_RADIUS_PX = 7;
|
|
117
|
+
return (_jsxs(Primitive.TOCItem, { href: item.url, style: {
|
|
118
|
+
- paddingInlineStart: getItemOffset(item.depth),
|
|
119
|
+
- }, className: "prose relative py-1.5 text-sm text-fd-muted-foreground hover:text-fd-accent-foreground transition-colors [overflow-wrap:anywhere] first:pt-0 last:pb-0 data-[active=true]:text-fd-primary", children: [offset !== upperOffset ? (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 16 16", className: "absolute -top-1.5 start-0 size-4 rtl:-scale-x-100", children: _jsx("line", { x1: upperOffset, y1: "0", x2: offset, y2: "12", className: "stroke-fd-foreground/10", strokeWidth: "1" }) })) : null, _jsx("div", { className: cn('absolute inset-y-0 w-px bg-fd-foreground/10', offset !== upperOffset && 'top-1.5', offset !== lowerOffset && 'bottom-1.5'), style: {
|
|
120
|
+
- insetInlineStart: offset,
|
|
121
|
+
- } }), item.title] }));
|
|
122
|
+
+ paddingInlineStart: itemPadding,
|
|
123
|
+
+ }, className: "prose group relative py-1.5 text-sm text-fd-muted-foreground hover:text-fd-accent-foreground transition-colors [overflow-wrap:anywhere] first:pt-0 last:pb-0 data-[active=true]:text-fd-primary", children: [lineOffsetWithinItem !== upperLineOffsetWithinItem ? (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 16 16", className: "absolute -top-1.5 size-4 pointer-events-none rtl:-scale-x-100", style: {
|
|
124
|
+
+ insetInlineStart: Math.min(lineOffsetWithinItem, upperLineOffsetWithinItem),
|
|
125
|
+
+ zIndex: 1,
|
|
126
|
+
+ }, children: _jsx("line", { x1: upperLineOffsetWithinItem -
|
|
127
|
+
+ Math.min(lineOffsetWithinItem, upperLineOffsetWithinItem), y1: "0", x2: lineOffsetWithinItem -
|
|
128
|
+
+ Math.min(lineOffsetWithinItem, upperLineOffsetWithinItem), y2: "12", className: cn('stroke-fd-foreground/10', 'group-data-[active=true]:stroke-fd-primary'), strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })) : null, _jsx("div", { className: cn('absolute inset-y-0 pointer-events-none transition-all duration-500 ease-in-out', 'w-[2px] bg-fd-foreground/15 group-data-[active=true]:bg-fd-primary', lineOffsetWithinItem !== upperLineOffsetWithinItem && 'top-1.5', lineOffsetWithinItem !== lowerLineOffsetWithinItem && 'bottom-1.5'), style: {
|
|
129
|
+
+ insetInlineStart: lineOffsetWithinItem,
|
|
130
|
+
+ zIndex: 1,
|
|
131
|
+
+ } }), shouldRenderCircle && stepNumber ? (_jsx("span", { className: cn('absolute z-10 flex size-[14px] -translate-y-1/2 items-center justify-center rounded-full', 'bg-black text-white dark:bg-white dark:text-black', 'group-data-[active=true]:bg-fd-primary group-data-[active=true]:text-white dark:group-data-[active=true]:text-black', 'font-medium text-xs'), style: {
|
|
132
|
+
+ left: visualElementX - CIRCLE_RADIUS_PX,
|
|
133
|
+
+ top: '50%',
|
|
134
|
+
+ }, children: stepNumber })) : null, _jsx("span", { style: { position: 'relative', zIndex: 1 }, children: resolvedContent })] }));
|
|
135
|
+
+}
|
|
136
|
+
+function _getDigitsFromUrl(url) {
|
|
137
|
+
+ const match = /^#(\d+)-/.exec(url);
|
|
138
|
+
+ if (!match)
|
|
139
|
+
+ return null;
|
|
140
|
+
+ const value = Number.parseInt(match[1], 10);
|
|
141
|
+
+ return Number.isNaN(value) ? null : value;
|
|
142
|
+
+}
|
|
143
|
+
+function getStepInfoFromTitle(title) {
|
|
144
|
+
+ const trimmed = title.trim();
|
|
145
|
+
+ const match = trimmed.match(/^(\d+(?:\.\d+)*\.?)\s+(.+)$/);
|
|
146
|
+
+ if (!match)
|
|
147
|
+
+ return { isStep: false, displayStep: null, content: null };
|
|
148
|
+
+ const content = (match[2] ?? '').trim();
|
|
149
|
+
+ if (content.length === 0)
|
|
150
|
+
+ return { isStep: false, displayStep: null, content: null };
|
|
151
|
+
+ const numericPart = match[1].replace(/\.$/, '');
|
|
152
|
+
+ const parts = numericPart.split('.').map((part) => Number.parseInt(part, 10));
|
|
153
|
+
+ const lastPart = parts.at(-1);
|
|
154
|
+
+ if (lastPart == null || Number.isNaN(lastPart)) {
|
|
155
|
+
+ return { isStep: false, displayStep: null, content: null };
|
|
156
|
+
+ }
|
|
157
|
+
+ const clamped = Math.max(0, Math.min(19, lastPart));
|
|
158
|
+
+ return { isStep: true, displayStep: clamped, content };
|
|
159
|
+
}
|