@windrun-huaiin/third-ui 20.0.0 → 21.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/LICENSE +1 -1
- package/dist/clerk/clerk-page-generator.d.ts +0 -8
- package/dist/clerk/fingerprint/fingerprint-provider.js +58 -49
- package/dist/clerk/fingerprint/fingerprint-provider.mjs +58 -49
- package/dist/fuma/fuma-page-genarator.d.ts +2 -2
- package/dist/fuma/fuma-page-genarator.js +21 -8
- package/dist/fuma/fuma-page-genarator.mjs +21 -8
- package/dist/fuma/llm-copy-handler.js +3 -2
- package/dist/fuma/llm-copy-handler.mjs +3 -2
- package/dist/fuma/mdx/index.d.ts +1 -0
- package/dist/fuma/mdx/index.js +3 -0
- package/dist/fuma/mdx/index.mjs +1 -0
- package/dist/fuma/mdx/math.d.ts +17 -0
- package/dist/fuma/mdx/math.js +60 -0
- package/dist/fuma/mdx/math.mjs +57 -0
- package/dist/fuma/mdx/zia-card.js +1 -1
- package/dist/fuma/mdx/zia-card.mjs +1 -1
- package/dist/main/{ads-alert-dialog.d.ts → alert-dialog/ads-alert-dialog.d.ts} +1 -1
- package/dist/main/alert-dialog/ads-alert-dialog.js +24 -0
- package/dist/main/alert-dialog/ads-alert-dialog.mjs +22 -0
- package/dist/main/alert-dialog/confirm-dialog.d.ts +15 -0
- package/dist/main/alert-dialog/confirm-dialog.js +40 -0
- package/dist/main/alert-dialog/confirm-dialog.mjs +38 -0
- package/dist/main/alert-dialog/dialog-styles.d.ts +14 -0
- package/dist/main/alert-dialog/dialog-styles.js +35 -0
- package/dist/main/alert-dialog/dialog-styles.mjs +20 -0
- package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +12 -0
- package/dist/main/alert-dialog/high-priority-confirm-dialog.js +23 -0
- package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +21 -0
- package/dist/main/alert-dialog/index.d.ts +4 -0
- package/dist/main/alert-dialog/info-dialog.d.ts +13 -0
- package/dist/main/alert-dialog/info-dialog.js +50 -0
- package/dist/main/alert-dialog/info-dialog.mjs +48 -0
- package/dist/main/index.d.ts +1 -1
- package/dist/main/index.js +7 -1
- package/dist/main/index.mjs +4 -1
- package/package.json +4 -4
- package/src/clerk/clerk-page-generator.tsx +0 -9
- package/src/clerk/fingerprint/fingerprint-provider.tsx +155 -62
- package/src/fuma/fuma-page-genarator.tsx +26 -9
- package/src/fuma/llm-copy-handler.ts +3 -3
- package/src/fuma/mdx/index.ts +1 -0
- package/src/fuma/mdx/math.tsx +130 -0
- package/src/fuma/mdx/zia-card.tsx +1 -0
- package/src/main/{ads-alert-dialog.tsx → alert-dialog/ads-alert-dialog.tsx} +46 -29
- package/src/main/alert-dialog/confirm-dialog.tsx +131 -0
- package/src/main/alert-dialog/dialog-styles.ts +73 -0
- package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +94 -0
- package/src/main/alert-dialog/index.ts +7 -0
- package/src/main/alert-dialog/info-dialog.tsx +139 -0
- package/src/main/index.ts +1 -1
- package/src/main/language-detector.tsx +0 -8
- package/dist/main/ads-alert-dialog.js +0 -21
- package/dist/main/ads-alert-dialog.mjs +0 -19
|
@@ -4,6 +4,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
4
4
|
import { Settings2Icon, CoinsIcon, GiftIcon, LightbulbIcon, ShieldUserIcon, XIcon, FingerprintIcon, GemIcon, DatabaseZapIcon, BellIcon, RefreshCcwIcon } from '@windrun-huaiin/base-ui/icons';
|
|
5
5
|
import { themeIconColor, themeButtonGradientClass, themeButtonGradientHoverClass } from '@windrun-huaiin/base-ui/lib';
|
|
6
6
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
7
|
+
import { useMessages } from 'next-intl';
|
|
7
8
|
import { createContext, useContext, useState, useRef, useEffect, useMemo } from 'react';
|
|
8
9
|
import { useFingerprint } from './use-fingerprint.mjs';
|
|
9
10
|
import { CopyableText } from '@windrun-huaiin/base-ui/ui';
|
|
@@ -12,6 +13,10 @@ import { getOrCreateDebugFingerprintOverride, regenerateDebugFingerprintOverride
|
|
|
12
13
|
import { FINGERPRINT_SOURCE_REFER } from './fingerprint-shared.mjs';
|
|
13
14
|
|
|
14
15
|
const FingerprintContext = createContext(undefined);
|
|
16
|
+
function useFingerprintStatusTranslations() {
|
|
17
|
+
const messages = useMessages();
|
|
18
|
+
return messages.fingerprint;
|
|
19
|
+
}
|
|
15
20
|
/**
|
|
16
21
|
* Fingerprint Provider Component
|
|
17
22
|
* 为应用提供fingerprint和匿名用户管理功能
|
|
@@ -51,6 +56,7 @@ function withFingerprint(Component, config) {
|
|
|
51
56
|
* 组件:显示用户状态和积分信息(用于调试)
|
|
52
57
|
*/
|
|
53
58
|
function FingerprintStatus() {
|
|
59
|
+
const translations = useFingerprintStatusTranslations();
|
|
54
60
|
const { fingerprintId, xUser, xCredit, xSubscription, error, clearError, } = useFingerprintContext();
|
|
55
61
|
const [isOpen, setIsOpen] = useState(false);
|
|
56
62
|
const [panelMode, setPanelMode] = useState('info');
|
|
@@ -90,7 +96,7 @@ function FingerprintStatus() {
|
|
|
90
96
|
return [
|
|
91
97
|
{
|
|
92
98
|
key: 'paid',
|
|
93
|
-
label:
|
|
99
|
+
label: translations.creditBuckets.paid,
|
|
94
100
|
icon: jsx(Settings2Icon, { className: "size-4 text-green-500 dark:text-green-300" }),
|
|
95
101
|
balance: xCredit.balancePaid,
|
|
96
102
|
total: xCredit.totalPaidLimit,
|
|
@@ -99,7 +105,7 @@ function FingerprintStatus() {
|
|
|
99
105
|
},
|
|
100
106
|
{
|
|
101
107
|
key: 'oneTimePaid',
|
|
102
|
-
label:
|
|
108
|
+
label: translations.creditBuckets.oneTimePaid,
|
|
103
109
|
icon: jsx(CoinsIcon, { className: "size-4 text-amber-500 dark:text-amber-300" }),
|
|
104
110
|
balance: xCredit.balanceOneTimePaid,
|
|
105
111
|
total: xCredit.totalOneTimePaidLimit,
|
|
@@ -108,7 +114,7 @@ function FingerprintStatus() {
|
|
|
108
114
|
},
|
|
109
115
|
{
|
|
110
116
|
key: 'free',
|
|
111
|
-
label:
|
|
117
|
+
label: translations.creditBuckets.free,
|
|
112
118
|
icon: jsx(GiftIcon, { className: "size-4 text-purple-500 dark:text-purple-300" }),
|
|
113
119
|
balance: xCredit.balanceFree,
|
|
114
120
|
total: xCredit.totalFreeLimit,
|
|
@@ -116,15 +122,15 @@ function FingerprintStatus() {
|
|
|
116
122
|
end: xCredit.freeEnd,
|
|
117
123
|
},
|
|
118
124
|
];
|
|
119
|
-
}, [xCredit]);
|
|
125
|
+
}, [translations.creditBuckets.free, translations.creditBuckets.oneTimePaid, translations.creditBuckets.paid, xCredit]);
|
|
120
126
|
const subscriptionStatus = useMemo(() => {
|
|
121
127
|
var _a, _b;
|
|
122
128
|
if (!xSubscription) {
|
|
123
129
|
return {
|
|
124
|
-
status:
|
|
130
|
+
status: translations.placeholders.subscriptionStatusNever,
|
|
125
131
|
priceName: '--',
|
|
126
132
|
creditsAllocated: '--',
|
|
127
|
-
period:
|
|
133
|
+
period: translations.placeholders.subscriptionPeriodUnavailable,
|
|
128
134
|
};
|
|
129
135
|
}
|
|
130
136
|
return {
|
|
@@ -133,9 +139,9 @@ function FingerprintStatus() {
|
|
|
133
139
|
creditsAllocated: typeof xSubscription.creditsAllocated === 'number'
|
|
134
140
|
? formatNumber(xSubscription.creditsAllocated)
|
|
135
141
|
: '--',
|
|
136
|
-
period: formatRangeText(xSubscription.subPeriodStart, xSubscription.subPeriodEnd),
|
|
142
|
+
period: formatRangeText(xSubscription.subPeriodStart, xSubscription.subPeriodEnd, translations),
|
|
137
143
|
};
|
|
138
|
-
}, [xSubscription]);
|
|
144
|
+
}, [translations.placeholders.subscriptionPeriodUnavailable, translations.placeholders.subscriptionStatusNever, xSubscription]);
|
|
139
145
|
const userStatus = (xUser === null || xUser === void 0 ? void 0 : xUser.status) || '--';
|
|
140
146
|
const totalCredits = formatNumber(xCredit === null || xCredit === void 0 ? void 0 : xCredit.totalBalance);
|
|
141
147
|
const subStatus = subscriptionStatus.status;
|
|
@@ -143,22 +149,22 @@ function FingerprintStatus() {
|
|
|
143
149
|
const runContextParallelInitTest = () => __awaiter(this, void 0, void 0, function* () {
|
|
144
150
|
const debugFingerprintId = activeDebugFingerprintId !== null && activeDebugFingerprintId !== void 0 ? activeDebugFingerprintId : getOrCreateDebugFingerprintOverride();
|
|
145
151
|
if (!debugFingerprintId) {
|
|
146
|
-
setTestResult(
|
|
152
|
+
setTestResult(translations.messages.testFingerprintNotReady);
|
|
147
153
|
return;
|
|
148
154
|
}
|
|
149
155
|
setActiveDebugFingerprintId(debugFingerprintId);
|
|
150
156
|
setIsRunningTest(true);
|
|
151
|
-
setTestResult(
|
|
157
|
+
setTestResult(tpl(translations.messages.runningFrontendPreventionTest, { fingerprintId: debugFingerprintId }));
|
|
152
158
|
try {
|
|
153
159
|
yield Promise.all([
|
|
154
160
|
initializeDebugAnonymousUser(debugFingerprintId),
|
|
155
161
|
initializeDebugAnonymousUser(debugFingerprintId),
|
|
156
162
|
initializeDebugAnonymousUser(debugFingerprintId),
|
|
157
163
|
]);
|
|
158
|
-
setTestResult(
|
|
164
|
+
setTestResult(tpl(translations.messages.frontendPreventionTestFinished, { fingerprintId: debugFingerprintId }));
|
|
159
165
|
}
|
|
160
166
|
catch (testError) {
|
|
161
|
-
setTestResult(
|
|
167
|
+
setTestResult(tpl(translations.messages.frontendPreventionTestFailed, { error: formatErrorMessage(testError, translations) }));
|
|
162
168
|
}
|
|
163
169
|
finally {
|
|
164
170
|
setIsRunningTest(false);
|
|
@@ -178,7 +184,7 @@ function FingerprintStatus() {
|
|
|
178
184
|
});
|
|
179
185
|
if (!response.ok) {
|
|
180
186
|
const errorData = yield response.json().catch(() => ({}));
|
|
181
|
-
throw new Error(errorData.error ||
|
|
187
|
+
throw new Error(errorData.error || translations.messages.failedToInitializeAnonymousUser);
|
|
182
188
|
}
|
|
183
189
|
yield response.json().catch(() => ({}));
|
|
184
190
|
}
|
|
@@ -189,12 +195,12 @@ function FingerprintStatus() {
|
|
|
189
195
|
const runRawParallelPostTest = () => __awaiter(this, void 0, void 0, function* () {
|
|
190
196
|
const normalizedFingerprintId = activeDebugFingerprintId !== null && activeDebugFingerprintId !== void 0 ? activeDebugFingerprintId : getOrCreateDebugFingerprintOverride();
|
|
191
197
|
if (!normalizedFingerprintId) {
|
|
192
|
-
setTestResult(
|
|
198
|
+
setTestResult(translations.messages.testFingerprintNotReady);
|
|
193
199
|
return;
|
|
194
200
|
}
|
|
195
201
|
setActiveDebugFingerprintId(normalizedFingerprintId);
|
|
196
202
|
setIsRunningTest(true);
|
|
197
|
-
setTestResult(
|
|
203
|
+
setTestResult(tpl(translations.messages.runningBackendIdempotencyTest, { fingerprintId: normalizedFingerprintId }));
|
|
198
204
|
try {
|
|
199
205
|
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
200
206
|
const requests = Array.from({ length: 3 }, () => fetch('/api/user/anonymous/init', {
|
|
@@ -225,16 +231,16 @@ function FingerprintStatus() {
|
|
|
225
231
|
.filter((payload) => !payload.ok)
|
|
226
232
|
.map((payload) => `${payload.status}${payload.error ? `:${payload.error}` : ''}`);
|
|
227
233
|
setTestResult([
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
failedStatuses.length > 0 ?
|
|
234
|
+
translations.messages.backendIdempotencyTestDone,
|
|
235
|
+
tpl(translations.messages.createdCount, { count: createdUserIds.length }),
|
|
236
|
+
tpl(translations.messages.reusedCount, { count: reusedUserIds.length }),
|
|
237
|
+
tpl(translations.messages.failedCount, { count: failedStatuses.length }),
|
|
238
|
+
tpl(translations.messages.createdUserIds, { value: createdUserIds.join(', ') }),
|
|
239
|
+
failedStatuses.length > 0 ? tpl(translations.messages.failedStatuses, { value: failedStatuses.join(', ') }) : null,
|
|
234
240
|
].filter(Boolean).join('\n'));
|
|
235
241
|
}
|
|
236
242
|
catch (testError) {
|
|
237
|
-
setTestResult(
|
|
243
|
+
setTestResult(tpl(translations.messages.backendIdempotencyTestFailed, { error: formatErrorMessage(testError, translations) }));
|
|
238
244
|
}
|
|
239
245
|
finally {
|
|
240
246
|
setIsRunningTest(false);
|
|
@@ -243,31 +249,31 @@ function FingerprintStatus() {
|
|
|
243
249
|
const regenerateTestFingerprint = () => {
|
|
244
250
|
const nextFingerprintId = regenerateDebugFingerprintOverride();
|
|
245
251
|
setActiveDebugFingerprintId(nextFingerprintId);
|
|
246
|
-
setTestResult(
|
|
252
|
+
setTestResult(tpl(translations.messages.generatedTestFingerprintOverride, { fingerprintId: nextFingerprintId }));
|
|
247
253
|
};
|
|
248
|
-
return (jsxs(Fragment, { children: [!isOpen && (jsx("button", { onClick: handleToggle, type: "button", "aria-label":
|
|
254
|
+
return (jsxs(Fragment, { children: [!isOpen && (jsx("button", { onClick: handleToggle, type: "button", "aria-label": translations.panel.toggleAriaLabel, className: cn('fixed left-2 top-2 md:left-2 md:top-3 z-10000 inline-flex size-8 md:size-11 items-center justify-center rounded-full', themeButtonGradientClass, themeButtonGradientHoverClass, 'text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-300'), children: jsx(LightbulbIcon, { className: "size-6 text-white" }) })), isOpen && (jsxs(Fragment, { children: [jsx("div", { onClick: handleBackdropClick, className: "fixed inset-0 z-9998 bg-black/60 backdrop-blur-sm" }), jsxs("div", { ref: modalRef, className: cn('fixed inset-3 z-9999 mx-auto w-[min(95vw,520px)] overflow-y-auto rounded-2xl border', 'border-slate-200/70 bg-white/95 p-4 shadow-2xl backdrop-blur-sm', 'font-sans text-sm text-slate-700 dark:border-white/12 dark:bg-slate-950/95 dark:text-slate-200', 'sm:inset-auto md:left-2 sm:top-1 md:right-auto sm:w-[min(520px,95vw)] sm:p-5'), children: [jsx("header", { className: "mb-4", children: jsxs("div", { className: "flex items-start justify-between gap-3", children: [jsxs("div", { className: cn("flex items-center gap-2 text-base font-bold tracking-wider", themeIconColor), children: [jsx(ShieldUserIcon, { className: "size-4" }), translations.panel.title] }), jsxs("div", { className: "flex items-center gap-2", children: [jsxs("button", { type: "button", onClick: () => setPanelMode((prev) => prev === 'info' ? 'test' : 'info'), className: cn('inline-flex items-center gap-2 rounded-full border px-2 py-1 text-[11px] font-semibold shadow-sm transition-all duration-200', panelMode === 'test'
|
|
249
255
|
? cn('border-transparent text-white', themeButtonGradientClass, themeButtonGradientHoverClass)
|
|
250
|
-
: themedGhostButtonClass), "aria-pressed": panelMode === 'test', children: [jsx("span", { children:
|
|
256
|
+
: themedGhostButtonClass), "aria-pressed": panelMode === 'test', children: [jsx("span", { children: translations.panel.testModeLabel }), jsx("span", { className: cn('relative inline-flex h-5 w-9 items-center rounded-full transition-colors', panelMode === 'test'
|
|
251
257
|
? 'bg-white/25'
|
|
252
|
-
: 'bg-slate-300 dark:bg-slate-700'), children: jsx("span", { className: cn('inline-block size-4 rounded-full shadow-sm transition-transform', panelMode === 'test' ? 'bg-white' : 'bg-white dark:bg-slate-100', panelMode === 'test' ? 'translate-x-4' : 'translate-x-0.5') }) })] }), jsx("button", { type: "button", "aria-label":
|
|
253
|
-
{ label:
|
|
254
|
-
{ label:
|
|
255
|
-
{ label:
|
|
256
|
-
{ label:
|
|
257
|
-
{ label:
|
|
258
|
-
{ label:
|
|
259
|
-
{ label:
|
|
260
|
-
] }), jsxs("div", { className: "space-y-2 rounded-xl border border-slate-200/70 bg-white/80 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/50", children: [jsx(PanelHeader, { icon: jsx(GemIcon, { className: "size-4" }), title:
|
|
258
|
+
: 'bg-slate-300 dark:bg-slate-700'), children: jsx("span", { className: cn('inline-block size-4 rounded-full shadow-sm transition-transform', panelMode === 'test' ? 'bg-white' : 'bg-white dark:bg-slate-100', panelMode === 'test' ? 'translate-x-4' : 'translate-x-0.5') }) })] }), jsx("button", { type: "button", "aria-label": translations.panel.closeAriaLabel, className: "rounded-full p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-700 dark:text-slate-300 dark:hover:bg-white/10 dark:hover:text-white", onClick: () => setIsOpen(false), children: jsx(XIcon, { className: "size-4" }) })] })] }) }), jsxs("section", { className: "space-y-1", children: [panelMode === 'info' ? (jsxs(Fragment, { children: [jsx(PanelSection, { icon: jsx(FingerprintIcon, { className: "size-4" }), title: translations.sections.user, rightInfo: jsx(StatusTag, { value: userStatus, translations: translations }), items: [
|
|
259
|
+
{ label: translations.labels.userId, value: jsx(CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.userId) || '' }) },
|
|
260
|
+
{ label: translations.labels.nickName, value: jsx(CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.userName) || '' }) },
|
|
261
|
+
{ label: translations.labels.fingerprintId, value: jsx(CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.fingerprintId) || fingerprintId || '' }) },
|
|
262
|
+
{ label: translations.labels.clerkUserId, value: jsx(CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.clerkUserId) || '' }) },
|
|
263
|
+
{ label: translations.labels.email, value: jsx(CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.email) || '' }) },
|
|
264
|
+
{ label: translations.labels.stripeCusId, value: jsx(CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.stripeCusId) || '' }) },
|
|
265
|
+
{ label: translations.labels.createdAt, value: (xUser === null || xUser === void 0 ? void 0 : xUser.createdAt) || '--' },
|
|
266
|
+
] }), jsxs("div", { className: "space-y-2 rounded-xl border border-slate-200/70 bg-white/80 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/50", children: [jsx(PanelHeader, { icon: jsx(GemIcon, { className: "size-4" }), title: translations.sections.creditsInfo, rightInfo: jsx("span", { className: cn("font-semibold", themeIconColor), children: totalCredits }) }), jsx("div", { className: "space-y-3", children: creditBuckets.length > 0 ? (creditBuckets.map((bucket) => {
|
|
261
267
|
const percent = Math.round(computeProgress(bucket.balance, bucket.total) * 100);
|
|
262
|
-
return (jsxs("div", { className: "rounded-lg border border-slate-200/70 bg-white/70 p-3 dark:border-white/10 dark:bg-slate-900/40", children: [jsxs("div", { className: "flex items-center justify-between text-xs font-medium text-slate-600 dark:text-slate-300", children: [jsxs("div", { className: "flex items-center gap-1.5", children: [bucket.icon, jsx("span", { children: bucket.label })] }), jsxs("span", { className: "font-semibold text-slate-700 dark:text-slate-100", children: [formatNumber(bucket.balance), " / ", formatNumber(bucket.total)] })] }), jsx("div", { className: "mt-2 h-1.5 w-full rounded-full bg-slate-200 dark:bg-slate-800", children: jsx("div", { className: "h-full rounded-full bg-linear-to-r from-purple-500 via-pink-500 to-rose-400 transition-[width]", style: { width: `${percent}%` } }) }), jsxs("div", { className: "mt-2 flex items-center justify-between text-[11px] text-slate-500 dark:text-slate-400", children: [jsx("span", { children: formatRangeText(bucket.start, bucket.end) }), jsxs("span", { children: [percent, "%"] })] })] }, bucket.key));
|
|
263
|
-
})) : (jsx(EmptyPlaceholder, { label:
|
|
264
|
-
{ label:
|
|
265
|
-
{ label:
|
|
266
|
-
{ label:
|
|
267
|
-
{ label:
|
|
268
|
-
{ label:
|
|
269
|
-
{ label:
|
|
270
|
-
] })] })) : (jsxs("div", { className: "space-y-3 rounded-xl border border-slate-200/70 bg-white/85 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/45", children: [jsx(PanelHeader, { icon: jsx(DatabaseZapIcon, { className: "size-4" }), title:
|
|
268
|
+
return (jsxs("div", { className: "rounded-lg border border-slate-200/70 bg-white/70 p-3 dark:border-white/10 dark:bg-slate-900/40", children: [jsxs("div", { className: "flex items-center justify-between text-xs font-medium text-slate-600 dark:text-slate-300", children: [jsxs("div", { className: "flex items-center gap-1.5", children: [bucket.icon, jsx("span", { children: bucket.label })] }), jsxs("span", { className: "font-semibold text-slate-700 dark:text-slate-100", children: [formatNumber(bucket.balance), " / ", formatNumber(bucket.total)] })] }), jsx("div", { className: "mt-2 h-1.5 w-full rounded-full bg-slate-200 dark:bg-slate-800", children: jsx("div", { className: "h-full rounded-full bg-linear-to-r from-purple-500 via-pink-500 to-rose-400 transition-[width]", style: { width: `${percent}%` } }) }), jsxs("div", { className: "mt-2 flex items-center justify-between text-[11px] text-slate-500 dark:text-slate-400", children: [jsx("span", { children: formatRangeText(bucket.start, bucket.end, translations) }), jsxs("span", { children: [percent, "%"] })] })] }, bucket.key));
|
|
269
|
+
})) : (jsx(EmptyPlaceholder, { label: translations.placeholders.noCreditsYet, icon: jsx(DatabaseZapIcon, { className: "size-4" }) })) })] }), jsx(PanelSection, { icon: jsx(BellIcon, { className: "size-4" }), title: translations.sections.subscription, rightInfo: jsx(StatusTag, { value: subStatus, translations: translations }), items: [
|
|
270
|
+
{ label: translations.labels.plan, value: subscriptionStatus.priceName },
|
|
271
|
+
{ label: translations.labels.period, value: subscriptionStatus.period },
|
|
272
|
+
{ label: translations.labels.allocated, value: subscriptionStatus.creditsAllocated },
|
|
273
|
+
{ label: translations.labels.subId, value: jsx(CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.paySubscriptionId) || '' }) },
|
|
274
|
+
{ label: translations.labels.orderId, value: jsx(CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.orderId) || '' }) },
|
|
275
|
+
{ label: translations.labels.priceId, value: jsx(CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.priceId) || '' }) },
|
|
276
|
+
] })] })) : (jsxs("div", { className: "space-y-3 rounded-xl border border-slate-200/70 bg-white/85 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/45", children: [jsx(PanelHeader, { icon: jsx(DatabaseZapIcon, { className: "size-4" }), title: translations.sections.concurrentBaseInfo, rightInfo: jsx(StatusTag, { value: isRunningTest ? translations.status.pending : translations.status.idle, translations: translations }) }), jsxs("div", { className: "space-y-2 text-xs text-slate-500 dark:text-slate-300", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsx("span", { className: "text-slate-400 dark:text-slate-500", children: translations.labels.realBrowser }), jsx(CopyableText, { text: fingerprintId || '' })] }), jsxs("div", { className: "space-y-1", children: [jsx("span", { className: "text-slate-400 dark:text-slate-500", children: translations.labels.testOverride }), jsxs("div", { className: "flex items-center gap-2 py-1", children: [jsx("div", { className: "min-w-0 flex-1 rounded-lg border border-slate-200 bg-white px-3 py-2 font-mono text-[0.5rem] sm:text-[0.625rem] md:text-xs leading-tight text-slate-700 dark:border-white/10 dark:bg-slate-950 dark:text-slate-100", children: jsx(CopyableText, { text: activeDebugFingerprintId || '' }) }), jsx("button", { type: "button", disabled: isRunningTest, onClick: regenerateTestFingerprint, "aria-label": translations.actions.generateNewTestFingerprintAriaLabel, className: "inline-flex size-9 items-center justify-center rounded-lg border border-slate-200 bg-slate-50 text-slate-700 transition hover:border-slate-300 hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-white/10 dark:bg-slate-950 dark:text-slate-100 dark:hover:bg-slate-900", children: jsx(RefreshCcwIcon, { className: "size-4" }) })] })] })] }), jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: [jsx("button", { type: "button", disabled: isRunningTest, onClick: runContextParallelInitTest, className: cn('shrink-0 rounded-full border px-3 py-2 text-xs font-semibold transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-50', themedGhostButtonClass), children: translations.actions.frontendPreventionTest }), jsx("button", { type: "button", disabled: isRunningTest, onClick: runRawParallelPostTest, className: cn('shrink-0 rounded-full border px-3 py-2 text-xs font-semibold text-white shadow-sm transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-50', 'border-transparent', themeButtonGradientClass, themeButtonGradientHoverClass), children: translations.actions.backendIdempotencyTest })] }), jsx("div", { className: "rounded-lg border border-dashed border-slate-200 bg-slate-50/80 p-3 dark:border-white/10 dark:bg-slate-950/50", children: jsx("pre", { className: "overflow-x-auto whitespace-pre-wrap break-all font-mono text-[11px] leading-5 text-slate-600 dark:text-slate-300", children: testResult || translations.placeholders.noTestExecutedYet }) })] })), error && (jsxs("div", { className: "flex items-start justify-between gap-3 rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs text-amber-600 shadow-sm dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-200", children: [jsxs("div", { className: "flex items-start gap-2", children: [jsx(XIcon, { className: "mt-0.5 size-4 shrink-0" }), jsx("span", { children: error })] }), jsx("button", { type: "button", "aria-label": translations.actions.dismissErrorAriaLabel, onClick: clearError, className: "shrink-0 rounded-full p-1 text-amber-500 transition hover:bg-amber-100 hover:text-amber-700 dark:text-amber-200 dark:hover:bg-amber-500/10 dark:hover:text-amber-100", children: jsx(XIcon, { className: "size-4" }) })] }))] })] })] }))] }));
|
|
271
277
|
}
|
|
272
278
|
/* ==================== 新增辅助组件 ==================== */
|
|
273
279
|
// 标题行:左侧图标+标题,右侧信息(右对齐)
|
|
@@ -294,11 +300,11 @@ function computeProgress(balance, total) {
|
|
|
294
300
|
return 0;
|
|
295
301
|
return Math.min(Math.max(ratio, 0), 1);
|
|
296
302
|
}
|
|
297
|
-
function formatRangeText(start, end) {
|
|
303
|
+
function formatRangeText(start, end, translations) {
|
|
298
304
|
const safeStart = start && start.trim() ? start : '';
|
|
299
305
|
const safeEnd = end && end.trim() ? end : '';
|
|
300
306
|
if (!safeStart && !safeEnd) {
|
|
301
|
-
return
|
|
307
|
+
return translations.placeholders.noRecords;
|
|
302
308
|
}
|
|
303
309
|
if (!safeStart) {
|
|
304
310
|
return safeEnd;
|
|
@@ -308,9 +314,9 @@ function formatRangeText(start, end) {
|
|
|
308
314
|
}
|
|
309
315
|
return `${safeStart} - ${safeEnd}`;
|
|
310
316
|
}
|
|
311
|
-
function StatusTag({ value }) {
|
|
317
|
+
function StatusTag({ value, translations, }) {
|
|
312
318
|
if (!value)
|
|
313
|
-
return jsx("span", { className: "text-slate-400", children:
|
|
319
|
+
return jsx("span", { className: "text-slate-400", children: translations.placeholders.none });
|
|
314
320
|
const normalized = value.toLowerCase();
|
|
315
321
|
const colorMap = {
|
|
316
322
|
// 绿色:正常/活跃
|
|
@@ -333,14 +339,17 @@ function StatusTag({ value }) {
|
|
|
333
339
|
const badgeClass = colorMap[normalized] || defaultColor;
|
|
334
340
|
return (jsx("span", { className: cn('inline-block rounded-full px-2 py-0.5 text-xs capitalize font-medium', badgeClass), children: value }));
|
|
335
341
|
}
|
|
336
|
-
function formatErrorMessage(error) {
|
|
342
|
+
function formatErrorMessage(error, translations) {
|
|
337
343
|
if (error instanceof Error) {
|
|
338
344
|
return error.message;
|
|
339
345
|
}
|
|
340
346
|
if (typeof error === 'string') {
|
|
341
347
|
return error;
|
|
342
348
|
}
|
|
343
|
-
return
|
|
349
|
+
return translations.placeholders.unknownError;
|
|
350
|
+
}
|
|
351
|
+
function tpl(template, values) {
|
|
352
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => { var _a; return String((_a = values[key]) !== null && _a !== void 0 ? _a : ''); });
|
|
344
353
|
}
|
|
345
354
|
|
|
346
355
|
export { FingerprintProvider, FingerprintStatus, useFingerprintContext, useFingerprintContextSafe, withFingerprint };
|
|
@@ -2,7 +2,7 @@ import { ReactNode, ReactElement } from 'react';
|
|
|
2
2
|
import type { LLMCopyButtonProps, LLMCopyButton } from '@third-ui/fuma/mdx/toc-base';
|
|
3
3
|
interface FumaPageParams {
|
|
4
4
|
sourceKey: string;
|
|
5
|
-
mdxContentSource: any;
|
|
5
|
+
mdxContentSource: any | (() => Promise<any>);
|
|
6
6
|
getMDXComponents: () => any;
|
|
7
7
|
mdxSourceDir: string;
|
|
8
8
|
githubBaseUrl?: string;
|
|
@@ -25,7 +25,7 @@ export declare function createFumaPage({ sourceKey, mdxContentSource, getMDXComp
|
|
|
25
25
|
slug?: string[];
|
|
26
26
|
}>;
|
|
27
27
|
}) => Promise<import("react/jsx-runtime").JSX.Element>;
|
|
28
|
-
generateStaticParams: () => any
|
|
28
|
+
generateStaticParams: () => Promise<any>;
|
|
29
29
|
generateMetadata: (props: {
|
|
30
30
|
params: Promise<{
|
|
31
31
|
slug?: string[];
|
|
@@ -9,36 +9,49 @@ var lib = require('@windrun-huaiin/lib');
|
|
|
9
9
|
var tocClerkPortable = require('./mdx/toc-clerk-portable.js');
|
|
10
10
|
|
|
11
11
|
function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
12
|
+
const getSource = () => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
13
|
+
if (typeof mdxContentSource === 'function') {
|
|
14
|
+
return yield mdxContentSource();
|
|
15
|
+
}
|
|
16
|
+
return mdxContentSource;
|
|
17
|
+
});
|
|
12
18
|
const Page = function Page(_a) {
|
|
13
19
|
return tslib.__awaiter(this, arguments, void 0, function* ({ params }) {
|
|
14
|
-
var _b, _c, _d;
|
|
20
|
+
var _b, _c, _d, _e;
|
|
15
21
|
const { slug, locale } = yield params;
|
|
16
|
-
const
|
|
22
|
+
const source = yield getSource();
|
|
23
|
+
const page$1 = source.getPage(slug, locale);
|
|
17
24
|
if (!page$1) {
|
|
18
|
-
console.log('[FumaPage] missing page', { slug, locale, available: (_d = (_c = (_b =
|
|
25
|
+
console.log('[FumaPage] missing page', { slug, locale, available: (_d = (_c = (_b = source.pageTree) === null || _b === void 0 ? void 0 : _b[locale]) === null || _c === void 0 ? void 0 : _c.children) === null || _d === void 0 ? void 0 : _d.map((c) => c.url) });
|
|
19
26
|
return jsxRuntime.jsx(FallbackPage, { siteIcon: siteIcon });
|
|
20
27
|
}
|
|
21
28
|
const path = githubBaseUrl ? `${mdxSourceDir}/${page$1.path}` : undefined;
|
|
22
29
|
const tocFooterElement = (jsxRuntime.jsx(tocFooterWrapper.TocFooterWrapper, { lastModified: page$1.data.date, copyButtonComponent: copyButtonComponent
|
|
23
30
|
? React.cloneElement(copyButtonComponent, { sourceKey })
|
|
24
31
|
: undefined, editPath: path, githubBaseUrl: githubBaseUrl }));
|
|
25
|
-
const
|
|
32
|
+
const content = typeof page$1.data.load === 'function'
|
|
33
|
+
? yield page$1.data.load(getMDXComponents())
|
|
34
|
+
: {
|
|
35
|
+
body: yield page$1.data.body({ components: getMDXComponents() }),
|
|
36
|
+
toc: (_e = page$1.data.toc) !== null && _e !== void 0 ? _e : [],
|
|
37
|
+
};
|
|
26
38
|
return (jsxRuntime.jsxs(page.DocsPage, { breadcrumb: { enabled: showBreadcrumb }, tableOfContent: {
|
|
27
39
|
enabled: showTableOfContent,
|
|
28
40
|
single: false,
|
|
29
|
-
component: (jsxRuntime.jsx(tocClerkPortable.PortableClerkTOC, { toc:
|
|
41
|
+
component: (jsxRuntime.jsx(tocClerkPortable.PortableClerkTOC, { toc: content.toc, footer: tocFooterElement })),
|
|
30
42
|
}, tableOfContentPopover: {
|
|
31
43
|
enabled: false,
|
|
32
|
-
}, toc:
|
|
44
|
+
}, toc: content.toc, article: { className: 'max-sm:pb-16' }, children: [jsxRuntime.jsx(page.DocsTitle, { children: page$1.data.title }), jsxRuntime.jsx(page.DocsDescription, { className: "mb-2", children: page$1.data.description }), jsxRuntime.jsx(page.DocsBody, { className: "text-fd-foreground/80", children: content.body })] }));
|
|
33
45
|
});
|
|
34
46
|
};
|
|
35
47
|
function generateStaticParams() {
|
|
36
|
-
return
|
|
48
|
+
return getSource().then((source) => source.generateParams('slug', 'locale'));
|
|
37
49
|
}
|
|
38
50
|
function generateMetadata(props) {
|
|
39
51
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
40
52
|
const { slug, locale } = yield props.params;
|
|
41
|
-
const
|
|
53
|
+
const source = yield getSource();
|
|
54
|
+
const page = source.getPage(slug, locale);
|
|
42
55
|
if (!page) {
|
|
43
56
|
return {
|
|
44
57
|
title: '404 - Page Not Found',
|
|
@@ -7,36 +7,49 @@ import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
|
|
|
7
7
|
import { PortableClerkTOC } from './mdx/toc-clerk-portable.mjs';
|
|
8
8
|
|
|
9
9
|
function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
10
|
+
const getSource = () => __awaiter(this, void 0, void 0, function* () {
|
|
11
|
+
if (typeof mdxContentSource === 'function') {
|
|
12
|
+
return yield mdxContentSource();
|
|
13
|
+
}
|
|
14
|
+
return mdxContentSource;
|
|
15
|
+
});
|
|
10
16
|
const Page = function Page(_a) {
|
|
11
17
|
return __awaiter(this, arguments, void 0, function* ({ params }) {
|
|
12
|
-
var _b, _c, _d;
|
|
18
|
+
var _b, _c, _d, _e;
|
|
13
19
|
const { slug, locale } = yield params;
|
|
14
|
-
const
|
|
20
|
+
const source = yield getSource();
|
|
21
|
+
const page = source.getPage(slug, locale);
|
|
15
22
|
if (!page) {
|
|
16
|
-
console.log('[FumaPage] missing page', { slug, locale, available: (_d = (_c = (_b =
|
|
23
|
+
console.log('[FumaPage] missing page', { slug, locale, available: (_d = (_c = (_b = source.pageTree) === null || _b === void 0 ? void 0 : _b[locale]) === null || _c === void 0 ? void 0 : _c.children) === null || _d === void 0 ? void 0 : _d.map((c) => c.url) });
|
|
17
24
|
return jsx(FallbackPage, { siteIcon: siteIcon });
|
|
18
25
|
}
|
|
19
26
|
const path = githubBaseUrl ? `${mdxSourceDir}/${page.path}` : undefined;
|
|
20
27
|
const tocFooterElement = (jsx(TocFooterWrapper, { lastModified: page.data.date, copyButtonComponent: copyButtonComponent
|
|
21
28
|
? cloneElement(copyButtonComponent, { sourceKey })
|
|
22
29
|
: undefined, editPath: path, githubBaseUrl: githubBaseUrl }));
|
|
23
|
-
const
|
|
30
|
+
const content = typeof page.data.load === 'function'
|
|
31
|
+
? yield page.data.load(getMDXComponents())
|
|
32
|
+
: {
|
|
33
|
+
body: yield page.data.body({ components: getMDXComponents() }),
|
|
34
|
+
toc: (_e = page.data.toc) !== null && _e !== void 0 ? _e : [],
|
|
35
|
+
};
|
|
24
36
|
return (jsxs(DocsPage, { breadcrumb: { enabled: showBreadcrumb }, tableOfContent: {
|
|
25
37
|
enabled: showTableOfContent,
|
|
26
38
|
single: false,
|
|
27
|
-
component: (jsx(PortableClerkTOC, { toc:
|
|
39
|
+
component: (jsx(PortableClerkTOC, { toc: content.toc, footer: tocFooterElement })),
|
|
28
40
|
}, tableOfContentPopover: {
|
|
29
41
|
enabled: false,
|
|
30
|
-
}, toc:
|
|
42
|
+
}, toc: content.toc, article: { className: 'max-sm:pb-16' }, children: [jsx(DocsTitle, { children: page.data.title }), jsx(DocsDescription, { className: "mb-2", children: page.data.description }), jsx(DocsBody, { className: "text-fd-foreground/80", children: content.body })] }));
|
|
31
43
|
});
|
|
32
44
|
};
|
|
33
45
|
function generateStaticParams() {
|
|
34
|
-
return
|
|
46
|
+
return getSource().then((source) => source.generateParams('slug', 'locale'));
|
|
35
47
|
}
|
|
36
48
|
function generateMetadata(props) {
|
|
37
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
50
|
const { slug, locale } = yield props.params;
|
|
39
|
-
const
|
|
51
|
+
const source = yield getSource();
|
|
52
|
+
const page = source.getPage(slug, locale);
|
|
40
53
|
if (!page) {
|
|
41
54
|
return {
|
|
42
55
|
title: '404 - Page Not Found',
|
|
@@ -11,6 +11,7 @@ var llmUtils = require('@windrun-huaiin/lib/llm-utils');
|
|
|
11
11
|
*/
|
|
12
12
|
function LLMCopyHandler(options) {
|
|
13
13
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
14
|
+
var _a, _b, _c, _d;
|
|
14
15
|
const { sourceDir, dataSource, requestedPath, locale } = options;
|
|
15
16
|
// log received parameters
|
|
16
17
|
console.log(`[LLMCopy] Received, locale=${locale}, path=${requestedPath}`);
|
|
@@ -28,8 +29,8 @@ function LLMCopyHandler(options) {
|
|
|
28
29
|
console.error(`[LLMCopy] file path information missing in page data for locale=${locale}, path=${requestedPath}`);
|
|
29
30
|
return { error: 'Page file path information missing', status: 500 };
|
|
30
31
|
}
|
|
31
|
-
const title = page.title;
|
|
32
|
-
const description = page.description;
|
|
32
|
+
const title = (_b = (_a = page.data) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : page.title;
|
|
33
|
+
const description = (_d = (_c = page.data) === null || _c === void 0 ? void 0 : _c.description) !== null && _d !== void 0 ? _d : page.description;
|
|
33
34
|
const relativeMdxFilePath = page.path;
|
|
34
35
|
const absoluteFilePath = nodePath.join(process.cwd(), sourceDir, relativeMdxFilePath);
|
|
35
36
|
console.log(`[LLMCopy] Attempting to read MDX content from: ${absoluteFilePath}`);
|
|
@@ -9,6 +9,7 @@ import { getLLMText } from '@windrun-huaiin/lib/llm-utils';
|
|
|
9
9
|
*/
|
|
10
10
|
function LLMCopyHandler(options) {
|
|
11
11
|
return __awaiter(this, void 0, void 0, function* () {
|
|
12
|
+
var _a, _b, _c, _d;
|
|
12
13
|
const { sourceDir, dataSource, requestedPath, locale } = options;
|
|
13
14
|
// log received parameters
|
|
14
15
|
console.log(`[LLMCopy] Received, locale=${locale}, path=${requestedPath}`);
|
|
@@ -26,8 +27,8 @@ function LLMCopyHandler(options) {
|
|
|
26
27
|
console.error(`[LLMCopy] file path information missing in page data for locale=${locale}, path=${requestedPath}`);
|
|
27
28
|
return { error: 'Page file path information missing', status: 500 };
|
|
28
29
|
}
|
|
29
|
-
const title = page.title;
|
|
30
|
-
const description = page.description;
|
|
30
|
+
const title = (_b = (_a = page.data) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : page.title;
|
|
31
|
+
const description = (_d = (_c = page.data) === null || _c === void 0 ? void 0 : _c.description) !== null && _d !== void 0 ? _d : page.description;
|
|
31
32
|
const relativeMdxFilePath = page.path;
|
|
32
33
|
const absoluteFilePath = nodePath.join(process.cwd(), sourceDir, relativeMdxFilePath);
|
|
33
34
|
console.log(`[LLMCopy] Attempting to read MDX content from: ${absoluteFilePath}`);
|
package/dist/fuma/mdx/index.d.ts
CHANGED
package/dist/fuma/mdx/index.js
CHANGED
|
@@ -15,6 +15,7 @@ var tocClerkPortable = require('./toc-clerk-portable.js');
|
|
|
15
15
|
var banner = require('./banner.js');
|
|
16
16
|
var sunoEmbed = require('./suno-embed.js');
|
|
17
17
|
var markdownComponentMap = require('./markdown-component-map.js');
|
|
18
|
+
var math = require('./math.js');
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
|
|
@@ -38,3 +39,5 @@ exports.PortableClerkTOCScrollArea = tocClerkPortable.PortableClerkTOCScrollArea
|
|
|
38
39
|
exports.Banner = banner.Banner;
|
|
39
40
|
exports.SunoEmbed = sunoEmbed.SunoEmbed;
|
|
40
41
|
exports.baseMarkdownComponents = markdownComponentMap.baseMarkdownComponents;
|
|
42
|
+
exports.InlineMath = math.InlineMath;
|
|
43
|
+
exports.MathBlock = math.MathBlock;
|
package/dist/fuma/mdx/index.mjs
CHANGED
|
@@ -13,3 +13,4 @@ export { PortableClerkTOC, PortableClerkTOCItems, PortableClerkTOCPopover, Porta
|
|
|
13
13
|
export { Banner } from './banner.mjs';
|
|
14
14
|
export { SunoEmbed } from './suno-embed.mjs';
|
|
15
15
|
export { baseMarkdownComponents } from './markdown-component-map.mjs';
|
|
16
|
+
export { InlineMath, MathBlock } from './math.mjs';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
type MathSourceProps = {
|
|
3
|
+
children?: ReactNode;
|
|
4
|
+
math?: string;
|
|
5
|
+
formula?: string;
|
|
6
|
+
};
|
|
7
|
+
type Align = 'left' | 'center' | 'right';
|
|
8
|
+
export type MathBlockProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & MathSourceProps & {
|
|
9
|
+
title?: ReactNode;
|
|
10
|
+
titleAlign?: Align;
|
|
11
|
+
};
|
|
12
|
+
export type InlineMathProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children'> & MathSourceProps & {
|
|
13
|
+
align?: Align;
|
|
14
|
+
};
|
|
15
|
+
export declare function MathBlock({ title, titleAlign, children, math, formula, className, ...props }: MathBlockProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare function InlineMath({ children, math, formula, align, className, ...props }: InlineMathProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var katex = require('katex');
|
|
6
|
+
var utils = require('@windrun-huaiin/lib/utils');
|
|
7
|
+
|
|
8
|
+
const alignClassMap = {
|
|
9
|
+
left: 'text-left justify-start',
|
|
10
|
+
center: 'text-center justify-center',
|
|
11
|
+
right: 'text-right justify-end',
|
|
12
|
+
};
|
|
13
|
+
const textAlignClassMap = {
|
|
14
|
+
left: 'text-left',
|
|
15
|
+
center: 'text-center',
|
|
16
|
+
right: 'text-right',
|
|
17
|
+
};
|
|
18
|
+
function getMathSource({ children, math, formula }) {
|
|
19
|
+
if (typeof math === 'string' && math.trim() !== '')
|
|
20
|
+
return math.trim();
|
|
21
|
+
if (typeof formula === 'string' && formula.trim() !== '')
|
|
22
|
+
return formula.trim();
|
|
23
|
+
if (typeof children === 'string' && children.trim() !== '')
|
|
24
|
+
return children.trim();
|
|
25
|
+
if (Array.isArray(children)) {
|
|
26
|
+
const text = children
|
|
27
|
+
.map((item) => (typeof item === 'string' ? item : ''))
|
|
28
|
+
.join('')
|
|
29
|
+
.trim();
|
|
30
|
+
if (text !== '')
|
|
31
|
+
return text;
|
|
32
|
+
}
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
function renderMath(source, displayMode) {
|
|
36
|
+
if (source === '')
|
|
37
|
+
return '';
|
|
38
|
+
return katex.renderToString(source, {
|
|
39
|
+
displayMode,
|
|
40
|
+
throwOnError: false,
|
|
41
|
+
output: 'html',
|
|
42
|
+
strict: 'ignore',
|
|
43
|
+
trust: false,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function MathBlock(_a) {
|
|
47
|
+
var { title, titleAlign = 'center', children, math, formula, className } = _a, props = tslib.__rest(_a, ["title", "titleAlign", "children", "math", "formula", "className"]);
|
|
48
|
+
const source = getMathSource({ children, math, formula });
|
|
49
|
+
const html = renderMath(source, true);
|
|
50
|
+
return (jsxRuntime.jsxs("div", Object.assign({}, props, { className: utils.cn('not-prose my-6 overflow-x-auto rounded-xl border bg-fd-card p-4 text-fd-card-foreground', className), children: [title ? (jsxRuntime.jsx("div", { className: utils.cn('mb-3 text-sm font-medium text-fd-muted-foreground', alignClassMap[titleAlign].split(' ')[0]), children: title })) : null, html ? (jsxRuntime.jsx("div", { className: "min-w-fit [&_.katex-display]:my-0 [&_.katex-display]:overflow-x-auto [&_.katex-display]:overflow-y-hidden", dangerouslySetInnerHTML: { __html: html } })) : (jsxRuntime.jsx("div", { className: "text-sm text-fd-muted-foreground", children: "Empty math block." }))] })));
|
|
51
|
+
}
|
|
52
|
+
function InlineMath(_a) {
|
|
53
|
+
var { children, math, formula, align = 'center', className } = _a, props = tslib.__rest(_a, ["children", "math", "formula", "align", "className"]);
|
|
54
|
+
const source = getMathSource({ children, math, formula });
|
|
55
|
+
const html = renderMath(source, false);
|
|
56
|
+
return (jsxRuntime.jsx("span", Object.assign({}, props, { className: utils.cn('mx-1 inline-flex max-w-full align-middle rounded-md bg-neutral-200 px-2 py-0.5 text-sm leading-none dark:bg-white/20 [&_.katex]:text-inherit', textAlignClassMap[align], className), children: jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: html } }) })));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
exports.InlineMath = InlineMath;
|
|
60
|
+
exports.MathBlock = MathBlock;
|