@windrun-huaiin/third-ui 7.3.9 → 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 +44 -43
- package/dist/main/money-price/money-price-interactive.mjs +44 -43
- 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.mjs +1 -1
- package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.mjs +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.mjs +1 -1
- package/package.json +3 -3
- package/src/main/money-price/money-price-interactive.tsx +59 -69
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,9 +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);
|
|
238
|
-
|
|
239
|
+
updateButtonStyles(billingType);
|
|
239
240
|
return () => {
|
|
240
241
|
if (monthlyButton) {
|
|
241
242
|
monthlyButton.removeEventListener('click', handleMonthlyClick);
|
|
@@ -249,7 +250,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
249
250
|
element.removeEventListener('mouseleave', handlers.mouseleave);
|
|
250
251
|
});
|
|
251
252
|
};
|
|
252
|
-
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
|
|
253
|
+
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
|
|
253
254
|
// Tooltip 组件
|
|
254
255
|
const Tooltip = ({ show, content, x, y }) => {
|
|
255
256
|
if (!show)
|
|
@@ -6,6 +6,7 @@ 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,9 +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);
|
|
236
|
-
|
|
237
|
+
updateButtonStyles(billingType);
|
|
237
238
|
return () => {
|
|
238
239
|
if (monthlyButton) {
|
|
239
240
|
monthlyButton.removeEventListener('click', handleMonthlyClick);
|
|
@@ -247,7 +248,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
247
248
|
element.removeEventListener('mouseleave', handlers.mouseleave);
|
|
248
249
|
});
|
|
249
250
|
};
|
|
250
|
-
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
|
|
251
|
+
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
|
|
251
252
|
// Tooltip 组件
|
|
252
253
|
const Tooltip = ({ show, content, x, y }) => {
|
|
253
254
|
if (!show)
|
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,4 +1,4 @@
|
|
|
1
|
-
import { __module as coseBase$1 } from '../../../../../_virtual/cose-
|
|
1
|
+
import { __module as coseBase$1 } from '../../../../../_virtual/cose-base.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,4 +1,4 @@
|
|
|
1
|
-
import { __module as coseBase$1 } from '../../../../../_virtual/cose-
|
|
1
|
+
import { __module as coseBase$1 } from '../../../../../_virtual/cose-base2.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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "7.3.
|
|
3
|
+
"version": "7.3.10",
|
|
4
4
|
"description": "Third-party integrated UI components for windrun-huaiin projects",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -75,8 +75,8 @@
|
|
|
75
75
|
"mermaid": "^11.6.0",
|
|
76
76
|
"react-medium-image-zoom": "^5.2.14",
|
|
77
77
|
"zod": "^3.22.4",
|
|
78
|
-
"@windrun-huaiin/
|
|
79
|
-
"@windrun-huaiin/
|
|
78
|
+
"@windrun-huaiin/lib": "^7.1.2",
|
|
79
|
+
"@windrun-huaiin/base-ui": "^8.1.2"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
82
|
"react": "19.1.0",
|
|
@@ -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,23 +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);
|
|
283
|
+
updateButtonStyles(billingType);
|
|
280
284
|
|
|
281
|
-
data.plans.map((plan: any) => (
|
|
282
|
-
<div key={plan.key} data-button-placeholder={plan.key}>
|
|
283
|
-
<MoneyPriceButton
|
|
284
|
-
planKey={plan.key}
|
|
285
|
-
userContext={userContext}
|
|
286
|
-
billingType={billingType}
|
|
287
|
-
onLogin={handleLogin}
|
|
288
|
-
onUpgrade={handleUpgrade}
|
|
289
|
-
texts={data.buttonTexts}
|
|
290
|
-
isProcessing={isProcessing}
|
|
291
|
-
/>
|
|
292
|
-
</div>
|
|
293
|
-
))
|
|
294
|
-
|
|
295
285
|
return () => {
|
|
296
286
|
if (monthlyButton) {
|
|
297
287
|
monthlyButton.removeEventListener('click', handleMonthlyClick);
|
|
@@ -306,7 +296,7 @@ export function MoneyPriceInteractive({
|
|
|
306
296
|
element.removeEventListener('mouseleave', handlers.mouseleave);
|
|
307
297
|
});
|
|
308
298
|
};
|
|
309
|
-
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
|
|
299
|
+
}, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
|
|
310
300
|
|
|
311
301
|
// Tooltip 组件
|
|
312
302
|
const Tooltip = ({ show, content, x, y }: typeof tooltip) => {
|
|
@@ -331,5 +321,5 @@ export function MoneyPriceInteractive({
|
|
|
331
321
|
);
|
|
332
322
|
};
|
|
333
323
|
|
|
334
|
-
return <Tooltip {...tooltip}
|
|
324
|
+
return <Tooltip {...tooltip} />;
|
|
335
325
|
}
|