@windrun-huaiin/third-ui 7.3.8 → 7.3.10
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/dist/main/faq.js +1 -0
- package/dist/main/faq.mjs +1 -0
- package/dist/main/gallery.js +1 -0
- package/dist/main/gallery.mjs +1 -0
- package/dist/main/money-price/money-price-interactive.js +45 -44
- package/dist/main/money-price/money-price-interactive.mjs +46 -45
- package/dist/main/price-plan.js +1 -0
- package/dist/main/price-plan.mjs +1 -0
- package/dist/node_modules/.pnpm/cose-base@1.0.3/node_modules/cose-base/cose-base.js +1 -1
- package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.js +1 -1
- package/dist/node_modules/.pnpm/layout-base@1.0.2/node_modules/layout-base/layout-base.js +1 -1
- package/dist/node_modules/.pnpm/layout-base@1.0.2/node_modules/layout-base/layout-base.mjs +1 -1
- package/dist/node_modules/.pnpm/layout-base@2.0.1/node_modules/layout-base/layout-base.js +1 -1
- package/dist/node_modules/.pnpm/layout-base@2.0.1/node_modules/layout-base/layout-base.mjs +1 -1
- package/package.json +1 -1
- package/src/main/money-price/money-price-interactive.tsx +60 -74
package/dist/main/faq.js
CHANGED
|
@@ -14,6 +14,7 @@ var faqInteractive = require('./faq-interactive.js');
|
|
|
14
14
|
require('next/navigation');
|
|
15
15
|
require('@clerk/nextjs');
|
|
16
16
|
require('../clerk/fingerprint/fingerprint-provider.js');
|
|
17
|
+
require('react-dom');
|
|
17
18
|
require('next-themes');
|
|
18
19
|
require('fumadocs-core/framework');
|
|
19
20
|
require('next/link');
|
package/dist/main/faq.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import { FAQInteractive } from './faq-interactive.mjs';
|
|
|
12
12
|
import 'next/navigation';
|
|
13
13
|
import '@clerk/nextjs';
|
|
14
14
|
import '../clerk/fingerprint/fingerprint-provider.mjs';
|
|
15
|
+
import 'react-dom';
|
|
15
16
|
import 'next-themes';
|
|
16
17
|
import 'fumadocs-core/framework';
|
|
17
18
|
import 'next/link';
|
package/dist/main/gallery.js
CHANGED
|
@@ -14,6 +14,7 @@ require('next/navigation');
|
|
|
14
14
|
var galleryInteractive = require('./gallery-interactive.js');
|
|
15
15
|
require('@clerk/nextjs');
|
|
16
16
|
require('../clerk/fingerprint/fingerprint-provider.js');
|
|
17
|
+
require('react-dom');
|
|
17
18
|
require('next-themes');
|
|
18
19
|
require('fumadocs-core/framework');
|
|
19
20
|
require('next/link');
|
package/dist/main/gallery.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import 'next/navigation';
|
|
|
12
12
|
import { GalleryInteractive } from './gallery-interactive.mjs';
|
|
13
13
|
import '@clerk/nextjs';
|
|
14
14
|
import '../clerk/fingerprint/fingerprint-provider.mjs';
|
|
15
|
+
import 'react-dom';
|
|
15
16
|
import 'next-themes';
|
|
16
17
|
import 'fumadocs-core/framework';
|
|
17
18
|
import 'next/link';
|
|
@@ -8,6 +8,7 @@ var React = require('react');
|
|
|
8
8
|
var fingerprintProvider = require('../../clerk/fingerprint/fingerprint-provider.js');
|
|
9
9
|
var utils = require('@windrun-huaiin/lib/utils');
|
|
10
10
|
var navigation = require('next/navigation');
|
|
11
|
+
var ReactDOM = require('react-dom');
|
|
11
12
|
var moneyPriceButton = require('./money-price-button.js');
|
|
12
13
|
var moneyPriceConfigUtil = require('./money-price-config-util.js');
|
|
13
14
|
var moneyPriceTypes = require('./money-price-types.js');
|
|
@@ -131,55 +132,47 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
131
132
|
if (priceDiscountElement)
|
|
132
133
|
priceDiscountElement.style.display = 'none';
|
|
133
134
|
}
|
|
134
|
-
const priceSubtitleElement = document.querySelector(`[data-price-subtitle="${plan.key}"]`);
|
|
135
|
-
if (priceSubtitleElement && plan.showBillingSubTitle !== false) {
|
|
136
|
-
const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
|
|
137
|
-
priceSubtitleElement.textContent = (billingOption === null || billingOption === void 0 ? void 0 : billingOption.subTitle) || '';
|
|
138
|
-
}
|
|
139
135
|
});
|
|
140
136
|
}, [config, data]);
|
|
141
|
-
// 更新按钮样式
|
|
142
|
-
const updateButtonStyles = React.useCallback((newBillingType) => {
|
|
143
|
-
const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
|
|
144
|
-
const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
|
|
145
|
-
const activeClasses = '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';
|
|
146
|
-
const inactiveClasses = 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
|
|
147
|
-
if (monthlyButton && yearlyButton) {
|
|
148
|
-
if (newBillingType === 'monthly') {
|
|
149
|
-
monthlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
|
|
150
|
-
yearlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
monthlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
|
|
154
|
-
yearlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}, []);
|
|
158
137
|
// 更新折扣信息
|
|
159
138
|
const updateDiscountInfo = React.useCallback((newBillingType) => {
|
|
160
139
|
const discountInfoElement = document.querySelector('[data-discount-info]');
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
140
|
+
if (discountInfoElement) {
|
|
141
|
+
const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
|
|
142
|
+
let hasDiscount = false;
|
|
143
|
+
let discountPercent = 0;
|
|
144
|
+
const providerConfig = moneyPriceConfigUtil.getActiveProviderConfig(config);
|
|
145
|
+
['pro', 'ultra'].forEach(planKey => {
|
|
146
|
+
const pricing = providerConfig.products[planKey].plans[newBillingType];
|
|
147
|
+
if (pricing.discountPercent) {
|
|
148
|
+
hasDiscount = true;
|
|
149
|
+
discountPercent = pricing.discountPercent;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
discountInfoElement.innerHTML = '';
|
|
153
|
+
if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
|
|
154
|
+
const discountBadge = document.createElement('span');
|
|
155
|
+
discountBadge.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';
|
|
156
|
+
discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
|
|
157
|
+
discountInfoElement.appendChild(discountBadge);
|
|
173
158
|
}
|
|
174
|
-
});
|
|
175
|
-
discountInfoElement.innerHTML = '';
|
|
176
|
-
if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
|
|
177
|
-
const discountBadge = document.createElement('span');
|
|
178
|
-
discountBadge.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';
|
|
179
|
-
discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
|
|
180
|
-
discountInfoElement.appendChild(discountBadge);
|
|
181
159
|
}
|
|
182
160
|
}, [config, data]);
|
|
161
|
+
// 更新按钮样式
|
|
162
|
+
const updateButtonStyles = React.useCallback((newBillingType) => {
|
|
163
|
+
const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
|
|
164
|
+
const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
|
|
165
|
+
if (monthlyButton) {
|
|
166
|
+
monthlyButton.className = newBillingType === 'monthly'
|
|
167
|
+
? utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', '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')
|
|
168
|
+
: utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
|
|
169
|
+
}
|
|
170
|
+
if (yearlyButton) {
|
|
171
|
+
yearlyButton.className = newBillingType === 'yearly'
|
|
172
|
+
? utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', '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')
|
|
173
|
+
: utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
|
|
174
|
+
}
|
|
175
|
+
}, []);
|
|
183
176
|
// 处理月付/年付切换和 tooltip 功能
|
|
184
177
|
React.useEffect(() => {
|
|
185
178
|
const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
|
|
@@ -233,8 +226,17 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
233
226
|
}
|
|
234
227
|
});
|
|
235
228
|
});
|
|
229
|
+
// Inject buttons into placeholders using createPortal
|
|
230
|
+
data.plans.forEach((plan) => {
|
|
231
|
+
const placeholder = document.querySelector(`[data-button-placeholder="${plan.key}"]`);
|
|
232
|
+
if (placeholder) {
|
|
233
|
+
ReactDOM.createPortal(jsxRuntime.jsx(moneyPriceButton.MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }), placeholder);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
// Initial updates
|
|
236
237
|
updatePriceDisplay(billingType);
|
|
237
238
|
updateDiscountInfo(billingType);
|
|
239
|
+
updateButtonStyles(billingType);
|
|
238
240
|
return () => {
|
|
239
241
|
if (monthlyButton) {
|
|
240
242
|
monthlyButton.removeEventListener('click', handleMonthlyClick);
|
|
@@ -248,7 +250,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
248
250
|
element.removeEventListener('mouseleave', handlers.mouseleave);
|
|
249
251
|
});
|
|
250
252
|
};
|
|
251
|
-
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
|
|
253
|
+
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
|
|
252
254
|
// Tooltip 组件
|
|
253
255
|
const Tooltip = ({ show, content, x, y }) => {
|
|
254
256
|
if (!show)
|
|
@@ -265,8 +267,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
265
267
|
};
|
|
266
268
|
return (jsxRuntime.jsx("div", { style: style, className: "bg-gray-700 dark:bg-gray-200 text-gray-100 dark:text-gray-800 text-xs leading-relaxed px-3 py-2 rounded-lg shadow-lg border border-gray-300 dark:border-gray-600 backdrop-blur-sm", children: content }));
|
|
267
269
|
};
|
|
268
|
-
|
|
269
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [data.plans.map((plan) => (jsxRuntime.jsx("div", { "data-button-placeholder": plan.key, children: jsxRuntime.jsx(moneyPriceButton.MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }) }, plan.key))), jsxRuntime.jsx(Tooltip, Object.assign({}, tooltip))] }));
|
|
270
|
+
return jsxRuntime.jsx(Tooltip, Object.assign({}, tooltip));
|
|
270
271
|
}
|
|
271
272
|
|
|
272
273
|
exports.MoneyPriceInteractive = MoneyPriceInteractive;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
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';
|
|
3
|
-
import {
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
4
|
import { useClerk } from '@clerk/nextjs';
|
|
5
5
|
import { useState, useCallback, useMemo, useEffect } from 'react';
|
|
6
6
|
import { useFingerprintContextSafe } from '../../clerk/fingerprint/fingerprint-provider.mjs';
|
|
7
7
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
8
8
|
import { useRouter } from 'next/navigation';
|
|
9
|
+
import { createPortal } from 'react-dom';
|
|
9
10
|
import { MoneyPriceButton } from './money-price-button.mjs';
|
|
10
11
|
import { getActiveProviderConfig, getProductPricing } from './money-price-config-util.mjs';
|
|
11
12
|
import { UserState } from './money-price-types.mjs';
|
|
@@ -129,55 +130,47 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
129
130
|
if (priceDiscountElement)
|
|
130
131
|
priceDiscountElement.style.display = 'none';
|
|
131
132
|
}
|
|
132
|
-
const priceSubtitleElement = document.querySelector(`[data-price-subtitle="${plan.key}"]`);
|
|
133
|
-
if (priceSubtitleElement && plan.showBillingSubTitle !== false) {
|
|
134
|
-
const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
|
|
135
|
-
priceSubtitleElement.textContent = (billingOption === null || billingOption === void 0 ? void 0 : billingOption.subTitle) || '';
|
|
136
|
-
}
|
|
137
133
|
});
|
|
138
134
|
}, [config, data]);
|
|
139
|
-
// 更新按钮样式
|
|
140
|
-
const updateButtonStyles = useCallback((newBillingType) => {
|
|
141
|
-
const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
|
|
142
|
-
const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
|
|
143
|
-
const activeClasses = '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';
|
|
144
|
-
const inactiveClasses = 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
|
|
145
|
-
if (monthlyButton && yearlyButton) {
|
|
146
|
-
if (newBillingType === 'monthly') {
|
|
147
|
-
monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
|
|
148
|
-
yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
|
|
152
|
-
yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}, []);
|
|
156
135
|
// 更新折扣信息
|
|
157
136
|
const updateDiscountInfo = useCallback((newBillingType) => {
|
|
158
137
|
const discountInfoElement = document.querySelector('[data-discount-info]');
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
138
|
+
if (discountInfoElement) {
|
|
139
|
+
const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
|
|
140
|
+
let hasDiscount = false;
|
|
141
|
+
let discountPercent = 0;
|
|
142
|
+
const providerConfig = getActiveProviderConfig(config);
|
|
143
|
+
['pro', 'ultra'].forEach(planKey => {
|
|
144
|
+
const pricing = providerConfig.products[planKey].plans[newBillingType];
|
|
145
|
+
if (pricing.discountPercent) {
|
|
146
|
+
hasDiscount = true;
|
|
147
|
+
discountPercent = pricing.discountPercent;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
discountInfoElement.innerHTML = '';
|
|
151
|
+
if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
|
|
152
|
+
const discountBadge = document.createElement('span');
|
|
153
|
+
discountBadge.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';
|
|
154
|
+
discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
|
|
155
|
+
discountInfoElement.appendChild(discountBadge);
|
|
171
156
|
}
|
|
172
|
-
});
|
|
173
|
-
discountInfoElement.innerHTML = '';
|
|
174
|
-
if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
|
|
175
|
-
const discountBadge = document.createElement('span');
|
|
176
|
-
discountBadge.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';
|
|
177
|
-
discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
|
|
178
|
-
discountInfoElement.appendChild(discountBadge);
|
|
179
157
|
}
|
|
180
158
|
}, [config, data]);
|
|
159
|
+
// 更新按钮样式
|
|
160
|
+
const updateButtonStyles = useCallback((newBillingType) => {
|
|
161
|
+
const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
|
|
162
|
+
const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
|
|
163
|
+
if (monthlyButton) {
|
|
164
|
+
monthlyButton.className = newBillingType === 'monthly'
|
|
165
|
+
? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', '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')
|
|
166
|
+
: cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
|
|
167
|
+
}
|
|
168
|
+
if (yearlyButton) {
|
|
169
|
+
yearlyButton.className = newBillingType === 'yearly'
|
|
170
|
+
? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', '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')
|
|
171
|
+
: cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
|
|
172
|
+
}
|
|
173
|
+
}, []);
|
|
181
174
|
// 处理月付/年付切换和 tooltip 功能
|
|
182
175
|
useEffect(() => {
|
|
183
176
|
const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
|
|
@@ -231,8 +224,17 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
231
224
|
}
|
|
232
225
|
});
|
|
233
226
|
});
|
|
227
|
+
// Inject buttons into placeholders using createPortal
|
|
228
|
+
data.plans.forEach((plan) => {
|
|
229
|
+
const placeholder = document.querySelector(`[data-button-placeholder="${plan.key}"]`);
|
|
230
|
+
if (placeholder) {
|
|
231
|
+
createPortal(jsx(MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }), placeholder);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
// Initial updates
|
|
234
235
|
updatePriceDisplay(billingType);
|
|
235
236
|
updateDiscountInfo(billingType);
|
|
237
|
+
updateButtonStyles(billingType);
|
|
236
238
|
return () => {
|
|
237
239
|
if (monthlyButton) {
|
|
238
240
|
monthlyButton.removeEventListener('click', handleMonthlyClick);
|
|
@@ -246,7 +248,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
246
248
|
element.removeEventListener('mouseleave', handlers.mouseleave);
|
|
247
249
|
});
|
|
248
250
|
};
|
|
249
|
-
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
|
|
251
|
+
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
|
|
250
252
|
// Tooltip 组件
|
|
251
253
|
const Tooltip = ({ show, content, x, y }) => {
|
|
252
254
|
if (!show)
|
|
@@ -263,8 +265,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
263
265
|
};
|
|
264
266
|
return (jsx("div", { style: style, className: "bg-gray-700 dark:bg-gray-200 text-gray-100 dark:text-gray-800 text-xs leading-relaxed px-3 py-2 rounded-lg shadow-lg border border-gray-300 dark:border-gray-600 backdrop-blur-sm", children: content }));
|
|
265
267
|
};
|
|
266
|
-
|
|
267
|
-
return (jsxs(Fragment, { children: [data.plans.map((plan) => (jsx("div", { "data-button-placeholder": plan.key, children: jsx(MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }) }, plan.key))), jsx(Tooltip, Object.assign({}, tooltip))] }));
|
|
268
|
+
return jsx(Tooltip, Object.assign({}, tooltip));
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
export { MoneyPriceInteractive };
|
package/dist/main/price-plan.js
CHANGED
|
@@ -14,6 +14,7 @@ var pricePlanInteractive = require('./price-plan-interactive.js');
|
|
|
14
14
|
require('@clerk/nextjs');
|
|
15
15
|
require('../clerk/fingerprint/fingerprint-provider.js');
|
|
16
16
|
require('next/navigation');
|
|
17
|
+
require('react-dom');
|
|
17
18
|
require('next-themes');
|
|
18
19
|
require('fumadocs-core/framework');
|
|
19
20
|
require('next/link');
|
package/dist/main/price-plan.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import { PricePlanInteractive } from './price-plan-interactive.mjs';
|
|
|
12
12
|
import '@clerk/nextjs';
|
|
13
13
|
import '../clerk/fingerprint/fingerprint-provider.mjs';
|
|
14
14
|
import 'next/navigation';
|
|
15
|
+
import 'react-dom';
|
|
15
16
|
import 'next-themes';
|
|
16
17
|
import 'fumadocs-core/framework';
|
|
17
18
|
import 'next/link';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var coseBase$1 = require('../../../../../_virtual/cose-
|
|
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,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var coseBase$1 = require('../../../../../_virtual/cose-
|
|
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;
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import { useFingerprintContextSafe } from '@third-ui/clerk/fingerprint';
|
|
|
5
5
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
6
6
|
import { useRouter } from 'next/navigation';
|
|
7
7
|
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
|
8
|
+
import { createPortal } from 'react-dom';
|
|
8
9
|
import { MoneyPriceButton } from './money-price-button';
|
|
9
10
|
import { getActiveProviderConfig, getProductPricing } from './money-price-config-util';
|
|
10
11
|
import {
|
|
@@ -130,7 +131,6 @@ export function MoneyPriceInteractive({
|
|
|
130
131
|
|
|
131
132
|
const priceOriginalElement = document.querySelector(`[data-price-original="${plan.key}"]`) as HTMLElement;
|
|
132
133
|
const priceDiscountElement = document.querySelector(`[data-price-discount="${plan.key}"]`) as HTMLElement;
|
|
133
|
-
|
|
134
134
|
if (pricing.originalAmount && pricing.discountPercent) {
|
|
135
135
|
if (priceOriginalElement) {
|
|
136
136
|
priceOriginalElement.style.display = 'inline';
|
|
@@ -140,74 +140,57 @@ export function MoneyPriceInteractive({
|
|
|
140
140
|
priceDiscountElement.style.display = 'inline';
|
|
141
141
|
const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
|
|
142
142
|
if (billingOption?.discountText) {
|
|
143
|
-
priceDiscountElement.textContent = billingOption.discountText.replace(
|
|
144
|
-
'{percent}',
|
|
145
|
-
String(pricing.discountPercent)
|
|
146
|
-
);
|
|
143
|
+
priceDiscountElement.textContent = billingOption.discountText.replace('{percent}', String(pricing.discountPercent));
|
|
147
144
|
}
|
|
148
145
|
}
|
|
149
146
|
} else {
|
|
150
147
|
if (priceOriginalElement) priceOriginalElement.style.display = 'none';
|
|
151
148
|
if (priceDiscountElement) priceDiscountElement.style.display = 'none';
|
|
152
149
|
}
|
|
153
|
-
|
|
154
|
-
const priceSubtitleElement = document.querySelector(`[data-price-subtitle="${plan.key}"]`) as HTMLElement;
|
|
155
|
-
if (priceSubtitleElement && plan.showBillingSubTitle !== false) {
|
|
156
|
-
const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
|
|
157
|
-
priceSubtitleElement.textContent = billingOption?.subTitle || '';
|
|
158
|
-
}
|
|
159
150
|
});
|
|
160
151
|
}, [config, data]);
|
|
161
152
|
|
|
162
|
-
// 更新按钮样式
|
|
163
|
-
const updateButtonStyles = useCallback((newBillingType: string) => {
|
|
164
|
-
const monthlyButton = document.querySelector('[data-billing-button="monthly"]') as HTMLButtonElement;
|
|
165
|
-
const yearlyButton = document.querySelector('[data-billing-button="yearly"]') as HTMLButtonElement;
|
|
166
|
-
|
|
167
|
-
const activeClasses = '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';
|
|
168
|
-
const inactiveClasses = 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
|
|
169
|
-
|
|
170
|
-
if (monthlyButton && yearlyButton) {
|
|
171
|
-
if (newBillingType === 'monthly') {
|
|
172
|
-
monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
|
|
173
|
-
yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
|
|
174
|
-
} else {
|
|
175
|
-
monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
|
|
176
|
-
yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}, []);
|
|
180
|
-
|
|
181
153
|
// 更新折扣信息
|
|
182
154
|
const updateDiscountInfo = useCallback((newBillingType: string) => {
|
|
183
155
|
const discountInfoElement = document.querySelector('[data-discount-info]') as HTMLElement;
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
156
|
+
if (discountInfoElement) {
|
|
157
|
+
const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
|
|
158
|
+
let hasDiscount = false;
|
|
159
|
+
let discountPercent = 0;
|
|
160
|
+
const providerConfig = getActiveProviderConfig(config);
|
|
161
|
+
['pro', 'ultra'].forEach(planKey => {
|
|
162
|
+
const pricing = providerConfig.products[planKey as 'pro' | 'ultra'].plans[newBillingType as 'monthly' | 'yearly'];
|
|
163
|
+
if (pricing.discountPercent) {
|
|
164
|
+
hasDiscount = true;
|
|
165
|
+
discountPercent = pricing.discountPercent;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
discountInfoElement.innerHTML = '';
|
|
169
|
+
if (hasDiscount && billingOption?.discountText) {
|
|
170
|
+
const discountBadge = document.createElement('span');
|
|
171
|
+
discountBadge.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';
|
|
172
|
+
discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
|
|
173
|
+
discountInfoElement.appendChild(discountBadge);
|
|
198
174
|
}
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
discountInfoElement.innerHTML = '';
|
|
202
|
-
|
|
203
|
-
if (hasDiscount && billingOption?.discountText) {
|
|
204
|
-
const discountBadge = document.createElement('span');
|
|
205
|
-
discountBadge.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';
|
|
206
|
-
discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
|
|
207
|
-
discountInfoElement.appendChild(discountBadge);
|
|
208
175
|
}
|
|
209
176
|
}, [config, data]);
|
|
210
177
|
|
|
178
|
+
// 更新按钮样式
|
|
179
|
+
const updateButtonStyles = useCallback((newBillingType: string) => {
|
|
180
|
+
const monthlyButton = document.querySelector('[data-billing-button="monthly"]') as HTMLElement;
|
|
181
|
+
const yearlyButton = document.querySelector('[data-billing-button="yearly"]') as HTMLElement;
|
|
182
|
+
if (monthlyButton) {
|
|
183
|
+
monthlyButton.className = newBillingType === 'monthly'
|
|
184
|
+
? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', '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')
|
|
185
|
+
: cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
|
|
186
|
+
}
|
|
187
|
+
if (yearlyButton) {
|
|
188
|
+
yearlyButton.className = newBillingType === 'yearly'
|
|
189
|
+
? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', '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')
|
|
190
|
+
: cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
|
|
191
|
+
}
|
|
192
|
+
}, []);
|
|
193
|
+
|
|
211
194
|
// 处理月付/年付切换和 tooltip 功能
|
|
212
195
|
useEffect(() => {
|
|
213
196
|
const monthlyButton = document.querySelector('[data-billing-button="monthly"]') as HTMLButtonElement;
|
|
@@ -275,9 +258,30 @@ export function MoneyPriceInteractive({
|
|
|
275
258
|
});
|
|
276
259
|
});
|
|
277
260
|
|
|
261
|
+
// Inject buttons into placeholders using createPortal
|
|
262
|
+
data.plans.forEach((plan: any) => {
|
|
263
|
+
const placeholder = document.querySelector(`[data-button-placeholder="${plan.key}"]`) as HTMLElement;
|
|
264
|
+
if (placeholder) {
|
|
265
|
+
createPortal(
|
|
266
|
+
<MoneyPriceButton
|
|
267
|
+
planKey={plan.key}
|
|
268
|
+
userContext={userContext}
|
|
269
|
+
billingType={billingType}
|
|
270
|
+
onLogin={handleLogin}
|
|
271
|
+
onUpgrade={handleUpgrade}
|
|
272
|
+
texts={data.buttonTexts}
|
|
273
|
+
isProcessing={isProcessing}
|
|
274
|
+
/>,
|
|
275
|
+
placeholder
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// Initial updates
|
|
278
281
|
updatePriceDisplay(billingType);
|
|
279
282
|
updateDiscountInfo(billingType);
|
|
280
|
-
|
|
283
|
+
updateButtonStyles(billingType);
|
|
284
|
+
|
|
281
285
|
return () => {
|
|
282
286
|
if (monthlyButton) {
|
|
283
287
|
monthlyButton.removeEventListener('click', handleMonthlyClick);
|
|
@@ -292,7 +296,7 @@ export function MoneyPriceInteractive({
|
|
|
292
296
|
element.removeEventListener('mouseleave', handlers.mouseleave);
|
|
293
297
|
});
|
|
294
298
|
};
|
|
295
|
-
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
|
|
299
|
+
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
|
|
296
300
|
|
|
297
301
|
// Tooltip 组件
|
|
298
302
|
const Tooltip = ({ show, content, x, y }: typeof tooltip) => {
|
|
@@ -317,23 +321,5 @@ export function MoneyPriceInteractive({
|
|
|
317
321
|
);
|
|
318
322
|
};
|
|
319
323
|
|
|
320
|
-
|
|
321
|
-
return (
|
|
322
|
-
<>
|
|
323
|
-
{data.plans.map((plan: any) => (
|
|
324
|
-
<div key={plan.key} data-button-placeholder={plan.key}>
|
|
325
|
-
<MoneyPriceButton
|
|
326
|
-
planKey={plan.key}
|
|
327
|
-
userContext={userContext}
|
|
328
|
-
billingType={billingType}
|
|
329
|
-
onLogin={handleLogin}
|
|
330
|
-
onUpgrade={handleUpgrade}
|
|
331
|
-
texts={data.buttonTexts}
|
|
332
|
-
isProcessing={isProcessing}
|
|
333
|
-
/>
|
|
334
|
-
</div>
|
|
335
|
-
))}
|
|
336
|
-
<Tooltip {...tooltip} />
|
|
337
|
-
</>
|
|
338
|
-
);
|
|
324
|
+
return <Tooltip {...tooltip} />;
|
|
339
325
|
}
|