@windrun-huaiin/third-ui 7.3.2 → 7.3.4

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.
Files changed (50) hide show
  1. package/dist/clerk/fingerprint/fingerprint-provider.js +26 -6
  2. package/dist/clerk/fingerprint/fingerprint-provider.mjs +27 -7
  3. package/dist/clerk/fingerprint/use-fingerprint.js +1 -1
  4. package/dist/clerk/fingerprint/use-fingerprint.mjs +1 -1
  5. package/dist/main/faq.js +11 -0
  6. package/dist/main/faq.mjs +11 -0
  7. package/dist/main/gallery.js +11 -0
  8. package/dist/main/gallery.mjs +11 -0
  9. package/dist/main/index.d.ts +2 -0
  10. package/dist/main/index.js +4 -0
  11. package/dist/main/index.mjs +2 -0
  12. package/dist/main/money-price/money-price-button.d.ts +2 -0
  13. package/dist/main/money-price/money-price-button.js +96 -0
  14. package/dist/main/money-price/money-price-button.mjs +94 -0
  15. package/dist/main/money-price/money-price-config-util.d.ts +7 -0
  16. package/dist/main/money-price/money-price-config-util.js +19 -0
  17. package/dist/main/money-price/money-price-config-util.mjs +16 -0
  18. package/dist/main/money-price/money-price-config.d.ts +8 -0
  19. package/dist/main/money-price/money-price-config.js +223 -0
  20. package/dist/main/money-price/money-price-config.mjs +219 -0
  21. package/dist/main/money-price/money-price-interactive.d.ts +2 -0
  22. package/dist/main/money-price/money-price-interactive.js +315 -0
  23. package/dist/main/money-price/money-price-interactive.mjs +313 -0
  24. package/dist/main/money-price/money-price-types.d.ts +116 -0
  25. package/dist/main/money-price/money-price-types.js +14 -0
  26. package/dist/main/money-price/money-price-types.mjs +14 -0
  27. package/dist/main/money-price/money-price.d.ts +2 -0
  28. package/dist/main/money-price/money-price.js +93 -0
  29. package/dist/main/money-price/money-price.mjs +91 -0
  30. package/dist/main/price-plan.js +12 -0
  31. package/dist/main/price-plan.mjs +12 -0
  32. package/dist/main/server.d.ts +4 -0
  33. package/dist/main/server.js +10 -0
  34. package/dist/main/server.mjs +3 -0
  35. package/dist/node_modules/.pnpm/cose-base@1.0.3/node_modules/cose-base/cose-base.js +1 -1
  36. package/dist/node_modules/.pnpm/cose-base@1.0.3/node_modules/cose-base/cose-base.mjs +1 -1
  37. package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.js +1 -1
  38. package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.mjs +1 -1
  39. package/dist/node_modules/.pnpm/layout-base@1.0.2/node_modules/layout-base/layout-base.js +1 -1
  40. package/dist/node_modules/.pnpm/layout-base@2.0.1/node_modules/layout-base/layout-base.js +1 -1
  41. package/package.json +1 -1
  42. package/src/clerk/fingerprint/fingerprint-provider.tsx +53 -20
  43. package/src/clerk/fingerprint/use-fingerprint.ts +1 -1
  44. package/src/main/index.ts +5 -1
  45. package/src/main/money-price/money-price-button.tsx +105 -0
  46. package/src/main/money-price/money-price-config-util.ts +23 -0
  47. package/src/main/money-price/money-price-interactive.tsx +381 -0
  48. package/src/main/money-price/money-price-types.ts +138 -0
  49. package/src/main/money-price/money-price.tsx +307 -0
  50. package/src/main/server.ts +24 -1
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Money Price Component Types
3
+ * 价格组件类型定义
4
+ */
5
+ export declare enum UserState {
6
+ Anonymous = "anonymous",
7
+ FreeUser = "free",
8
+ ProUser = "pro",
9
+ UltraUser = "ultra"
10
+ }
11
+ export interface UserContext {
12
+ isAuthenticated: boolean;
13
+ subscriptionStatus: UserState;
14
+ subscriptionType?: 'monthly' | 'yearly';
15
+ subscriptionEndDate?: string;
16
+ }
17
+ export type PaymentProvider = 'stripe' | 'apple' | 'paypal' | 'wechat' | 'alipay';
18
+ export interface EnhancePricePlan {
19
+ priceId: string;
20
+ amount: number;
21
+ originalAmount?: number;
22
+ discountPercent?: number;
23
+ currency: string;
24
+ credits?: number;
25
+ }
26
+ export interface ProductConfig {
27
+ key: string;
28
+ name: string;
29
+ plans: {
30
+ monthly: EnhancePricePlan;
31
+ yearly: EnhancePricePlan;
32
+ };
33
+ }
34
+ export interface PaymentProviderConfig {
35
+ provider: PaymentProvider;
36
+ enabled: boolean;
37
+ products: {
38
+ free: ProductConfig;
39
+ pro: ProductConfig;
40
+ ultra: ProductConfig;
41
+ };
42
+ }
43
+ export interface MoneyPriceConfig {
44
+ paymentProviders: {
45
+ [provider: string]: PaymentProviderConfig;
46
+ };
47
+ activeProvider: string;
48
+ display: {
49
+ currency: string;
50
+ locale: string;
51
+ minFeaturesCount: number;
52
+ };
53
+ }
54
+ export interface MoneyPriceProps {
55
+ locale: string;
56
+ config: MoneyPriceConfig;
57
+ className?: string;
58
+ upgradeApiEndpoint?: string;
59
+ signInPath?: string;
60
+ sectionClassName?: string;
61
+ }
62
+ export interface MoneyPriceInteractiveProps {
63
+ data: MoneyPriceData;
64
+ config: MoneyPriceConfig;
65
+ upgradeApiEndpoint?: string;
66
+ signInPath?: string;
67
+ }
68
+ export interface MoneyPriceButtonProps {
69
+ planKey: 'free' | 'pro' | 'ultra';
70
+ userContext: UserContext;
71
+ billingType: 'monthly' | 'yearly';
72
+ onLogin: () => void;
73
+ onUpgrade: (plan: string, billingType: string) => void | Promise<void>;
74
+ texts: {
75
+ getStarted: string;
76
+ getPro: string;
77
+ getUltra: string;
78
+ currentPlan: string;
79
+ upgrade: string;
80
+ };
81
+ isProcessing?: boolean;
82
+ }
83
+ export interface MoneyPriceData {
84
+ title: string;
85
+ subtitle: string;
86
+ billingSwitch: {
87
+ options: Array<{
88
+ key: string;
89
+ name: string;
90
+ unit: string;
91
+ discountText: string;
92
+ subTitle?: string;
93
+ }>;
94
+ defaultKey: string;
95
+ };
96
+ plans: Array<{
97
+ key: string;
98
+ title: string;
99
+ showBillingSubTitle?: boolean;
100
+ titleTags?: string[];
101
+ features?: Array<{
102
+ description: string;
103
+ icon?: string;
104
+ tag?: string;
105
+ tooltip?: string;
106
+ }>;
107
+ }>;
108
+ buttonTexts: {
109
+ getStarted: string;
110
+ getPro: string;
111
+ getUltra: string;
112
+ currentPlan: string;
113
+ upgrade: string;
114
+ };
115
+ currency: string;
116
+ }
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Money Price Component Types
5
+ * 价格组件类型定义
6
+ */
7
+ // 用户状态枚举
8
+ exports.UserState = void 0;
9
+ (function (UserState) {
10
+ UserState["Anonymous"] = "anonymous";
11
+ UserState["FreeUser"] = "free";
12
+ UserState["ProUser"] = "pro";
13
+ UserState["UltraUser"] = "ultra";
14
+ })(exports.UserState || (exports.UserState = {}));
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Money Price Component Types
3
+ * 价格组件类型定义
4
+ */
5
+ // 用户状态枚举
6
+ var UserState;
7
+ (function (UserState) {
8
+ UserState["Anonymous"] = "anonymous";
9
+ UserState["FreeUser"] = "free";
10
+ UserState["ProUser"] = "pro";
11
+ UserState["UltraUser"] = "ultra";
12
+ })(UserState || (UserState = {}));
13
+
14
+ export { UserState };
@@ -0,0 +1,2 @@
1
+ import type { MoneyPriceProps } from './money-price-types';
2
+ export declare function MoneyPrice({ locale, config, upgradeApiEndpoint, signInPath, sectionClassName }: MoneyPriceProps): Promise<import("react/jsx-runtime").JSX.Element>;
@@ -0,0 +1,93 @@
1
+ 'use strict';
2
+
3
+ var tslib_es6 = require('../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.js');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ require('@windrun-huaiin/base-ui/components/server');
6
+ require('next-themes');
7
+ require('react');
8
+ require('fumadocs-core/framework');
9
+ var utils = require('@windrun-huaiin/lib/utils');
10
+ require('next/link');
11
+ var gradientButton = require('../../fuma/mdx/gradient-button.js');
12
+ require('next/navigation');
13
+ require('fumadocs-ui/utils/use-copy-button');
14
+ require('fumadocs-core/link');
15
+ require('@windrun-huaiin/base-ui/ui');
16
+ require('fumadocs-ui/components/ui/collapsible');
17
+ require('../../fuma/mdx/banner.js');
18
+ var server = require('next-intl/server');
19
+ var moneyPriceConfigUtil = require('./money-price-config-util.js');
20
+ var moneyPriceInteractive = require('./money-price-interactive.js');
21
+
22
+ function MoneyPrice(_a) {
23
+ return tslib_es6.__awaiter(this, arguments, void 0, function* ({ locale, config, upgradeApiEndpoint, signInPath, sectionClassName }) {
24
+ var _b, _c;
25
+ const t = yield server.getTranslations({ locale, namespace: 'moneyPrice' });
26
+ const data = {
27
+ title: t('title'),
28
+ subtitle: t('subtitle'),
29
+ billingSwitch: t.raw('billingSwitch'),
30
+ plans: t.raw('plans'),
31
+ buttonTexts: t.raw('buttonTexts'),
32
+ currency: config.display.currency
33
+ };
34
+ // 获取激活的支付供应商配置
35
+ const providerConfig = moneyPriceConfigUtil.getActiveProviderConfig(config);
36
+ const minPlanFeaturesCount = config.display.minFeaturesCount;
37
+ // 使用默认计费类型进行静态渲染
38
+ const defaultBilling = data.billingSwitch.defaultKey;
39
+ const defaultBillingDisplay = data.billingSwitch.options.find((opt) => opt.key === defaultBilling) || data.billingSwitch.options[0];
40
+ // 计算特性数量
41
+ const maxFeaturesCount = Math.max(...data.plans.map((plan) => { var _a; return ((_a = plan.features) === null || _a === void 0 ? void 0 : _a.length) || 0; }), minPlanFeaturesCount || 0);
42
+ // 处理卡片高度对齐
43
+ const getFeatureRows = (plan) => {
44
+ const features = plan.features || [];
45
+ const filled = [...features];
46
+ while (filled.length < maxFeaturesCount)
47
+ filled.push(null);
48
+ return filled;
49
+ };
50
+ // 静态价格渲染逻辑
51
+ function renderPrice(plan, billingKey = data.billingSwitch.defaultKey) {
52
+ const productConfig = providerConfig.products[plan.key];
53
+ const pricing = productConfig.plans[billingKey];
54
+ const currentBillingDisplay = data.billingSwitch.options.find((opt) => opt.key === billingKey) || defaultBillingDisplay;
55
+ const billingSubTitle = (currentBillingDisplay === null || currentBillingDisplay === void 0 ? void 0 : currentBillingDisplay.subTitle) || '';
56
+ // 免费计划
57
+ if (pricing.amount === 0) {
58
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col items-start w-full", "data-price-container": plan.key, children: [jsxRuntime.jsx("div", { className: "flex items-end gap-2", children: jsxRuntime.jsx("span", { className: "text-4xl font-extrabold text-gray-900 dark:text-gray-100", "data-price-value": plan.key, children: "Free" }) }), jsxRuntime.jsx("div", { className: "flex items-center gap-2 min-h-[24px] mt-1", children: jsxRuntime.jsx("span", { className: utils.cn('text-xs text-gray-700 dark:text-gray-300 font-medium', plan.showBillingSubTitle === false && 'opacity-0 select-none'), "data-price-subtitle": plan.key, children: plan.showBillingSubTitle === false ? '' : billingSubTitle }) })] }));
59
+ }
60
+ // 付费计划
61
+ const hasDiscount = pricing.discountPercent && pricing.discountPercent > 0;
62
+ const unit = currentBillingDisplay.unit || '';
63
+ let discountText = '';
64
+ if (hasDiscount && currentBillingDisplay.discountText) {
65
+ discountText = currentBillingDisplay.discountText.replace('{percent}', String(pricing.discountPercent));
66
+ }
67
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col items-start w-full", "data-price-container": plan.key, children: [jsxRuntime.jsxs("div", { className: "flex items-end gap-2", children: [jsxRuntime.jsxs("span", { className: "text-4xl font-extrabold text-gray-900 dark:text-gray-100", "data-price-value": plan.key, children: [data.currency, pricing.amount] }), jsxRuntime.jsx("span", { className: "text-lg text-gray-700 dark:text-gray-300 font-medium mb-1", "data-price-unit": plan.key, children: unit })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-h-[24px] mt-1", children: [hasDiscount && pricing.originalAmount && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("span", { className: "text-base text-gray-400 line-through", "data-price-original": plan.key, children: [data.currency, pricing.originalAmount] }), discountText && (jsxRuntime.jsx("span", { className: "px-2 py-0.5 text-xs rounded bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200 font-semibold align-middle", "data-price-discount": plan.key, children: discountText }))] })), jsxRuntime.jsx("span", { className: utils.cn('text-xs text-gray-700 dark:text-gray-300 font-medium', plan.showBillingSubTitle === false && 'opacity-0 select-none'), "data-price-subtitle": plan.key, children: plan.showBillingSubTitle === false ? '' : billingSubTitle })] })] }));
68
+ }
69
+ return (jsxRuntime.jsxs("section", { id: "money-pricing", className: utils.cn("px-4 py-10 md:px-16 md:py-16 mx-auto max-w-7xl scroll-mt-10", sectionClassName), children: [jsxRuntime.jsx("h2", { className: "text-3xl md:text-4xl font-bold text-center mb-3", children: data.title }), jsxRuntime.jsx("p", { className: "text-center text-gray-600 dark:text-gray-400 mb-8 text-base md:text-lg mx-auto", children: data.subtitle }), jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [jsxRuntime.jsx("div", { className: "flex items-center relative mb-3", children: jsxRuntime.jsxs("div", { className: "flex bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded-full p-1", "data-billing-switch": true, children: [jsxRuntime.jsx("button", { className: utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', data.billingSwitch.defaultKey === 'monthly'
70
+ ? 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm'
71
+ : 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full'), "data-billing-button": "monthly", type: "button", children: ((_b = data.billingSwitch.options.find((opt) => opt.key === 'monthly')) === null || _b === void 0 ? void 0 : _b.name) || 'Monthly' }), jsxRuntime.jsx("button", { className: utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', data.billingSwitch.defaultKey === 'yearly'
72
+ ? 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm'
73
+ : 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full'), "data-billing-button": "yearly", type: "button", children: ((_c = data.billingSwitch.options.find((opt) => opt.key === 'yearly')) === null || _c === void 0 ? void 0 : _c.name) || 'Yearly' })] }) }), jsxRuntime.jsx("div", { className: "h-8 flex items-center justify-center mb-3", "data-discount-info": true, children: (() => {
74
+ const opt = data.billingSwitch.options.find((opt) => opt.key === data.billingSwitch.defaultKey);
75
+ // 检查默认计费类型是否有折扣
76
+ let hasDiscount = false;
77
+ let discountPercent = 0;
78
+ ['pro', 'ultra'].forEach(planKey => {
79
+ const product = providerConfig.products[planKey];
80
+ const pricing = product.plans[data.billingSwitch.defaultKey];
81
+ if (pricing.discountPercent) {
82
+ hasDiscount = true;
83
+ discountPercent = pricing.discountPercent;
84
+ }
85
+ });
86
+ if (!(opt && hasDiscount && opt.discountText))
87
+ return null;
88
+ return (jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap", children: opt.discountText.replace('{percent}', String(discountPercent)) }));
89
+ })() })] }), jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-8", children: data.plans.map((plan, _idx) => (jsxRuntime.jsxs("div", { "data-price-plan": plan.key, className: utils.cn('flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8 h-full shadow-sm dark:shadow-none', 'hover:border-2 hover:border-purple-500', 'focus-within:border-2 focus-within:border-purple-500'), style: { minHeight: maxFeaturesCount * 100 }, children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsxRuntime.jsx("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: plan.title }), plan.titleTags && plan.titleTags.map((tag, i) => (jsxRuntime.jsx("span", { className: "px-2 py-0.5 text-xs rounded bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200 font-semibold align-middle", children: tag }, i)))] }), renderPrice(plan), jsxRuntime.jsx("ul", { className: "flex-1 mb-6 mt-4", children: getFeatureRows(plan).map((feature, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-2 mb-2 min-h-[28px]", "data-feature-item": `${plan.key}-${i}`, children: [feature ? (jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200 mr-1", children: feature.icon ? jsxRuntime.jsx("span", { children: feature.icon }) : jsxRuntime.jsx("span", { className: "font-bold", children: "\u2713" }) })) : (jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full mr-1", children: "\u00A0" })), feature && feature.tag && (jsxRuntime.jsx("span", { className: "px-1 py-0.5 text-[6px] rounded bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 font-semibold align-middle", children: feature.tag })), feature ? (jsxRuntime.jsxs("span", { className: "relative group cursor-pointer text-sm text-gray-800 dark:text-gray-200", children: [feature.description, feature.tooltip && (jsxRuntime.jsx("span", { className: "ml-1 align-middle inline-flex", "data-tooltip-trigger": `${plan.key}-${i}`, "data-tooltip-content": feature.tooltip, children: jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }) }))] })) : (jsxRuntime.jsx("span", { children: "\u00A0" }))] }, i))) }), jsxRuntime.jsx("div", { className: "flex-1" }), jsxRuntime.jsx("div", { "data-button-placeholder": plan.key, children: jsxRuntime.jsx(gradientButton.GradientButton, { title: data.buttonTexts.getStarted, disabled: true, align: "center", className: "w-full" }) })] }, plan.key))) }), jsxRuntime.jsx(moneyPriceInteractive.MoneyPriceInteractive, { data: data, config: config, upgradeApiEndpoint: upgradeApiEndpoint, signInPath: signInPath })] }));
90
+ });
91
+ }
92
+
93
+ exports.MoneyPrice = MoneyPrice;
@@ -0,0 +1,91 @@
1
+ import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.mjs';
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
+ import '@windrun-huaiin/base-ui/components/server';
4
+ import 'next-themes';
5
+ import 'react';
6
+ import 'fumadocs-core/framework';
7
+ import { cn } from '@windrun-huaiin/lib/utils';
8
+ import 'next/link';
9
+ import { GradientButton } from '../../fuma/mdx/gradient-button.mjs';
10
+ import 'next/navigation';
11
+ import 'fumadocs-ui/utils/use-copy-button';
12
+ import 'fumadocs-core/link';
13
+ import '@windrun-huaiin/base-ui/ui';
14
+ import 'fumadocs-ui/components/ui/collapsible';
15
+ import '../../fuma/mdx/banner.mjs';
16
+ import { getTranslations } from 'next-intl/server';
17
+ import { getActiveProviderConfig } from './money-price-config-util.mjs';
18
+ import { MoneyPriceInteractive } from './money-price-interactive.mjs';
19
+
20
+ function MoneyPrice(_a) {
21
+ return __awaiter(this, arguments, void 0, function* ({ locale, config, upgradeApiEndpoint, signInPath, sectionClassName }) {
22
+ var _b, _c;
23
+ const t = yield getTranslations({ locale, namespace: 'moneyPrice' });
24
+ const data = {
25
+ title: t('title'),
26
+ subtitle: t('subtitle'),
27
+ billingSwitch: t.raw('billingSwitch'),
28
+ plans: t.raw('plans'),
29
+ buttonTexts: t.raw('buttonTexts'),
30
+ currency: config.display.currency
31
+ };
32
+ // 获取激活的支付供应商配置
33
+ const providerConfig = getActiveProviderConfig(config);
34
+ const minPlanFeaturesCount = config.display.minFeaturesCount;
35
+ // 使用默认计费类型进行静态渲染
36
+ const defaultBilling = data.billingSwitch.defaultKey;
37
+ const defaultBillingDisplay = data.billingSwitch.options.find((opt) => opt.key === defaultBilling) || data.billingSwitch.options[0];
38
+ // 计算特性数量
39
+ const maxFeaturesCount = Math.max(...data.plans.map((plan) => { var _a; return ((_a = plan.features) === null || _a === void 0 ? void 0 : _a.length) || 0; }), minPlanFeaturesCount || 0);
40
+ // 处理卡片高度对齐
41
+ const getFeatureRows = (plan) => {
42
+ const features = plan.features || [];
43
+ const filled = [...features];
44
+ while (filled.length < maxFeaturesCount)
45
+ filled.push(null);
46
+ return filled;
47
+ };
48
+ // 静态价格渲染逻辑
49
+ function renderPrice(plan, billingKey = data.billingSwitch.defaultKey) {
50
+ const productConfig = providerConfig.products[plan.key];
51
+ const pricing = productConfig.plans[billingKey];
52
+ const currentBillingDisplay = data.billingSwitch.options.find((opt) => opt.key === billingKey) || defaultBillingDisplay;
53
+ const billingSubTitle = (currentBillingDisplay === null || currentBillingDisplay === void 0 ? void 0 : currentBillingDisplay.subTitle) || '';
54
+ // 免费计划
55
+ if (pricing.amount === 0) {
56
+ return (jsxs("div", { className: "flex flex-col items-start w-full", "data-price-container": plan.key, children: [jsx("div", { className: "flex items-end gap-2", children: jsx("span", { className: "text-4xl font-extrabold text-gray-900 dark:text-gray-100", "data-price-value": plan.key, children: "Free" }) }), jsx("div", { className: "flex items-center gap-2 min-h-[24px] mt-1", children: jsx("span", { className: cn('text-xs text-gray-700 dark:text-gray-300 font-medium', plan.showBillingSubTitle === false && 'opacity-0 select-none'), "data-price-subtitle": plan.key, children: plan.showBillingSubTitle === false ? '' : billingSubTitle }) })] }));
57
+ }
58
+ // 付费计划
59
+ const hasDiscount = pricing.discountPercent && pricing.discountPercent > 0;
60
+ const unit = currentBillingDisplay.unit || '';
61
+ let discountText = '';
62
+ if (hasDiscount && currentBillingDisplay.discountText) {
63
+ discountText = currentBillingDisplay.discountText.replace('{percent}', String(pricing.discountPercent));
64
+ }
65
+ return (jsxs("div", { className: "flex flex-col items-start w-full", "data-price-container": plan.key, children: [jsxs("div", { className: "flex items-end gap-2", children: [jsxs("span", { className: "text-4xl font-extrabold text-gray-900 dark:text-gray-100", "data-price-value": plan.key, children: [data.currency, pricing.amount] }), jsx("span", { className: "text-lg text-gray-700 dark:text-gray-300 font-medium mb-1", "data-price-unit": plan.key, children: unit })] }), jsxs("div", { className: "flex items-center gap-2 min-h-[24px] mt-1", children: [hasDiscount && pricing.originalAmount && (jsxs(Fragment, { children: [jsxs("span", { className: "text-base text-gray-400 line-through", "data-price-original": plan.key, children: [data.currency, pricing.originalAmount] }), discountText && (jsx("span", { className: "px-2 py-0.5 text-xs rounded bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200 font-semibold align-middle", "data-price-discount": plan.key, children: discountText }))] })), jsx("span", { className: cn('text-xs text-gray-700 dark:text-gray-300 font-medium', plan.showBillingSubTitle === false && 'opacity-0 select-none'), "data-price-subtitle": plan.key, children: plan.showBillingSubTitle === false ? '' : billingSubTitle })] })] }));
66
+ }
67
+ return (jsxs("section", { id: "money-pricing", className: cn("px-4 py-10 md:px-16 md:py-16 mx-auto max-w-7xl scroll-mt-10", sectionClassName), children: [jsx("h2", { className: "text-3xl md:text-4xl font-bold text-center mb-3", children: data.title }), jsx("p", { className: "text-center text-gray-600 dark:text-gray-400 mb-8 text-base md:text-lg mx-auto", children: data.subtitle }), jsxs("div", { className: "flex flex-col items-center", children: [jsx("div", { className: "flex items-center relative mb-3", children: jsxs("div", { className: "flex bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded-full p-1", "data-billing-switch": true, children: [jsx("button", { className: cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', data.billingSwitch.defaultKey === 'monthly'
68
+ ? 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm'
69
+ : 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full'), "data-billing-button": "monthly", type: "button", children: ((_b = data.billingSwitch.options.find((opt) => opt.key === 'monthly')) === null || _b === void 0 ? void 0 : _b.name) || 'Monthly' }), jsx("button", { className: cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', data.billingSwitch.defaultKey === 'yearly'
70
+ ? 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm'
71
+ : 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full'), "data-billing-button": "yearly", type: "button", children: ((_c = data.billingSwitch.options.find((opt) => opt.key === 'yearly')) === null || _c === void 0 ? void 0 : _c.name) || 'Yearly' })] }) }), jsx("div", { className: "h-8 flex items-center justify-center mb-3", "data-discount-info": true, children: (() => {
72
+ const opt = data.billingSwitch.options.find((opt) => opt.key === data.billingSwitch.defaultKey);
73
+ // 检查默认计费类型是否有折扣
74
+ let hasDiscount = false;
75
+ let discountPercent = 0;
76
+ ['pro', 'ultra'].forEach(planKey => {
77
+ const product = providerConfig.products[planKey];
78
+ const pricing = product.plans[data.billingSwitch.defaultKey];
79
+ if (pricing.discountPercent) {
80
+ hasDiscount = true;
81
+ discountPercent = pricing.discountPercent;
82
+ }
83
+ });
84
+ if (!(opt && hasDiscount && opt.discountText))
85
+ return null;
86
+ return (jsx("span", { className: "px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap", children: opt.discountText.replace('{percent}', String(discountPercent)) }));
87
+ })() })] }), jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-8", children: data.plans.map((plan, _idx) => (jsxs("div", { "data-price-plan": plan.key, className: cn('flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8 h-full shadow-sm dark:shadow-none', 'hover:border-2 hover:border-purple-500', 'focus-within:border-2 focus-within:border-purple-500'), style: { minHeight: maxFeaturesCount * 100 }, children: [jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsx("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: plan.title }), plan.titleTags && plan.titleTags.map((tag, i) => (jsx("span", { className: "px-2 py-0.5 text-xs rounded bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200 font-semibold align-middle", children: tag }, i)))] }), renderPrice(plan), jsx("ul", { className: "flex-1 mb-6 mt-4", children: getFeatureRows(plan).map((feature, i) => (jsxs("li", { className: "flex items-center gap-2 mb-2 min-h-[28px]", "data-feature-item": `${plan.key}-${i}`, children: [feature ? (jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200 mr-1", children: feature.icon ? jsx("span", { children: feature.icon }) : jsx("span", { className: "font-bold", children: "\u2713" }) })) : (jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full mr-1", children: "\u00A0" })), feature && feature.tag && (jsx("span", { className: "px-1 py-0.5 text-[6px] rounded bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 font-semibold align-middle", children: feature.tag })), feature ? (jsxs("span", { className: "relative group cursor-pointer text-sm text-gray-800 dark:text-gray-200", children: [feature.description, feature.tooltip && (jsx("span", { className: "ml-1 align-middle inline-flex", "data-tooltip-trigger": `${plan.key}-${i}`, "data-tooltip-content": feature.tooltip, children: jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }) }))] })) : (jsx("span", { children: "\u00A0" }))] }, i))) }), jsx("div", { className: "flex-1" }), jsx("div", { "data-button-placeholder": plan.key, children: jsx(GradientButton, { title: data.buttonTexts.getStarted, disabled: true, align: "center", className: "w-full" }) })] }, plan.key))) }), jsx(MoneyPriceInteractive, { data: data, config: config, upgradeApiEndpoint: upgradeApiEndpoint, signInPath: signInPath })] }));
88
+ });
89
+ }
90
+
91
+ export { MoneyPrice };
@@ -11,6 +11,18 @@ require('next/image');
11
11
  require('@windrun-huaiin/base-ui/ui');
