@windrun-huaiin/third-ui 30.0.0 → 31.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -143
- package/dist/ai/ai-prompt-textarea.js +5 -5
- package/dist/ai/ai-prompt-textarea.mjs +5 -5
- package/dist/clerk/clerk-auth-appearance.d.ts +13 -0
- package/dist/clerk/clerk-auth-appearance.js +19 -0
- package/dist/clerk/clerk-auth-appearance.mjs +15 -0
- package/dist/clerk/clerk-auth-modal-appearance.d.ts +12 -0
- package/dist/clerk/clerk-auth-modal-appearance.js +17 -0
- package/dist/clerk/clerk-auth-modal-appearance.mjs +14 -0
- package/dist/clerk/clerk-page-context-generator.js +3 -3
- package/dist/clerk/clerk-page-context-generator.mjs +3 -3
- package/dist/clerk/clerk-page-generator.js +4 -4
- package/dist/clerk/clerk-page-generator.mjs +4 -4
- package/dist/clerk/clerk-user-client.js +2 -1
- package/dist/clerk/clerk-user-client.mjs +2 -1
- package/dist/clerk/fingerprint/fingerprint-client.d.ts +10 -10
- package/dist/clerk/fingerprint/fingerprint-client.js +20 -20
- package/dist/clerk/fingerprint/fingerprint-client.mjs +20 -20
- package/dist/clerk/fingerprint/fingerprint-provider.d.ts +3 -3
- package/dist/clerk/fingerprint/fingerprint-provider.js +8 -8
- package/dist/clerk/fingerprint/fingerprint-provider.mjs +8 -8
- package/dist/clerk/fingerprint/fingerprint-server.d.ts +12 -12
- package/dist/clerk/fingerprint/fingerprint-server.js +17 -17
- package/dist/clerk/fingerprint/fingerprint-server.mjs +17 -17
- package/dist/clerk/fingerprint/fingerprint-shared.d.ts +3 -3
- package/dist/clerk/fingerprint/fingerprint-shared.js +10 -10
- package/dist/clerk/fingerprint/fingerprint-shared.mjs +10 -10
- package/dist/clerk/fingerprint/types.d.ts +0 -1
- package/dist/clerk/fingerprint/use-fingerprint.js +7 -7
- package/dist/clerk/fingerprint/use-fingerprint.mjs +7 -7
- package/dist/clerk/signin-with-fingerprint-client.d.ts +2 -2
- package/dist/clerk/signin-with-fingerprint-client.js +7 -6
- package/dist/clerk/signin-with-fingerprint-client.mjs +7 -6
- package/dist/clerk/signup-button-with-fingerprint-client.js +6 -4
- package/dist/clerk/signup-button-with-fingerprint-client.mjs +6 -4
- package/dist/clerk/signup-with-fingerprint-client.d.ts +2 -2
- package/dist/clerk/signup-with-fingerprint-client.js +7 -6
- package/dist/clerk/signup-with-fingerprint-client.mjs +7 -6
- package/dist/fuma/fuma-page-genarator.d.ts +2 -6
- package/dist/fuma/fuma-page-genarator.js +3 -2
- package/dist/fuma/fuma-page-genarator.mjs +3 -2
- package/dist/fuma/heavy/mermaid.js +1 -1
- package/dist/fuma/heavy/mermaid.mjs +1 -1
- package/dist/fuma/site-x.js +0 -1
- package/dist/fuma/site-x.mjs +0 -1
- package/dist/main/404-page.d.ts +12 -0
- package/dist/main/404-page.js +66 -0
- package/dist/main/404-page.mjs +64 -0
- package/dist/main/anime/anime-404-page.d.ts +14 -0
- package/dist/main/anime/anime-404-page.js +197 -0
- package/dist/main/anime/anime-404-page.mjs +195 -0
- package/dist/main/anime/anime-not-found-page.d.ts +7 -0
- package/dist/main/anime/anime-not-found-page.js +142 -0
- package/dist/main/anime/anime-not-found-page.mjs +140 -0
- package/dist/main/anime/index.d.ts +1 -0
- package/dist/main/anime/index.js +2 -0
- package/dist/main/anime/index.mjs +1 -0
- package/dist/main/calendar/calendar-date-range-input.js +1 -1
- package/dist/main/calendar/calendar-date-range-input.mjs +1 -1
- package/dist/main/credit/types.d.ts +8 -8
- package/dist/main/index.d.ts +1 -0
- package/dist/main/index.js +2 -0
- package/dist/main/index.mjs +1 -0
- package/dist/main/money-price/index.d.ts +1 -1
- package/dist/main/money-price/money-price-button.js +10 -10
- package/dist/main/money-price/money-price-button.mjs +10 -10
- package/dist/main/money-price/money-price-config-util.d.ts +30 -30
- package/dist/main/money-price/money-price-config-util.js +48 -48
- package/dist/main/money-price/money-price-config-util.mjs +48 -48
- package/dist/main/money-price/money-price-interactive.js +30 -18
- package/dist/main/money-price/money-price-interactive.mjs +30 -18
- package/dist/main/money-price/money-price-types.d.ts +7 -1
- package/dist/main/money-price/money-price-types.js +2 -2
- package/dist/main/money-price/money-price-types.mjs +2 -2
- package/dist/main/money-price/server.d.ts +1 -1
- package/dist/main/motion/creative-left-panel.d.ts +7 -0
- package/dist/main/motion/creative-left-panel.js +11 -0
- package/dist/main/motion/creative-left-panel.mjs +9 -0
- package/dist/main/motion/creative-right-panel.d.ts +7 -0
- package/dist/main/motion/creative-right-panel.js +11 -0
- package/dist/main/motion/creative-right-panel.mjs +9 -0
- package/dist/main/pill-select/x-pill-select.js +2 -2
- package/dist/main/pill-select/x-pill-select.mjs +2 -2
- package/dist/main/server.d.ts +1 -1
- package/dist/main/snake-loading-frame.js +1 -0
- package/dist/main/snake-loading-frame.mjs +1 -0
- package/package.json +13 -7
- package/src/ai/ai-prompt-textarea.tsx +6 -6
- package/src/clerk/clerk-auth-appearance.ts +16 -0
- package/src/clerk/clerk-page-context-generator.tsx +3 -5
- package/src/clerk/clerk-page-generator.tsx +9 -8
- package/src/clerk/clerk-user-client.tsx +14 -5
- package/src/clerk/fingerprint/fingerprint-client.ts +20 -20
- package/src/clerk/fingerprint/fingerprint-provider.tsx +11 -11
- package/src/clerk/fingerprint/fingerprint-server.ts +17 -17
- package/src/clerk/fingerprint/fingerprint-shared.ts +10 -10
- package/src/clerk/fingerprint/types.ts +0 -1
- package/src/clerk/fingerprint/use-fingerprint.ts +7 -7
- package/src/clerk/signin-with-fingerprint-client.tsx +7 -7
- package/src/clerk/signup-button-with-fingerprint-client.tsx +7 -5
- package/src/clerk/signup-with-fingerprint-client.tsx +7 -7
- package/src/fuma/base/custom-home-layout.tsx +4 -4
- package/src/fuma/fuma-page-genarator.tsx +2 -22
- package/src/fuma/heavy/mermaid.tsx +1 -1
- package/src/fuma/site-x.tsx +0 -1
- package/src/main/404-page.tsx +162 -0
- package/src/main/anime/anime-404-page.tsx +344 -0
- package/src/main/anime/index.ts +1 -0
- package/src/main/calendar/calendar-date-range-input.tsx +1 -1
- package/src/main/credit/types.ts +8 -8
- package/src/main/gallery/gallery-mobile-swiper.tsx +0 -1
- package/src/main/gallery/gallery-server.tsx +2 -2
- package/src/main/index.ts +1 -0
- package/src/main/money-price/index.ts +2 -0
- package/src/main/money-price/money-price-button.tsx +10 -10
- package/src/main/money-price/money-price-config-util.ts +49 -49
- package/src/main/money-price/money-price-interactive.tsx +40 -20
- package/src/main/money-price/money-price-types.ts +21 -14
- package/src/main/money-price/server.ts +2 -0
- package/src/main/pill-select/x-pill-select.tsx +2 -2
- package/src/main/server.ts +3 -1
- package/src/styles/third-ui.css +8 -0
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Money Price Configuration
|
|
3
|
-
*
|
|
3
|
+
* Pricing component configuration.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { MoneyPriceConfig, PaymentProviderConfig, EnhancePricePlan } from './money-price-types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Get the currently active payment provider configuration.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
11
|
+
* Security design:
|
|
12
|
+
* - The utility layer extracts the active provider configuration from the config.
|
|
13
|
+
* - Only the extracted result is returned; the full config structure is not exposed.
|
|
14
|
+
* - Application-level wrappers hide the config object from callers.
|
|
15
15
|
*
|
|
16
|
-
* @param config - MoneyPriceConfig
|
|
17
|
-
* @returns
|
|
16
|
+
* @param config - MoneyPriceConfig object provided by the application layer.
|
|
17
|
+
* @returns The currently active payment provider configuration.
|
|
18
18
|
*/
|
|
19
19
|
export function getActiveProviderConfigUtil(config: MoneyPriceConfig): PaymentProviderConfig {
|
|
20
20
|
const provider = config.activeProvider;
|
|
21
21
|
return config.paymentProviders[provider];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
//
|
|
24
|
+
// Helper: get pricing information for a specific product.
|
|
25
25
|
export function getProductPricing(
|
|
26
26
|
productKey: 'F1' | 'P2' | 'U3',
|
|
27
27
|
billingType: string,
|
|
@@ -30,10 +30,10 @@ export function getProductPricing(
|
|
|
30
30
|
): EnhancePricePlan {
|
|
31
31
|
const providerConfig = config.paymentProviders[provider];
|
|
32
32
|
|
|
33
|
-
//
|
|
33
|
+
// For one-time billing, try to resolve pricing from credit packs.
|
|
34
34
|
if (billingType === 'onetime') {
|
|
35
35
|
const creditPacks = providerConfig.creditPackProducts;
|
|
36
|
-
//
|
|
36
|
+
// Use the same product key directly: F1 -> F1, P2 -> P2, U3 -> U3.
|
|
37
37
|
if (creditPacks && creditPacks[productKey]) {
|
|
38
38
|
const pack = creditPacks[productKey];
|
|
39
39
|
return {
|
|
@@ -45,7 +45,7 @@ export function getProductPricing(
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
//
|
|
48
|
+
// Otherwise resolve pricing from subscription products.
|
|
49
49
|
const products = providerConfig.subscriptionProducts || providerConfig.products;
|
|
50
50
|
if (products && products[productKey] && products[productKey].plans[billingType]) {
|
|
51
51
|
return products[productKey].plans[billingType];
|
|
@@ -54,19 +54,19 @@ export function getProductPricing(
|
|
|
54
54
|
throw new Error(`Product pricing not found for ${productKey} ${billingType}`);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
// ============
|
|
57
|
+
// ============ Safe utility functions: accept only simple mapping inputs and do not expose config internals ============
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
60
|
+
* Get the credit amount for a price ID.
|
|
61
61
|
*
|
|
62
|
-
*
|
|
63
|
-
* -
|
|
64
|
-
* -
|
|
65
|
-
* -
|
|
62
|
+
* Security design:
|
|
63
|
+
* - The utility layer parses the config and extracts only the required data.
|
|
64
|
+
* - Only the query result is returned; the full config structure is not exposed.
|
|
65
|
+
* - Application-level wrappers hide the config object from callers.
|
|
66
66
|
*
|
|
67
|
-
* @param priceId -
|
|
68
|
-
* @param config - MoneyPriceConfig
|
|
69
|
-
* @returns
|
|
67
|
+
* @param priceId - Price ID to query.
|
|
68
|
+
* @param config - MoneyPriceConfig object provided by the application layer.
|
|
69
|
+
* @returns The matching credit amount, or null.
|
|
70
70
|
*/
|
|
71
71
|
export function getCreditsFromPriceIdUtil(
|
|
72
72
|
priceId: string | undefined,
|
|
@@ -76,9 +76,9 @@ export function getCreditsFromPriceIdUtil(
|
|
|
76
76
|
return null;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
//
|
|
79
|
+
// Iterate through all payment providers.
|
|
80
80
|
for (const provider of Object.values(config.paymentProviders)) {
|
|
81
|
-
//
|
|
81
|
+
// Iterate through subscription products.
|
|
82
82
|
const subscriptionProducts = (
|
|
83
83
|
provider.subscriptionProducts || provider.products
|
|
84
84
|
) as Record<string, any>;
|
|
@@ -96,7 +96,7 @@ export function getCreditsFromPriceIdUtil(
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
//
|
|
99
|
+
// Iterate through credit pack products.
|
|
100
100
|
const creditPacks = provider.creditPackProducts as Record<string, any>;
|
|
101
101
|
if (creditPacks) {
|
|
102
102
|
for (const pack of Object.values(creditPacks)) {
|
|
@@ -112,23 +112,23 @@ export function getCreditsFromPriceIdUtil(
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
|
-
*
|
|
115
|
+
* Get price configuration by query parameters.
|
|
116
116
|
*
|
|
117
|
-
*
|
|
118
|
-
* 1.
|
|
119
|
-
* 2.
|
|
120
|
-
* 3.
|
|
117
|
+
* Supported query modes:
|
|
118
|
+
* 1. Query directly by priceId.
|
|
119
|
+
* 2. Query by plan and billingType.
|
|
120
|
+
* 3. Query by plan.
|
|
121
121
|
*
|
|
122
|
-
*
|
|
123
|
-
* -
|
|
124
|
-
* -
|
|
125
|
-
* -
|
|
122
|
+
* Security design:
|
|
123
|
+
* - The utility layer parses the config and extracts only matching data.
|
|
124
|
+
* - Only the query result is returned; the full config structure is not exposed.
|
|
125
|
+
* - Application-level wrappers hide the config object from callers.
|
|
126
126
|
*
|
|
127
|
-
* @param priceId -
|
|
128
|
-
* @param plan -
|
|
129
|
-
* @param billingType -
|
|
130
|
-
* @param config - MoneyPriceConfig
|
|
131
|
-
* @returns
|
|
127
|
+
* @param priceId - Optional price ID to query.
|
|
128
|
+
* @param plan - Optional plan name, such as 'P2' or 'U3'.
|
|
129
|
+
* @param billingType - Optional billing type, such as 'monthly' or 'yearly'.
|
|
130
|
+
* @param config - MoneyPriceConfig object provided by the application layer.
|
|
131
|
+
* @returns The matching price config with derived metadata: priceName, description, and interval.
|
|
132
132
|
*/
|
|
133
133
|
export function getPriceConfigUtil(
|
|
134
134
|
priceId: string | undefined,
|
|
@@ -136,9 +136,9 @@ export function getPriceConfigUtil(
|
|
|
136
136
|
billingType: string | undefined,
|
|
137
137
|
config: MoneyPriceConfig
|
|
138
138
|
): (EnhancePricePlan & { priceName: string; description: string; interval?: string }) | null {
|
|
139
|
-
//
|
|
139
|
+
// Iterate through all payment providers.
|
|
140
140
|
for (const provider of Object.values(config.paymentProviders)) {
|
|
141
|
-
//
|
|
141
|
+
// Iterate through subscription products.
|
|
142
142
|
const subscriptionProducts = (
|
|
143
143
|
provider.subscriptionProducts || provider.products
|
|
144
144
|
) as Record<string, any>;
|
|
@@ -149,8 +149,8 @@ export function getPriceConfigUtil(
|
|
|
149
149
|
for (const [billingKey, planConfig] of Object.entries(product.plans)) {
|
|
150
150
|
const plan_config = planConfig as any;
|
|
151
151
|
|
|
152
|
-
//
|
|
153
|
-
// 1.
|
|
152
|
+
// Matching order by priority.
|
|
153
|
+
// 1. Exact priceId match with highest priority.
|
|
154
154
|
if (priceId && plan_config.priceId === priceId) {
|
|
155
155
|
return {
|
|
156
156
|
...plan_config,
|
|
@@ -160,7 +160,7 @@ export function getPriceConfigUtil(
|
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
// 2.
|
|
163
|
+
// 2. Match by both plan and billingType.
|
|
164
164
|
if (!priceId && plan && billingType) {
|
|
165
165
|
if (productKey === plan && billingKey === billingType) {
|
|
166
166
|
return {
|
|
@@ -172,7 +172,7 @@ export function getPriceConfigUtil(
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
// 3.
|
|
175
|
+
// 3. Match by plan when billingType is empty.
|
|
176
176
|
if (!priceId && !billingType && plan && productKey === plan) {
|
|
177
177
|
return {
|
|
178
178
|
...plan_config,
|
|
@@ -186,13 +186,13 @@ export function getPriceConfigUtil(
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
//
|
|
189
|
+
// Iterate through credit pack products.
|
|
190
190
|
const creditPacks = provider.creditPackProducts as Record<string, any>;
|
|
191
191
|
if (creditPacks) {
|
|
192
192
|
for (const [packKey, pack] of Object.entries(creditPacks)) {
|
|
193
193
|
const pack_typed = pack as any;
|
|
194
194
|
|
|
195
|
-
//
|
|
195
|
+
// Credit pack match.
|
|
196
196
|
if (priceId && pack_typed.priceId === priceId) {
|
|
197
197
|
return {
|
|
198
198
|
priceId: pack_typed.priceId,
|
|
@@ -205,7 +205,7 @@ export function getPriceConfigUtil(
|
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
//
|
|
208
|
+
// Match by plan and one-time billing.
|
|
209
209
|
if (!priceId && plan && billingType === 'onetime') {
|
|
210
210
|
if (packKey === plan) {
|
|
211
211
|
return {
|
|
@@ -220,7 +220,7 @@ export function getPriceConfigUtil(
|
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
//
|
|
223
|
+
// Match by plan; also resolves the first credit pack when billingType is empty.
|
|
224
224
|
if (!priceId && !billingType && plan && packKey === plan) {
|
|
225
225
|
return {
|
|
226
226
|
priceId: pack_typed.priceId,
|
|
@@ -237,4 +237,4 @@ export function getPriceConfigUtil(
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
return null;
|
|
240
|
-
}
|
|
240
|
+
}
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from './money-price-types';
|
|
20
20
|
import { redirectToCustomerPortal } from './customer-portal';
|
|
21
21
|
import { themeButtonGradientClass, themeButtonGradientHoverClass, themeIconColor } from '@windrun-huaiin/base-ui/lib';
|
|
22
|
+
import { AnimeBeamFrame } from '../anime';
|
|
22
23
|
|
|
23
24
|
type BillingType = string;
|
|
24
25
|
type ProcessingTarget = {
|
|
@@ -56,12 +57,12 @@ export function MoneyPriceInteractive({
|
|
|
56
57
|
const billingOptions = useMemo(() => {
|
|
57
58
|
const options = data.billingSwitch.options as BillingOption[];
|
|
58
59
|
|
|
59
|
-
//
|
|
60
|
+
// If enabledBillingTypes is configured, show only those billing types.
|
|
60
61
|
if (enabledBillingTypes?.length) {
|
|
61
62
|
return options.filter(option => enabledBillingTypes.includes(option.key));
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
//
|
|
65
|
+
// Otherwise show all configured options.
|
|
65
66
|
return options;
|
|
66
67
|
}, [data.billingSwitch.options, enabledBillingTypes]);
|
|
67
68
|
const billingOptionMap = useMemo(() => {
|
|
@@ -73,12 +74,12 @@ export function MoneyPriceInteractive({
|
|
|
73
74
|
const defaultBilling = useMemo<BillingType>(() => {
|
|
74
75
|
const defaultKey = data.billingSwitch.defaultKey;
|
|
75
76
|
|
|
76
|
-
//
|
|
77
|
+
// Use the default value when it is available.
|
|
77
78
|
if (billingOptions.some(opt => opt.key === defaultKey)) {
|
|
78
79
|
return defaultKey;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
//
|
|
82
|
+
// Otherwise use the first available option.
|
|
82
83
|
return billingOptions[0]?.key || 'monthly';
|
|
83
84
|
}, [data.billingSwitch.defaultKey, billingOptions]);
|
|
84
85
|
|
|
@@ -95,18 +96,18 @@ export function MoneyPriceInteractive({
|
|
|
95
96
|
const priceIdsByCycle = useMemo(() => {
|
|
96
97
|
const priceIds: Record<string, string[]> = {};
|
|
97
98
|
|
|
98
|
-
//
|
|
99
|
+
// Build a price ID list for each available billing type.
|
|
99
100
|
billingOptions.forEach(option => {
|
|
100
101
|
priceIds[option.key] = [];
|
|
101
102
|
|
|
102
103
|
if (option.key === 'onetime') {
|
|
103
|
-
//
|
|
104
|
+
// Handle credit pack products.
|
|
104
105
|
const creditPacks = providerConfig.creditPackProducts || {};
|
|
105
106
|
Object.values(creditPacks).forEach((pack: any) => {
|
|
106
107
|
priceIds[option.key].push(pack.priceId);
|
|
107
108
|
});
|
|
108
109
|
} else {
|
|
109
|
-
//
|
|
110
|
+
// Handle subscription products.
|
|
110
111
|
const products = providerConfig.subscriptionProducts || providerConfig.products || {};
|
|
111
112
|
PLAN_KEYS.forEach(planKey => {
|
|
112
113
|
const product = (products as any)[planKey];
|
|
@@ -341,7 +342,7 @@ export function MoneyPriceInteractive({
|
|
|
341
342
|
enableSubscriptionUpgrade
|
|
342
343
|
]);
|
|
343
344
|
|
|
344
|
-
//
|
|
345
|
+
// Select visible plans dynamically based on the current billing type.
|
|
345
346
|
const currentPlans = useMemo(() => {
|
|
346
347
|
if (billingType === 'onetime') {
|
|
347
348
|
return data.creditsPlans || [];
|
|
@@ -374,12 +375,12 @@ export function MoneyPriceInteractive({
|
|
|
374
375
|
const discountBadgeText = useMemo(() => {
|
|
375
376
|
if (!selectedBillingOption?.discountText) return null;
|
|
376
377
|
|
|
377
|
-
//
|
|
378
|
+
// In one-time mode, show discountText directly without relying on discountPercent.
|
|
378
379
|
if (billingType === 'onetime') {
|
|
379
380
|
return selectedBillingOption.discountText;
|
|
380
381
|
}
|
|
381
382
|
|
|
382
|
-
//
|
|
383
|
+
// In subscription mode, find discountPercent and interpolate it.
|
|
383
384
|
let discountPercent: number | null = null;
|
|
384
385
|
const products = providerConfig.subscriptionProducts || providerConfig.products || {};
|
|
385
386
|
|
|
@@ -394,7 +395,7 @@ export function MoneyPriceInteractive({
|
|
|
394
395
|
return selectedBillingOption.discountText.replace('{percent}', String(discountPercent));
|
|
395
396
|
}, [selectedBillingOption, providerConfig, billingType]);
|
|
396
397
|
|
|
397
|
-
//
|
|
398
|
+
// Configure the mobile floating style for BillingTypeButton.
|
|
398
399
|
return (
|
|
399
400
|
<>
|
|
400
401
|
<div className="flex justify-center mb-6 max-md:sticky max-md:top-30 max-md:z-30 max-md:py-2 max-md:bg-transparent">
|
|
@@ -442,18 +443,36 @@ export function MoneyPriceInteractive({
|
|
|
442
443
|
|
|
443
444
|
const showBillingSubtitle = plan.showBillingSubTitle !== false;
|
|
444
445
|
const hasDiscount = !!pricing.discountPercent && !!pricing.originalAmount;
|
|
446
|
+
const hasStrictDiffAnime = Object.prototype.hasOwnProperty.call(
|
|
447
|
+
plan.strictDiffAnime ?? {},
|
|
448
|
+
billingType
|
|
449
|
+
);
|
|
450
|
+
const animeTone = hasStrictDiffAnime
|
|
451
|
+
? plan.strictDiffAnime?.[billingType]
|
|
452
|
+
: plan.animeTone;
|
|
453
|
+
const hasAnimeTone = !!animeTone;
|
|
445
454
|
|
|
446
|
-
// 移动端宽度样式
|
|
447
455
|
return (
|
|
456
|
+
<AnimeBeamFrame
|
|
457
|
+
key={`${billingType}-${plan.key}-${animeTone ?? 'none'}`}
|
|
458
|
+
active={false}
|
|
459
|
+
interactive={hasAnimeTone}
|
|
460
|
+
tone={animeTone ?? 'theme'}
|
|
461
|
+
radius={16}
|
|
462
|
+
className={cn(
|
|
463
|
+
'h-full w-[85vw] max-w-[360px]',
|
|
464
|
+
'md:w-[clamp(280px,32vw,360px)] md:max-w-[360px] md:shrink-0',
|
|
465
|
+
)}
|
|
466
|
+
>
|
|
448
467
|
<div
|
|
449
|
-
key={plan.key}
|
|
450
468
|
data-price-plan={planKey}
|
|
451
469
|
className={cn(
|
|
452
|
-
'flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-5 md:p-8 h-full shadow-sm dark:shadow-none
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
470
|
+
'flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-5 md:p-8 h-full shadow-sm dark:shadow-none',
|
|
471
|
+
!hasAnimeTone && [
|
|
472
|
+
'hover:border-current',
|
|
473
|
+
'focus-within:border-current',
|
|
474
|
+
themeIconColor,
|
|
475
|
+
]
|
|
457
476
|
)}
|
|
458
477
|
style={{ minHeight: maxFeaturesCount * (isTouchDevice ? 86 : 100) }}
|
|
459
478
|
>
|
|
@@ -498,7 +517,7 @@ export function MoneyPriceInteractive({
|
|
|
498
517
|
data-price-subtitle={planKey}
|
|
499
518
|
>
|
|
500
519
|
{showBillingSubtitle && billingType === 'onetime' ? (
|
|
501
|
-
//
|
|
520
|
+
// Special one-time mode rendering: plain text plus styled product subtitle.
|
|
502
521
|
<>
|
|
503
522
|
{selectedBillingOption?.subTitle && (
|
|
504
523
|
<span className="text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium">
|
|
@@ -512,7 +531,7 @@ export function MoneyPriceInteractive({
|
|
|
512
531
|
)}
|
|
513
532
|
</>
|
|
514
533
|
) : (
|
|
515
|
-
//
|
|
534
|
+
// Keep the original rendering for other modes.
|
|
516
535
|
showBillingSubtitle && (
|
|
517
536
|
<span className="text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium">
|
|
518
537
|
{selectedBillingOption?.subTitle || ''}
|
|
@@ -570,6 +589,7 @@ export function MoneyPriceInteractive({
|
|
|
570
589
|
enableSubscriptionUpgrade={enableSubscriptionUpgrade}
|
|
571
590
|
/>
|
|
572
591
|
</div>
|
|
592
|
+
</AnimeBeamFrame>
|
|
573
593
|
);
|
|
574
594
|
})}
|
|
575
595
|
</div>
|
|
@@ -2,10 +2,10 @@ import type { XCredit, XSubscription, XUser } from '../../clerk/fingerprint/type
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Money Price Component Types
|
|
5
|
-
*
|
|
5
|
+
* Pricing component type definitions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// User status enum.
|
|
9
9
|
export enum UserState {
|
|
10
10
|
Anonymous = 'anonymous',
|
|
11
11
|
FreeUser = 'free',
|
|
@@ -13,7 +13,7 @@ export enum UserState {
|
|
|
13
13
|
UltraUser = 'ultra'
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
//
|
|
16
|
+
// User context.
|
|
17
17
|
export interface UserContext {
|
|
18
18
|
isAuthenticated: boolean;
|
|
19
19
|
subscriptionStatus: UserState;
|
|
@@ -29,10 +29,10 @@ export interface InitUserContext {
|
|
|
29
29
|
isClerkAuthenticated?: boolean;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
//
|
|
32
|
+
// Payment provider type.
|
|
33
33
|
export type PaymentProvider = 'stripe' | 'apple' | 'paypal' | 'wechat' | 'alipay' ;
|
|
34
34
|
|
|
35
|
-
//
|
|
35
|
+
// Price plan.
|
|
36
36
|
export interface EnhancePricePlan {
|
|
37
37
|
priceId: string;
|
|
38
38
|
amount: number;
|
|
@@ -42,13 +42,13 @@ export interface EnhancePricePlan {
|
|
|
42
42
|
credits?: number;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
//
|
|
45
|
+
// Subscription product configuration.
|
|
46
46
|
export interface SubscriptionProductConfig {
|
|
47
47
|
key: string;
|
|
48
48
|
plans: Record<string, EnhancePricePlan>;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
//
|
|
51
|
+
// Credit pack product configuration.
|
|
52
52
|
export interface CreditPackProductConfig {
|
|
53
53
|
key: string;
|
|
54
54
|
priceId: string;
|
|
@@ -57,7 +57,7 @@ export interface CreditPackProductConfig {
|
|
|
57
57
|
credits: number;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
//
|
|
60
|
+
// Payment provider configuration.
|
|
61
61
|
export interface PaymentProviderConfig {
|
|
62
62
|
provider: PaymentProvider;
|
|
63
63
|
enabled: boolean;
|
|
@@ -71,7 +71,7 @@ export interface PaymentProviderConfig {
|
|
|
71
71
|
P2: CreditPackProductConfig;
|
|
72
72
|
U3: CreditPackProductConfig;
|
|
73
73
|
};
|
|
74
|
-
//
|
|
74
|
+
// Backward-compatible legacy shape.
|
|
75
75
|
products?: {
|
|
76
76
|
F1: SubscriptionProductConfig;
|
|
77
77
|
P2: SubscriptionProductConfig;
|
|
@@ -79,7 +79,7 @@ export interface PaymentProviderConfig {
|
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
//
|
|
82
|
+
// Main configuration.
|
|
83
83
|
export interface MoneyPriceConfig {
|
|
84
84
|
paymentProviders: {
|
|
85
85
|
[provider: string]: PaymentProviderConfig;
|
|
@@ -92,7 +92,7 @@ export interface MoneyPriceConfig {
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
//
|
|
95
|
+
// Component props.
|
|
96
96
|
export interface MoneyPriceProps {
|
|
97
97
|
locale: string;
|
|
98
98
|
config: MoneyPriceConfig;
|
|
@@ -107,7 +107,7 @@ export interface MoneyPriceProps {
|
|
|
107
107
|
initialBillingType?: string;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
//
|
|
110
|
+
// Interactive component props.
|
|
111
111
|
export interface MoneyPriceInteractiveProps {
|
|
112
112
|
data: MoneyPriceData;
|
|
113
113
|
config: MoneyPriceConfig;
|
|
@@ -122,7 +122,7 @@ export interface MoneyPriceInteractiveProps {
|
|
|
122
122
|
isInitLoading?: boolean;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
//
|
|
125
|
+
// Button component props.
|
|
126
126
|
export interface MoneyPriceButtonProps {
|
|
127
127
|
planKey: 'F1' | 'P2' | 'U3';
|
|
128
128
|
userContext: UserContext;
|
|
@@ -143,7 +143,10 @@ export interface MoneyPriceButtonProps {
|
|
|
143
143
|
enableSubscriptionUpgrade?: boolean;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
export type MoneyPriceAnimeTone = 'theme' | 'rainbow' | 'mono' | 'warm' | 'cool';
|
|
147
|
+
export type MoneyPriceStrictDiffAnime = Record<string, MoneyPriceAnimeTone | null | undefined>;
|
|
148
|
+
|
|
149
|
+
// Data structures.
|
|
147
150
|
export interface MoneyPriceData {
|
|
148
151
|
title: string;
|
|
149
152
|
subtitle: string;
|
|
@@ -160,6 +163,8 @@ export interface MoneyPriceData {
|
|
|
160
163
|
subscriptionPlans: Array<{
|
|
161
164
|
key: string;
|
|
162
165
|
title: string;
|
|
166
|
+
animeTone?: MoneyPriceAnimeTone;
|
|
167
|
+
strictDiffAnime?: MoneyPriceStrictDiffAnime;
|
|
163
168
|
showBillingSubTitle?: boolean;
|
|
164
169
|
titleTags?: string[];
|
|
165
170
|
features?: Array<{
|
|
@@ -173,6 +178,8 @@ export interface MoneyPriceData {
|
|
|
173
178
|
key: string;
|
|
174
179
|
title: string;
|
|
175
180
|
subtitle?: string;
|
|
181
|
+
animeTone?: MoneyPriceAnimeTone;
|
|
182
|
+
strictDiffAnime?: MoneyPriceStrictDiffAnime;
|
|
176
183
|
showBillingSubTitle?: boolean;
|
|
177
184
|
titleTags?: string[];
|
|
178
185
|
features?: Array<{
|
|
@@ -82,7 +82,7 @@ export function XPillSelect(props: XPillSelectProps) {
|
|
|
82
82
|
props.mode === 'multiple' &&
|
|
83
83
|
allOptionValues.length > 0 &&
|
|
84
84
|
allOptionValues.every((value) => selectedValues.includes(value));
|
|
85
|
-
const aggregatedSelectedLabel = isAllSelected ? allSelectedLabel?.trim() || '
|
|
85
|
+
const aggregatedSelectedLabel = isAllSelected ? allSelectedLabel?.trim() || 'All' : null;
|
|
86
86
|
const hasVisiblePillLimit = props.mode === 'multiple' && typeof maxVisiblePills === 'number' && maxVisiblePills >= 0;
|
|
87
87
|
const visibleSelectedValues =
|
|
88
88
|
aggregatedSelectedLabel || !hasVisiblePillLimit
|
|
@@ -272,7 +272,7 @@ export function XPillSelect(props: XPillSelectProps) {
|
|
|
272
272
|
compact ? 'px-2.5 py-0.5 text-[11px]' : 'px-3 py-1 text-xs',
|
|
273
273
|
'bg-neutral-200 text-neutral-700 dark:bg-neutral-800 dark:text-white'
|
|
274
274
|
)}
|
|
275
|
-
title={
|
|
275
|
+
title={`${hiddenSelectedCount} items remain unexpanded`}
|
|
276
276
|
>
|
|
277
277
|
+{hiddenSelectedCount}
|
|
278
278
|
</span>
|
package/src/main/server.ts
CHANGED
|
@@ -32,6 +32,8 @@ export type {
|
|
|
32
32
|
MoneyPriceInteractiveProps,
|
|
33
33
|
MoneyPriceButtonProps,
|
|
34
34
|
MoneyPriceData,
|
|
35
|
+
MoneyPriceAnimeTone,
|
|
36
|
+
MoneyPriceStrictDiffAnime,
|
|
35
37
|
InitUserContext,
|
|
36
38
|
PaymentProvider,
|
|
37
39
|
PaymentProviderConfig,
|
|
@@ -41,4 +43,4 @@ export type {
|
|
|
41
43
|
UserContext
|
|
42
44
|
} from './money-price/money-price-types';
|
|
43
45
|
|
|
44
|
-
export { UserState } from './money-price/money-price-types';
|
|
46
|
+
export { UserState } from './money-price/money-price-types';
|
package/src/styles/third-ui.css
CHANGED
|
@@ -76,3 +76,11 @@ body {
|
|
|
76
76
|
background: var(--gallery-swiper-bullet-active-color, #AC62FD) !important;
|
|
77
77
|
transform: scale(1.5);
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
.cl-modalBackdrop {
|
|
81
|
+
background-color: rgb(0 0 0 / 0.8) !important;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.dark .cl-modalBackdrop {
|
|
85
|
+
background-color: rgb(0 0 0 / 0.8) !important;
|
|
86
|
+
}
|