12
12
  require('./rich-text-expert.js');
13
13
  var pricePlanInteractive = require('./price-plan-interactive.js');
14
+ require('@clerk/nextjs');
15
+ require('../clerk/fingerprint/fingerprint-provider.js');
16
+ require('next/navigation');
17
+ require('react-dom/client');
18
+ require('next-themes');
19
+ require('fumadocs-core/framework');
20
+ require('next/link');
21
+ require('fumadocs-ui/utils/use-copy-button');
22
+ require('fumadocs-core/link');
23
+ require('fumadocs-ui/components/ui/collapsible');
24
+ require('../fuma/mdx/banner.js');
25
+ require('./money-price/money-price-types.js');
14
26
 
15
27
  function PricePlan(_a) {
16
28
  return tslib_es6.__awaiter(this, arguments, void 0, function* ({ locale, currency = '$', pricePlanConfig, sectionClassName }) {
@@ -9,6 +9,18 @@ import 'next/image';
9
9
  import '@windrun-huaiin/base-ui/ui';
10
10
  import './rich-text-expert.mjs';
11
11
  import { PricePlanInteractive } from './price-plan-interactive.mjs';
12
+ import '@clerk/nextjs';
13
+ import '../clerk/fingerprint/fingerprint-provider.mjs';
14
+ import 'next/navigation';
15
+ import 'react-dom/client';
16
+ import 'next-themes';
17
+ import 'fumadocs-core/framework';
18
+ import 'next/link';
19
+ import 'fumadocs-ui/utils/use-copy-button';
20
+ import 'fumadocs-core/link';
21
+ import 'fumadocs-ui/components/ui/collapsible';
22
+ import '../fuma/mdx/banner.mjs';
23
+ import './money-price/money-price-types.mjs';
12
24
 
13
25
  function PricePlan(_a) {
14
26
  return __awaiter(this, arguments, void 0, function* ({ locale, currency = '$', pricePlanConfig, sectionClassName }) {
@@ -7,3 +7,7 @@ export * from './seo-content';
7
7
  export * from './cta';
8
8
  export * from './footer';
9
9
  export * from './price-plan';
10
+ export { MoneyPrice } from './money-price/money-price';
11
+ export { getActiveProviderConfig, getProductPricing } from './money-price/money-price-config-util';
12
+ export type { MoneyPriceConfig, MoneyPriceProps, MoneyPriceInteractiveProps, MoneyPriceButtonProps, MoneyPriceData, PaymentProvider, PaymentProviderConfig, EnhancePricePlan, ProductConfig, UserContext } from './money-price/money-price-types';
13
+ export { UserState } from './money-price/money-price-types';
@@ -9,6 +9,9 @@ var seoContent = require('./seo-content.js');
9
9
  var cta = require('./cta.js');
10
10
  var footer = require('./footer.js');
11
11
  var pricePlan = require('./price-plan.js');
12
+ var moneyPrice = require('./money-price/money-price.js');
13
+ var moneyPriceConfigUtil = require('./money-price/money-price-config-util.js');
14
+ var moneyPriceTypes = require('./money-price/money-price-types.js');
12
15
 
13
16
 
14
17
 
@@ -21,3 +24,10 @@ exports.SeoContent = seoContent.SeoContent;
21
24
  exports.CTA = cta.CTA;
22
25
  exports.Footer = footer.Footer;
23
26
  exports.PricePlan = pricePlan.PricePlan;
27
+ exports.MoneyPrice = moneyPrice.MoneyPrice;
28
+ exports.getActiveProviderConfig = moneyPriceConfigUtil.getActiveProviderConfig;
29
+ exports.getProductPricing = moneyPriceConfigUtil.getProductPricing;
30
+ Object.defineProperty(exports, "UserState", {
31
+ enumerable: true,
32
+ get: function () { return moneyPriceTypes.UserState; }
33
+ });
@@ -7,3 +7,6 @@ export { SeoContent } from './seo-content.mjs';
7
7
  export { CTA } from './cta.mjs';
8
8
  export { Footer } from './footer.mjs';
9
9
  export { PricePlan } from './price-plan.mjs';
10
+ export { MoneyPrice } from './money-price/money-price.mjs';
11
+ export { getActiveProviderConfig, getProductPricing } from './money-price/money-price-config-util.mjs';
12
+ export { UserState } from './money-price/money-price-types.mjs';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var coseBase$1 = require('../../../../../_virtual/cose-base2.js');
3
+ var coseBase$1 = require('../../../../../_virtual/cose-base.js');
4
4
  var layoutBase = require('../../../layout-base@1.0.2/node_modules/layout-base/layout-base.js');
5
5
 
6
6
  var coseBase = coseBase$1.__module.exports;
@@ -1,4 +1,4 @@
1
- import { __module as coseBase$1 } from '../../../../../_virtual/cose-base.mjs';
1
+ import { __module as coseBase$1 } from '../../../../../_virtual/cose-base2.mjs';
2
2
  import { __require as requireLayoutBase } from '../../../layout-base@1.0.2/node_modules/layout-base/layout-base.mjs';
3
3
 
4
4
  var coseBase = coseBase$1.exports;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var coseBase$1 = require('../../../../../_virtual/cose-base.js');
3
+ var coseBase$1 = require('../../../../../_virtual/cose-base2.js');
4
4
  var layoutBase = require('../../../layout-base@2.0.1/node_modules/layout-base/layout-base.js');
5
5
 
6
6
  var coseBase = coseBase$1.__module.exports;
@@ -1,4 +1,4 @@
1
- import { __module as coseBase$1 } from '../../../../../_virtual/cose-base2.mjs';
1
+ import { __module as coseBase$1 } from '../../../../../_virtual/cose-base.mjs';
2
2
  import { __require as requireLayoutBase } from '../../../layout-base@2.0.1/node_modules/layout-base/layout-base.mjs';
3
3
 
4
4
  var coseBase = coseBase$1.exports;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var layoutBase$1 = require('../../../../../_virtual/layout-base2.js');
3
+ var layoutBase$1 = require('../../../../../_virtual/layout-base.js');
4
4
 
5
5
  var layoutBase = layoutBase$1.__module.exports;
6
6
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var layoutBase$1 = require('../../../../../_virtual/layout-base.js');
3
+ var layoutBase$1 = require('../../../../../_virtual/layout-base2.js');
4
4
 
5
5
  var layoutBase = layoutBase$1.__module.exports;
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "7.3.2",
3
+ "version": "7.3.4",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
 
3
- import React, { createContext, useContext, useState } from 'react';
3
+ import React, { createContext, useContext, useState, useEffect, useRef } from 'react';
4
4
  import { useFingerprint } from './use-fingerprint';
5
+ import { globalLucideIcons as icons } from '@windrun-huaiin/base-ui/components/server';
5
6
  import type {
6
7
  FingerprintContextType,
7
8
  FingerprintProviderProps
@@ -78,11 +79,35 @@ export function FingerprintStatus() {
78
79
  } = useFingerprintContext();
79
80
 
80
81
  const [isOpen, setIsOpen] = useState(false);
82
+ const modalRef = useRef<HTMLDivElement>(null);
81
83
 
82
84
  const handleToggle = () => {
83
85
  setIsOpen(!isOpen);
84
86
  };
85
87
 
88
+ const handleBackdropClick = (e: React.MouseEvent) => {
89
+ if (e.target === e.currentTarget) {
90
+ setIsOpen(false);
91
+ }
92
+ };
93
+
94
+ // ESC键关闭弹框
95
+ useEffect(() => {
96
+ const handleEscKey = (e: KeyboardEvent) => {
97
+ if (e.key === 'Escape' && isOpen) {
98
+ setIsOpen(false);
99
+ }
100
+ };
101
+
102
+ if (isOpen) {
103
+ document.addEventListener('keydown', handleEscKey);
104
+ }
105
+
106
+ return () => {
107
+ document.removeEventListener('keydown', handleEscKey);
108
+ };
109
+ }, [isOpen]);
110
+
86
111
  return (
87
112
  <>
88
113
  <button
@@ -104,17 +129,20 @@ export function FingerprintStatus() {
104
129
  boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)',
105
130
  }}
106
131
  >
107
- <span style={{
108
- fontSize: '24px',
109
- color: 'white',
110
- transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',
111
- transition: 'transform 0.3s ease',
112
- }}>▼</span>
132
+ <icons.BTC
133
+ size={24}
134
+ style={{
135
+ color: 'white',
136
+ transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',
137
+ transition: 'transform 0.3s ease',
138
+ }}
139
+ />
113
140
  </button>
114
141
 
115
142
  {isOpen && (
116
143
  <>
117
144
  <div
145
+ onClick={handleBackdropClick}
118
146
  style={{
119
147
  position: 'fixed',
120
148
  top: 0,
@@ -126,6 +154,7 @@ export function FingerprintStatus() {
126
154
  }}
127
155
  />
128
156
  <div
157
+ ref={modalRef}
129
158
  style={{
130
159
  position: 'fixed',
131
160
  top: '70px',
@@ -135,7 +164,7 @@ export function FingerprintStatus() {
135
164
  borderRadius: '5px',
136
165
  fontSize: '12px',
137
166
  fontFamily: 'monospace',
138
- maxWidth: '300px',
167
+ maxWidth: '500px',
139
168
  zIndex: 9999,
140
169
  border: '1px solid #ccc',
141
170
  boxShadow: '0 4px 12px rgba(0, 0, 0, 0.2)',
@@ -158,18 +187,22 @@ export function FingerprintStatus() {
158
187
  <strong>Credits:</strong> {xCredit.balanceFree} Free + {xCredit.balancePaid} Paid = {xCredit.totalBalance} Total
159
188
  </div>
160
189
  )}
161
- {xSubscription && (
162
- <div>
163
- <strong>user_id:</strong> {xSubscription.userId} <br/>
164
- <strong>pay_subscription_id:</strong> {xSubscription.paySubscriptionId} <br/>
165
- <strong>price_id:</strong> {xSubscription.priceId || 'None'} <br/>
166
- <strong>price_name:</strong> {xSubscription.priceName || 'None'} <br/>
167
- <strong>status:</strong> {xSubscription.status || 'Free'} <br/>
168
- <strong>credits_allocated:</strong> {xSubscription.creditsAllocated || ''} <br/>
169
- <strong>sub_period_start:</strong> {xSubscription.subPeriodStart || ''} <br/>
170
- <strong>sub_period_end:</strong> {xSubscription.subPeriodEnd || ''} <br/>
171
- </div>
172
- )}
190
+ <div>
191
+ {xSubscription ? (
192
+ <>
193
+ <strong>user_id:</strong> {xSubscription.userId} <br/>
194
+ <strong>pay_subscription_id:</strong> {xSubscription.paySubscriptionId} <br/>
195
+ <strong>price_id:</strong> {xSubscription.priceId || 'None'} <br/>
196
+ <strong>price_name:</strong> {xSubscription.priceName || 'None'} <br/>
197
+ <strong>status:</strong> {xSubscription.status || 'Free'} <br/>
198
+ <strong>credits_allocated:</strong> {xSubscription.creditsAllocated || ''} <br/>
199
+ <strong>sub_period_start:</strong> {xSubscription.subPeriodStart || ''} <br/>
200
+ <strong>sub_period_end:</strong> {xSubscription.subPeriodEnd || ''} <br/>
201
+ </>
202
+ ) : (
203
+ <strong>No Subscription, Default as Hobby Plan</strong>
204
+ )}
205
+ </div>
173
206
  </div>
174
207
  </>
175
208
  )}
@@ -97,7 +97,7 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
97
97
  } finally {
98
98
  setIsLoading(false);
99
99
  }
100
- }, [fingerprintId]);
100
+ }, [fingerprintId, config.apiEndpoint]);
101
101
 
102
102
  /**
103
103
  * 刷新用户数据