@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
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface AnimeNotFoundPageProps {
|
|
3
|
+
siteIcon: ReactNode;
|
|
4
|
+
homeUrl?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function AnimeNotFoundPage({ siteIcon, homeUrl, className, }: AnimeNotFoundPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var lib = require('@windrun-huaiin/base-ui/lib');
|
|
6
|
+
var utils = require('@windrun-huaiin/lib/utils');
|
|
7
|
+
var animejs = require('animejs');
|
|
8
|
+
var react = require('motion/react');
|
|
9
|
+
var React = require('react');
|
|
10
|
+
|
|
11
|
+
const dust = Array.from({ length: 10 }, (_, index) => ({
|
|
12
|
+
id: index,
|
|
13
|
+
left: `${12 + index * 8}%`,
|
|
14
|
+
top: `${18 + (index % 5) * 13}%`,
|
|
15
|
+
size: 3 + (index % 3),
|
|
16
|
+
}));
|
|
17
|
+
function AnimeNotFoundPage({ siteIcon, homeUrl = process.env.NEXT_PUBLIC_BASE_URL || '/', className, }) {
|
|
18
|
+
const rootRef = React.useRef(null);
|
|
19
|
+
const timelineRef = React.useRef(null);
|
|
20
|
+
const shimmerRef = React.useRef(null);
|
|
21
|
+
const doorAnimationRef = React.useRef(null);
|
|
22
|
+
const lightAnimationRef = React.useRef(null);
|
|
23
|
+
const handleAnimationRef = React.useRef(null);
|
|
24
|
+
const isDoorOpenRef = React.useRef(true);
|
|
25
|
+
const prefersReducedMotion = react.useReducedMotion();
|
|
26
|
+
const doorStyle = React.useMemo(() => ({
|
|
27
|
+
'--not-found-theme': lib.themeSvgIconColor,
|
|
28
|
+
}), []);
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
var _a, _b;
|
|
31
|
+
const root = rootRef.current;
|
|
32
|
+
if (!root || prefersReducedMotion) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const door = root.querySelector('[data-not-found-door]');
|
|
36
|
+
const light = root.querySelector('[data-not-found-light]');
|
|
37
|
+
const plate = root.querySelector('[data-not-found-plate]');
|
|
38
|
+
const handle = root.querySelector('[data-not-found-handle]');
|
|
39
|
+
const dustNodes = Array.from(root.querySelectorAll('[data-not-found-dust]'));
|
|
40
|
+
if (!door || !light || !plate || !handle) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
door.style.transform = 'rotateY(-46deg) translateX(-7px)';
|
|
44
|
+
light.style.opacity = '0.7';
|
|
45
|
+
light.style.transform = 'scaleX(1.12)';
|
|
46
|
+
(_a = timelineRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
47
|
+
timelineRef.current = animejs.createTimeline({ loop: true })
|
|
48
|
+
.add(plate, {
|
|
49
|
+
translateY: [0, -3, 0],
|
|
50
|
+
scale: [1, 1.025, 1],
|
|
51
|
+
duration: 1400,
|
|
52
|
+
ease: 'inOutSine',
|
|
53
|
+
})
|
|
54
|
+
.add(plate, {
|
|
55
|
+
translateY: [0, -3, 0],
|
|
56
|
+
scale: [1, 1.025, 1],
|
|
57
|
+
duration: 1400,
|
|
58
|
+
ease: 'inOutSine',
|
|
59
|
+
}, '+=900')
|
|
60
|
+
.add(dustNodes, {
|
|
61
|
+
opacity: [0, 0.72, 0],
|
|
62
|
+
translateY: [14, -18],
|
|
63
|
+
translateX: (_target, index) => (index % 2 === 0 ? 10 : -10),
|
|
64
|
+
scale: [0.4, 1, 0.6],
|
|
65
|
+
duration: 1800,
|
|
66
|
+
delay: animejs.stagger(80),
|
|
67
|
+
ease: 'outSine',
|
|
68
|
+
}, '<+=200');
|
|
69
|
+
(_b = shimmerRef.current) === null || _b === void 0 ? void 0 : _b.revert();
|
|
70
|
+
shimmerRef.current = animejs.animate(root.querySelectorAll('[data-not-found-shimmer]'), {
|
|
71
|
+
translateX: ['-120%', '120%'],
|
|
72
|
+
opacity: [0, 0.8, 0],
|
|
73
|
+
duration: 2400,
|
|
74
|
+
delay: animejs.stagger(160),
|
|
75
|
+
ease: 'inOutSine',
|
|
76
|
+
loop: true,
|
|
77
|
+
});
|
|
78
|
+
return () => {
|
|
79
|
+
var _a, _b, _c, _d, _e;
|
|
80
|
+
(_a = timelineRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
81
|
+
timelineRef.current = null;
|
|
82
|
+
(_b = shimmerRef.current) === null || _b === void 0 ? void 0 : _b.revert();
|
|
83
|
+
shimmerRef.current = null;
|
|
84
|
+
(_c = doorAnimationRef.current) === null || _c === void 0 ? void 0 : _c.revert();
|
|
85
|
+
doorAnimationRef.current = null;
|
|
86
|
+
(_d = lightAnimationRef.current) === null || _d === void 0 ? void 0 : _d.revert();
|
|
87
|
+
lightAnimationRef.current = null;
|
|
88
|
+
(_e = handleAnimationRef.current) === null || _e === void 0 ? void 0 : _e.revert();
|
|
89
|
+
handleAnimationRef.current = null;
|
|
90
|
+
};
|
|
91
|
+
}, [prefersReducedMotion]);
|
|
92
|
+
const toggleDoor = () => {
|
|
93
|
+
var _a, _b, _c;
|
|
94
|
+
const root = rootRef.current;
|
|
95
|
+
if (!root) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const door = root.querySelector('[data-not-found-door]');
|
|
99
|
+
const light = root.querySelector('[data-not-found-light]');
|
|
100
|
+
const handle = root.querySelector('[data-not-found-handle]');
|
|
101
|
+
if (!door || !light || !handle) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const nextOpen = !isDoorOpenRef.current;
|
|
105
|
+
isDoorOpenRef.current = nextOpen;
|
|
106
|
+
(_a = doorAnimationRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
107
|
+
(_b = lightAnimationRef.current) === null || _b === void 0 ? void 0 : _b.revert();
|
|
108
|
+
(_c = handleAnimationRef.current) === null || _c === void 0 ? void 0 : _c.revert();
|
|
109
|
+
if (prefersReducedMotion) {
|
|
110
|
+
door.style.transform = nextOpen ? 'rotateY(-56deg) translateX(-9px)' : 'rotateY(-2deg) translateX(0)';
|
|
111
|
+
light.style.opacity = nextOpen ? '0.76' : '0.2';
|
|
112
|
+
light.style.transform = nextOpen ? 'scaleX(1.18)' : 'scaleX(0.78)';
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
doorAnimationRef.current = animejs.animate(door, {
|
|
116
|
+
rotateY: nextOpen ? -56 : -2,
|
|
117
|
+
translateX: nextOpen ? -9 : 0,
|
|
118
|
+
duration: 760,
|
|
119
|
+
ease: 'outCubic',
|
|
120
|
+
});
|
|
121
|
+
lightAnimationRef.current = animejs.animate(light, {
|
|
122
|
+
opacity: nextOpen ? 0.76 : 0.2,
|
|
123
|
+
scaleX: nextOpen ? 1.18 : 0.78,
|
|
124
|
+
duration: 760,
|
|
125
|
+
ease: 'outCubic',
|
|
126
|
+
});
|
|
127
|
+
handleAnimationRef.current = animejs.animate(handle, {
|
|
128
|
+
scale: [1, 1.22, 1],
|
|
129
|
+
rotate: nextOpen ? [0, 18, 0] : [0, -18, 0],
|
|
130
|
+
duration: 520,
|
|
131
|
+
ease: 'inOutSine',
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
return (jsxRuntime.jsxs("div", { ref: rootRef, className: utils.cn('relative flex min-h-dvh w-full items-center justify-center overflow-hidden px-4 py-8', className), style: doorStyle, children: [jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(circle_at_50%_20%,rgba(255,255,255,0.75),transparent_34%),linear-gradient(180deg,rgba(250,250,250,0.96),rgba(244,244,245,0.72))] dark:bg-[radial-gradient(circle_at_50%_20%,rgba(255,255,255,0.08),transparent_34%),linear-gradient(180deg,rgba(24,24,27,0.96),rgba(9,9,11,0.92))]" }), jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 -z-10 h-1/2 bg-[linear-gradient(180deg,transparent,rgba(0,0,0,0.05))] dark:bg-[linear-gradient(180deg,transparent,rgba(0,0,0,0.34))]" }), jsxRuntime.jsxs("div", { className: "grid w-full max-w-4xl items-center gap-4 md:grid-cols-[minmax(0,0.9fr)_minmax(280px,0.78fr)] md:gap-6", children: [jsxRuntime.jsxs("section", { className: "order-2 text-center md:order-1 md:text-left", children: [jsxRuntime.jsx("h3", { className: utils.cn('whitespace-nowrap text-[clamp(2.15rem,8vw,3.4rem)] font-black leading-none tracking-normal md:text-[clamp(2.6rem,4.5vw,4rem)] bg-linear-to-r bg-clip-text text-transparent', lib.themeButtonGradientClass), children: "Page Not Found" }), jsxRuntime.jsx("p", { className: "mx-auto mt-5 max-w-xl text-base leading-7 text-muted-foreground md:mx-0 md:text-lg", children: "The page you're looking for doesn't exist" }), jsxRuntime.jsx("a", { href: homeUrl, className: utils.cn('mt-4 inline-flex text-sm font-semibold underline underline-offset-4 transition-opacity hover:opacity-80', lib.themeIconColor, 'decoration-current'), children: "Back to Homepage" }), jsxRuntime.jsx("span", { className: utils.cn('mt-9 inline-flex size-2 rounded-full', lib.themeBgColor) })] }), jsxRuntime.jsx("section", { className: "order-1 flex justify-center md:order-2", children: jsxRuntime.jsxs("div", { className: "relative aspect-[0.78] w-full max-w-[270px] sm:max-w-[315px] md:max-w-[330px] [perspective:1200px]", children: [jsxRuntime.jsx("div", { "data-not-found-light": "", className: "absolute left-[14%] top-[7%] h-[86%] w-[72%] rounded-[28px] bg-[radial-gradient(circle_at_50%_45%,rgba(255,255,255,0.96),color-mix(in_srgb,var(--not-found-theme)_42%,transparent)_42%,transparent_72%)] opacity-25 blur-xl" }), jsxRuntime.jsx("div", { className: "absolute inset-[4%] rounded-[32px] border border-black/10 bg-neutral-950/5 shadow-2xl shadow-black/10 dark:border-white/10 dark:bg-white/5" }), jsxRuntime.jsx("div", { className: "absolute inset-[8%] rounded-[26px] bg-[linear-gradient(180deg,rgba(255,255,255,0.88),rgba(228,228,231,0.86))] shadow-[inset_0_1px_0_rgba(255,255,255,0.85)] dark:bg-[linear-gradient(180deg,rgba(39,39,42,0.92),rgba(24,24,27,0.96))]" }), jsxRuntime.jsxs("div", { "data-not-found-door": "", className: "absolute inset-[8%] origin-left rounded-[26px] border border-black/10 bg-[linear-gradient(145deg,rgba(255,255,255,0.92),rgba(212,212,216,0.9))] shadow-2xl shadow-black/20 will-change-transform dark:border-white/10 dark:bg-[linear-gradient(145deg,rgba(63,63,70,0.96),rgba(24,24,27,0.98))]", children: [jsxRuntime.jsxs("div", { className: "absolute inset-4 overflow-hidden rounded-[20px] border border-black/10 dark:border-white/10", children: [jsxRuntime.jsx("div", { "data-not-found-shimmer": "", className: "absolute inset-y-0 w-1/3 -skew-x-12 bg-white/35 blur-md dark:bg-white/12" }), jsxRuntime.jsx("div", { className: "absolute inset-x-5 top-5 h-[30%] rounded-2xl border border-black/10 bg-white/35 dark:border-white/10 dark:bg-white/5" }), jsxRuntime.jsxs("a", { href: homeUrl, className: "absolute inset-x-5 bottom-5 flex h-[39%] flex-col items-center justify-center gap-2 rounded-2xl border border-black/10 bg-white/25 text-sm text-muted-foreground transition-opacity hover:opacity-80 dark:border-white/10 dark:bg-white/5", children: [siteIcon, jsxRuntime.jsx("span", { children: "Woops!" })] })] }), jsxRuntime.jsxs("div", { "data-not-found-plate": "", className: "absolute left-1/2 top-[18%] flex h-[88px] w-[156px] -translate-x-1/2 items-center justify-center overflow-hidden rounded-2xl border border-black/10 bg-white/86 shadow-lg shadow-black/10 dark:border-white/10 dark:bg-black/30", children: [jsxRuntime.jsx("div", { "data-not-found-shimmer": "", className: "absolute inset-y-0 w-1/2 -skew-x-12 bg-white/60 blur-md dark:bg-white/15" }), jsxRuntime.jsx("span", { className: utils.cn('relative text-5xl font-black tabular-nums bg-linear-to-r bg-clip-text text-transparent', lib.themeButtonGradientClass), children: "404" })] }), jsxRuntime.jsx("button", { type: "button", "data-not-found-handle": "", className: "absolute right-[16%] top-1/2 z-10 size-6 rounded-full border border-black/10 bg-[var(--not-found-theme)] shadow-lg shadow-black/20 outline-none ring-offset-2 transition-transform hover:scale-110 focus-visible:ring-2 focus-visible:ring-[var(--not-found-theme)] dark:border-white/15", "aria-label": "Toggle the 404 door", onClick: toggleDoor })] }), dust.map(dot => (jsxRuntime.jsx("span", { "data-not-found-dust": "", className: "absolute rounded-full bg-[var(--not-found-theme)] opacity-0", style: {
|
|
135
|
+
left: dot.left,
|
|
136
|
+
top: dot.top,
|
|
137
|
+
width: dot.size,
|
|
138
|
+
height: dot.size,
|
|
139
|
+
} }, dot.id)))] }) })] })] }));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
exports.AnimeNotFoundPage = AnimeNotFoundPage;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { themeSvgIconColor, themeButtonGradientClass, themeIconColor, themeBgColor } from '@windrun-huaiin/base-ui/lib';
|
|
4
|
+
import { cn } from '@windrun-huaiin/lib/utils';
|
|
5
|
+
import { createTimeline, stagger, animate } from 'animejs';
|
|
6
|
+
import { useReducedMotion } from 'motion/react';
|
|
7
|
+
import { useRef, useMemo, useEffect } from 'react';
|
|
8
|
+
|
|
9
|
+
const dust = Array.from({ length: 10 }, (_, index) => ({
|
|
10
|
+
id: index,
|
|
11
|
+
left: `${12 + index * 8}%`,
|
|
12
|
+
top: `${18 + (index % 5) * 13}%`,
|
|
13
|
+
size: 3 + (index % 3),
|
|
14
|
+
}));
|
|
15
|
+
function AnimeNotFoundPage({ siteIcon, homeUrl = process.env.NEXT_PUBLIC_BASE_URL || '/', className, }) {
|
|
16
|
+
const rootRef = useRef(null);
|
|
17
|
+
const timelineRef = useRef(null);
|
|
18
|
+
const shimmerRef = useRef(null);
|
|
19
|
+
const doorAnimationRef = useRef(null);
|
|
20
|
+
const lightAnimationRef = useRef(null);
|
|
21
|
+
const handleAnimationRef = useRef(null);
|
|
22
|
+
const isDoorOpenRef = useRef(true);
|
|
23
|
+
const prefersReducedMotion = useReducedMotion();
|
|
24
|
+
const doorStyle = useMemo(() => ({
|
|
25
|
+
'--not-found-theme': themeSvgIconColor,
|
|
26
|
+
}), []);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const root = rootRef.current;
|
|
30
|
+
if (!root || prefersReducedMotion) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const door = root.querySelector('[data-not-found-door]');
|
|
34
|
+
const light = root.querySelector('[data-not-found-light]');
|
|
35
|
+
const plate = root.querySelector('[data-not-found-plate]');
|
|
36
|
+
const handle = root.querySelector('[data-not-found-handle]');
|
|
37
|
+
const dustNodes = Array.from(root.querySelectorAll('[data-not-found-dust]'));
|
|
38
|
+
if (!door || !light || !plate || !handle) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
door.style.transform = 'rotateY(-46deg) translateX(-7px)';
|
|
42
|
+
light.style.opacity = '0.7';
|
|
43
|
+
light.style.transform = 'scaleX(1.12)';
|
|
44
|
+
(_a = timelineRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
45
|
+
timelineRef.current = createTimeline({ loop: true })
|
|
46
|
+
.add(plate, {
|
|
47
|
+
translateY: [0, -3, 0],
|
|
48
|
+
scale: [1, 1.025, 1],
|
|
49
|
+
duration: 1400,
|
|
50
|
+
ease: 'inOutSine',
|
|
51
|
+
})
|
|
52
|
+
.add(plate, {
|
|
53
|
+
translateY: [0, -3, 0],
|
|
54
|
+
scale: [1, 1.025, 1],
|
|
55
|
+
duration: 1400,
|
|
56
|
+
ease: 'inOutSine',
|
|
57
|
+
}, '+=900')
|
|
58
|
+
.add(dustNodes, {
|
|
59
|
+
opacity: [0, 0.72, 0],
|
|
60
|
+
translateY: [14, -18],
|
|
61
|
+
translateX: (_target, index) => (index % 2 === 0 ? 10 : -10),
|
|
62
|
+
scale: [0.4, 1, 0.6],
|
|
63
|
+
duration: 1800,
|
|
64
|
+
delay: stagger(80),
|
|
65
|
+
ease: 'outSine',
|
|
66
|
+
}, '<+=200');
|
|
67
|
+
(_b = shimmerRef.current) === null || _b === void 0 ? void 0 : _b.revert();
|
|
68
|
+
shimmerRef.current = animate(root.querySelectorAll('[data-not-found-shimmer]'), {
|
|
69
|
+
translateX: ['-120%', '120%'],
|
|
70
|
+
opacity: [0, 0.8, 0],
|
|
71
|
+
duration: 2400,
|
|
72
|
+
delay: stagger(160),
|
|
73
|
+
ease: 'inOutSine',
|
|
74
|
+
loop: true,
|
|
75
|
+
});
|
|
76
|
+
return () => {
|
|
77
|
+
var _a, _b, _c, _d, _e;
|
|
78
|
+
(_a = timelineRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
79
|
+
timelineRef.current = null;
|
|
80
|
+
(_b = shimmerRef.current) === null || _b === void 0 ? void 0 : _b.revert();
|
|
81
|
+
shimmerRef.current = null;
|
|
82
|
+
(_c = doorAnimationRef.current) === null || _c === void 0 ? void 0 : _c.revert();
|
|
83
|
+
doorAnimationRef.current = null;
|
|
84
|
+
(_d = lightAnimationRef.current) === null || _d === void 0 ? void 0 : _d.revert();
|
|
85
|
+
lightAnimationRef.current = null;
|
|
86
|
+
(_e = handleAnimationRef.current) === null || _e === void 0 ? void 0 : _e.revert();
|
|
87
|
+
handleAnimationRef.current = null;
|
|
88
|
+
};
|
|
89
|
+
}, [prefersReducedMotion]);
|
|
90
|
+
const toggleDoor = () => {
|
|
91
|
+
var _a, _b, _c;
|
|
92
|
+
const root = rootRef.current;
|
|
93
|
+
if (!root) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const door = root.querySelector('[data-not-found-door]');
|
|
97
|
+
const light = root.querySelector('[data-not-found-light]');
|
|
98
|
+
const handle = root.querySelector('[data-not-found-handle]');
|
|
99
|
+
if (!door || !light || !handle) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const nextOpen = !isDoorOpenRef.current;
|
|
103
|
+
isDoorOpenRef.current = nextOpen;
|
|
104
|
+
(_a = doorAnimationRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
105
|
+
(_b = lightAnimationRef.current) === null || _b === void 0 ? void 0 : _b.revert();
|
|
106
|
+
(_c = handleAnimationRef.current) === null || _c === void 0 ? void 0 : _c.revert();
|
|
107
|
+
if (prefersReducedMotion) {
|
|
108
|
+
door.style.transform = nextOpen ? 'rotateY(-56deg) translateX(-9px)' : 'rotateY(-2deg) translateX(0)';
|
|
109
|
+
light.style.opacity = nextOpen ? '0.76' : '0.2';
|
|
110
|
+
light.style.transform = nextOpen ? 'scaleX(1.18)' : 'scaleX(0.78)';
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
doorAnimationRef.current = animate(door, {
|
|
114
|
+
rotateY: nextOpen ? -56 : -2,
|
|
115
|
+
translateX: nextOpen ? -9 : 0,
|
|
116
|
+
duration: 760,
|
|
117
|
+
ease: 'outCubic',
|
|
118
|
+
});
|
|
119
|
+
lightAnimationRef.current = animate(light, {
|
|
120
|
+
opacity: nextOpen ? 0.76 : 0.2,
|
|
121
|
+
scaleX: nextOpen ? 1.18 : 0.78,
|
|
122
|
+
duration: 760,
|
|
123
|
+
ease: 'outCubic',
|
|
124
|
+
});
|
|
125
|
+
handleAnimationRef.current = animate(handle, {
|
|
126
|
+
scale: [1, 1.22, 1],
|
|
127
|
+
rotate: nextOpen ? [0, 18, 0] : [0, -18, 0],
|
|
128
|
+
duration: 520,
|
|
129
|
+
ease: 'inOutSine',
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
return (jsxs("div", { ref: rootRef, className: cn('relative flex min-h-dvh w-full items-center justify-center overflow-hidden px-4 py-8', className), style: doorStyle, children: [jsx("div", { className: "pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(circle_at_50%_20%,rgba(255,255,255,0.75),transparent_34%),linear-gradient(180deg,rgba(250,250,250,0.96),rgba(244,244,245,0.72))] dark:bg-[radial-gradient(circle_at_50%_20%,rgba(255,255,255,0.08),transparent_34%),linear-gradient(180deg,rgba(24,24,27,0.96),rgba(9,9,11,0.92))]" }), jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 -z-10 h-1/2 bg-[linear-gradient(180deg,transparent,rgba(0,0,0,0.05))] dark:bg-[linear-gradient(180deg,transparent,rgba(0,0,0,0.34))]" }), jsxs("div", { className: "grid w-full max-w-4xl items-center gap-4 md:grid-cols-[minmax(0,0.9fr)_minmax(280px,0.78fr)] md:gap-6", children: [jsxs("section", { className: "order-2 text-center md:order-1 md:text-left", children: [jsx("h3", { className: cn('whitespace-nowrap text-[clamp(2.15rem,8vw,3.4rem)] font-black leading-none tracking-normal md:text-[clamp(2.6rem,4.5vw,4rem)] bg-linear-to-r bg-clip-text text-transparent', themeButtonGradientClass), children: "Page Not Found" }), jsx("p", { className: "mx-auto mt-5 max-w-xl text-base leading-7 text-muted-foreground md:mx-0 md:text-lg", children: "The page you're looking for doesn't exist" }), jsx("a", { href: homeUrl, className: cn('mt-4 inline-flex text-sm font-semibold underline underline-offset-4 transition-opacity hover:opacity-80', themeIconColor, 'decoration-current'), children: "Back to Homepage" }), jsx("span", { className: cn('mt-9 inline-flex size-2 rounded-full', themeBgColor) })] }), jsx("section", { className: "order-1 flex justify-center md:order-2", children: jsxs("div", { className: "relative aspect-[0.78] w-full max-w-[270px] sm:max-w-[315px] md:max-w-[330px] [perspective:1200px]", children: [jsx("div", { "data-not-found-light": "", className: "absolute left-[14%] top-[7%] h-[86%] w-[72%] rounded-[28px] bg-[radial-gradient(circle_at_50%_45%,rgba(255,255,255,0.96),color-mix(in_srgb,var(--not-found-theme)_42%,transparent)_42%,transparent_72%)] opacity-25 blur-xl" }), jsx("div", { className: "absolute inset-[4%] rounded-[32px] border border-black/10 bg-neutral-950/5 shadow-2xl shadow-black/10 dark:border-white/10 dark:bg-white/5" }), jsx("div", { className: "absolute inset-[8%] rounded-[26px] bg-[linear-gradient(180deg,rgba(255,255,255,0.88),rgba(228,228,231,0.86))] shadow-[inset_0_1px_0_rgba(255,255,255,0.85)] dark:bg-[linear-gradient(180deg,rgba(39,39,42,0.92),rgba(24,24,27,0.96))]" }), jsxs("div", { "data-not-found-door": "", className: "absolute inset-[8%] origin-left rounded-[26px] border border-black/10 bg-[linear-gradient(145deg,rgba(255,255,255,0.92),rgba(212,212,216,0.9))] shadow-2xl shadow-black/20 will-change-transform dark:border-white/10 dark:bg-[linear-gradient(145deg,rgba(63,63,70,0.96),rgba(24,24,27,0.98))]", children: [jsxs("div", { className: "absolute inset-4 overflow-hidden rounded-[20px] border border-black/10 dark:border-white/10", children: [jsx("div", { "data-not-found-shimmer": "", className: "absolute inset-y-0 w-1/3 -skew-x-12 bg-white/35 blur-md dark:bg-white/12" }), jsx("div", { className: "absolute inset-x-5 top-5 h-[30%] rounded-2xl border border-black/10 bg-white/35 dark:border-white/10 dark:bg-white/5" }), jsxs("a", { href: homeUrl, className: "absolute inset-x-5 bottom-5 flex h-[39%] flex-col items-center justify-center gap-2 rounded-2xl border border-black/10 bg-white/25 text-sm text-muted-foreground transition-opacity hover:opacity-80 dark:border-white/10 dark:bg-white/5", children: [siteIcon, jsx("span", { children: "Woops!" })] })] }), jsxs("div", { "data-not-found-plate": "", className: "absolute left-1/2 top-[18%] flex h-[88px] w-[156px] -translate-x-1/2 items-center justify-center overflow-hidden rounded-2xl border border-black/10 bg-white/86 shadow-lg shadow-black/10 dark:border-white/10 dark:bg-black/30", children: [jsx("div", { "data-not-found-shimmer": "", className: "absolute inset-y-0 w-1/2 -skew-x-12 bg-white/60 blur-md dark:bg-white/15" }), jsx("span", { className: cn('relative text-5xl font-black tabular-nums bg-linear-to-r bg-clip-text text-transparent', themeButtonGradientClass), children: "404" })] }), jsx("button", { type: "button", "data-not-found-handle": "", className: "absolute right-[16%] top-1/2 z-10 size-6 rounded-full border border-black/10 bg-[var(--not-found-theme)] shadow-lg shadow-black/20 outline-none ring-offset-2 transition-transform hover:scale-110 focus-visible:ring-2 focus-visible:ring-[var(--not-found-theme)] dark:border-white/15", "aria-label": "Toggle the 404 door", onClick: toggleDoor })] }), dust.map(dot => (jsx("span", { "data-not-found-dust": "", className: "absolute rounded-full bg-[var(--not-found-theme)] opacity-0", style: {
|
|
133
|
+
left: dot.left,
|
|
134
|
+
top: dot.top,
|
|
135
|
+
width: dot.size,
|
|
136
|
+
height: dot.size,
|
|
137
|
+
} }, dot.id)))] }) })] })] }));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export { AnimeNotFoundPage };
|
package/dist/main/anime/index.js
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
var animeBeamFrame = require('./anime-beam-frame.js');
|
|
5
5
|
var animeSpiralLoading = require('./anime-spiral-loading.js');
|
|
6
|
+
var anime404Page = require('./anime-404-page.js');
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
exports.AnimeBeamFrame = animeBeamFrame.AnimeBeamFrame;
|
|
10
11
|
exports.AnimeSpiralLoading = animeSpiralLoading.AnimeSpiralLoading;
|
|
12
|
+
exports.AnimeNotFoundPage = anime404Page.AnimeNotFoundPage;
|
|
@@ -9,7 +9,7 @@ var utils = require('@windrun-huaiin/lib/utils');
|
|
|
9
9
|
var usePressFeedback = require('../buttons/use-press-feedback.js');
|
|
10
10
|
var randomDateRangeDialog = require('./random-date-range-dialog.js');
|
|
11
11
|
|
|
12
|
-
const DEFAULT_PLACEHOLDER = '
|
|
12
|
+
const DEFAULT_PLACEHOLDER = 'Slide pick Date';
|
|
13
13
|
const DEFAULT_RANGE_DAYS = 7;
|
|
14
14
|
const CLEAR_PRESS_FEEDBACK_MS = 180;
|
|
15
15
|
function parseDateString(value) {
|
|
@@ -7,7 +7,7 @@ import { cn } from '@windrun-huaiin/lib/utils';
|
|
|
7
7
|
import { usePressFeedback, resolvePressFeedbackMode } from '../buttons/use-press-feedback.mjs';
|
|
8
8
|
import { RandomDateRangeDialog } from './random-date-range-dialog.mjs';
|
|
9
9
|
|
|
10
|
-
const DEFAULT_PLACEHOLDER = '
|
|
10
|
+
const DEFAULT_PLACEHOLDER = 'Slide pick Date';
|
|
11
11
|
const DEFAULT_RANGE_DAYS = 7;
|
|
12
12
|
const CLEAR_PRESS_FEEDBACK_MS = 180;
|
|
13
13
|
function parseDateString(value) {
|
|
@@ -29,21 +29,21 @@ export interface CreditCTAConfig {
|
|
|
29
29
|
}
|
|
30
30
|
export type CreditBucketStatus = 'active' | 'expiringSoon' | 'expired';
|
|
31
31
|
export interface CreditBucket {
|
|
32
|
-
/**
|
|
32
|
+
/** Business-defined credit type identifier for translation mapping or analytics. */
|
|
33
33
|
kind: string;
|
|
34
|
-
/**
|
|
34
|
+
/** Display name override; otherwise the component uses the default translation for kind. */
|
|
35
35
|
label?: string;
|
|
36
|
-
/**
|
|
36
|
+
/** Current credit balance. */
|
|
37
37
|
balance: number;
|
|
38
|
-
/**
|
|
38
|
+
/** Credit limit for this credit type. */
|
|
39
39
|
limit: number;
|
|
40
|
-
/**
|
|
40
|
+
/** Optional status label for highlighting states such as expiration. */
|
|
41
41
|
status?: CreditBucketStatus;
|
|
42
|
-
/**
|
|
42
|
+
/** Credit expiration time as a local time string, used to derive component state. */
|
|
43
43
|
expiresAt?: string;
|
|
44
|
-
/**
|
|
44
|
+
/** Progress percentage from 0 to 100; computed from balance/limit when omitted. */
|
|
45
45
|
progressPercent?: number;
|
|
46
|
-
/**
|
|
46
|
+
/** Additional details, such as remaining days or usage limits. */
|
|
47
47
|
description?: string;
|
|
48
48
|
}
|
|
49
49
|
export interface SubscriptionInfo {
|
package/dist/main/index.d.ts
CHANGED
package/dist/main/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var goToTop = require('./go-to-top.js');
|
|
5
|
+
var _404Page = require('./404-page.js');
|
|
5
6
|
var loading = require('./loading.js');
|
|
6
7
|
var nprogressBar = require('./nprogress-bar.js');
|
|
7
8
|
var richTextExpert = require('./rich-text-expert.js');
|
|
@@ -11,6 +12,7 @@ var infoTooltip = require('./info-tooltip.js');
|
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
exports.GoToTop = goToTop.GoToTop;
|
|
15
|
+
exports.NotFoundPage = _404Page.NotFoundPage;
|
|
14
16
|
exports.Loading = loading.Loading;
|
|
15
17
|
exports.getLoadingCycleDurationMs = loading.getLoadingCycleDurationMs;
|
|
16
18
|
exports.NProgressBar = nprogressBar.NProgressBar;
|
package/dist/main/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
export { GoToTop } from './go-to-top.mjs';
|
|
3
|
+
export { NotFoundPage } from './404-page.mjs';
|
|
3
4
|
export { Loading, getLoadingCycleDurationMs } from './loading.mjs';
|
|
4
5
|
export { NProgressBar } from './nprogress-bar.mjs';
|
|
5
6
|
export { createRichTextRenderer, richText } from './rich-text-expert.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { MoneyPriceInteractive } from './money-price-interactive';
|
|
2
2
|
export { MoneyPriceButton } from './money-price-button';
|
|
3
|
-
export type { MoneyPriceConfig, MoneyPriceData, InitUserContext, MoneyPriceInteractiveProps, MoneyPriceButtonProps, PaymentProvider, PaymentProviderConfig, EnhancePricePlan, SubscriptionProductConfig, CreditPackProductConfig, UserContext, } from './money-price-types';
|
|
3
|
+
export type { MoneyPriceConfig, MoneyPriceData, MoneyPriceAnimeTone, MoneyPriceStrictDiffAnime, InitUserContext, MoneyPriceInteractiveProps, MoneyPriceButtonProps, PaymentProvider, PaymentProviderConfig, EnhancePricePlan, SubscriptionProductConfig, CreditPackProductConfig, UserContext, } from './money-price-types';
|
|
4
4
|
export { UserState } from './money-price-types';
|
|
@@ -26,9 +26,9 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
26
26
|
return billing === 'monthly' ? 2 : 4;
|
|
27
27
|
return 0;
|
|
28
28
|
};
|
|
29
|
-
//
|
|
29
|
+
// Button configuration for one-time mode.
|
|
30
30
|
const getOnetimeButtonConfig = () => {
|
|
31
|
-
//
|
|
31
|
+
// Anonymous users: show the sign-in button on every card.
|
|
32
32
|
if (!isAuthenticated) {
|
|
33
33
|
return {
|
|
34
34
|
text: texts.getStarted,
|
|
@@ -38,11 +38,11 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
if (subscriptionStatus === moneyPriceTypes.UserState.Anonymous) {
|
|
41
|
-
//
|
|
41
|
+
// Signed in but status unknown: treat as FreeUser.
|
|
42
42
|
console.warn('Clerk is authed OK but user is anonymous!');
|
|
43
43
|
return { text: '', disabled: true, hidden: true };
|
|
44
44
|
}
|
|
45
|
-
//
|
|
45
|
+
// Signed-in users: show the buy-credits button on every card in one-time mode.
|
|
46
46
|
return {
|
|
47
47
|
text: texts.buyCredits || texts.upgrade,
|
|
48
48
|
onClick: () => onAction(planKey, billingType),
|
|
@@ -50,9 +50,9 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
50
50
|
hidden: false
|
|
51
51
|
};
|
|
52
52
|
};
|
|
53
|
-
//
|
|
53
|
+
// Button configuration for subscription mode.
|
|
54
54
|
const getSubscriptionButtonConfig = () => {
|
|
55
|
-
//
|
|
55
|
+
// Anonymous users.
|
|
56
56
|
if (!isAuthenticated) {
|
|
57
57
|
const getButtonText = () => {
|
|
58
58
|
switch (planKey) {
|
|
@@ -73,7 +73,7 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
73
73
|
hidden: false
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
-
//
|
|
76
|
+
// Signed-in users.
|
|
77
77
|
switch (subscriptionStatus) {
|
|
78
78
|
case moneyPriceTypes.UserState.FreeUser: {
|
|
79
79
|
if (planTier === 'F1') {
|
|
@@ -91,7 +91,7 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
case moneyPriceTypes.UserState.ProUser: {
|
|
94
|
-
//
|
|
94
|
+
// Do not allow downgrades to Free.
|
|
95
95
|
if (planTier === 'F1') {
|
|
96
96
|
return { hidden: true };
|
|
97
97
|
}
|
|
@@ -169,12 +169,12 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
169
169
|
return { hidden: true };
|
|
170
170
|
}
|
|
171
171
|
default:
|
|
172
|
-
//
|
|
172
|
+
// Signed in but status unknown: treat as FreeUser.
|
|
173
173
|
console.warn('Clerk is authed OK but user is anonymous!');
|
|
174
174
|
return { text: '', disabled: true, hidden: true };
|
|
175
175
|
}
|
|
176
176
|
};
|
|
177
|
-
//
|
|
177
|
+
// Main button configuration function.
|
|
178
178
|
const getButtonConfig = () => {
|
|
179
179
|
if (billingType === 'onetime') {
|
|
180
180
|
return getOnetimeButtonConfig();
|
|
@@ -24,9 +24,9 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
24
24
|
return billing === 'monthly' ? 2 : 4;
|
|
25
25
|
return 0;
|
|
26
26
|
};
|
|
27
|
-
//
|
|
27
|
+
// Button configuration for one-time mode.
|
|
28
28
|
const getOnetimeButtonConfig = () => {
|
|
29
|
-
//
|
|
29
|
+
// Anonymous users: show the sign-in button on every card.
|
|
30
30
|
if (!isAuthenticated) {
|
|
31
31
|
return {
|
|
32
32
|
text: texts.getStarted,
|
|
@@ -36,11 +36,11 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
if (subscriptionStatus === UserState.Anonymous) {
|
|
39
|
-
//
|
|
39
|
+
// Signed in but status unknown: treat as FreeUser.
|
|
40
40
|
console.warn('Clerk is authed OK but user is anonymous!');
|
|
41
41
|
return { text: '', disabled: true, hidden: true };
|
|
42
42
|
}
|
|
43
|
-
//
|
|
43
|
+
// Signed-in users: show the buy-credits button on every card in one-time mode.
|
|
44
44
|
return {
|
|
45
45
|
text: texts.buyCredits || texts.upgrade,
|
|
46
46
|
onClick: () => onAction(planKey, billingType),
|
|
@@ -48,9 +48,9 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
48
48
|
hidden: false
|
|
49
49
|
};
|
|
50
50
|
};
|
|
51
|
-
//
|
|
51
|
+
// Button configuration for subscription mode.
|
|
52
52
|
const getSubscriptionButtonConfig = () => {
|
|
53
|
-
//
|
|
53
|
+
// Anonymous users.
|
|
54
54
|
if (!isAuthenticated) {
|
|
55
55
|
const getButtonText = () => {
|
|
56
56
|
switch (planKey) {
|
|
@@ -71,7 +71,7 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
71
71
|
hidden: false
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
|
-
//
|
|
74
|
+
// Signed-in users.
|
|
75
75
|
switch (subscriptionStatus) {
|
|
76
76
|
case UserState.FreeUser: {
|
|
77
77
|
if (planTier === 'F1') {
|
|
@@ -89,7 +89,7 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
case UserState.ProUser: {
|
|
92
|
-
//
|
|
92
|
+
// Do not allow downgrades to Free.
|
|
93
93
|
if (planTier === 'F1') {
|
|
94
94
|
return { hidden: true };
|
|
95
95
|
}
|
|
@@ -167,12 +167,12 @@ function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction,
|
|
|
167
167
|
return { hidden: true };
|
|
168
168
|
}
|
|
169
169
|
default:
|
|
170
|
-
//
|
|
170
|
+
// Signed in but status unknown: treat as FreeUser.
|
|
171
171
|
console.warn('Clerk is authed OK but user is anonymous!');
|
|
172
172
|
return { text: '', disabled: true, hidden: true };
|
|
173
173
|
}
|
|
174
174
|
};
|
|
175
|
-
//
|
|
175
|
+
// Main button configuration function.
|
|
176
176
|
const getButtonConfig = () => {
|
|
177
177
|
if (billingType === 'onetime') {
|
|
178
178
|
return getOnetimeButtonConfig();
|
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Money Price Configuration
|
|
3
|
-
*
|
|
3
|
+
* Pricing component configuration.
|
|
4
4
|
*/
|
|
5
5
|
import type { MoneyPriceConfig, PaymentProviderConfig, EnhancePricePlan } from './money-price-types';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Get the currently active payment provider configuration.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
9
|
+
* Security design:
|
|
10
|
+
* - The utility layer extracts the active provider configuration from the config.
|
|
11
|
+
* - Only the extracted result is returned; the full config structure is not exposed.
|
|
12
|
+
* - Application-level wrappers hide the config object from callers.
|
|
13
13
|
*
|
|
14
|
-
* @param config - MoneyPriceConfig
|
|
15
|
-
* @returns
|
|
14
|
+
* @param config - MoneyPriceConfig object provided by the application layer.
|
|
15
|
+
* @returns The currently active payment provider configuration.
|
|
16
16
|
*/
|
|
17
17
|
export declare function getActiveProviderConfigUtil(config: MoneyPriceConfig): PaymentProviderConfig;
|
|
18
18
|
export declare function getProductPricing(productKey: 'F1' | 'P2' | 'U3', billingType: string, provider: string, config: MoneyPriceConfig): EnhancePricePlan;
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Get the credit amount for a price ID.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
* -
|
|
24
|
-
* -
|
|
25
|
-
* -
|
|
22
|
+
* Security design:
|
|
23
|
+
* - The utility layer parses the config and extracts only the required data.
|
|
24
|
+
* - Only the query result is returned; the full config structure is not exposed.
|
|
25
|
+
* - Application-level wrappers hide the config object from callers.
|
|
26
26
|
*
|
|
27
|
-
* @param priceId -
|
|
28
|
-
* @param config - MoneyPriceConfig
|
|
29
|
-
* @returns
|
|
27
|
+
* @param priceId - Price ID to query.
|
|
28
|
+
* @param config - MoneyPriceConfig object provided by the application layer.
|
|
29
|
+
* @returns The matching credit amount, or null.
|
|
30
30
|
*/
|
|
31
31
|
export declare function getCreditsFromPriceIdUtil(priceId: string | undefined, config: MoneyPriceConfig): number | null;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Get price configuration by query parameters.
|
|
34
34
|
*
|
|
35
|
-
*
|
|
36
|
-
* 1.
|
|
37
|
-
* 2.
|
|
38
|
-
* 3.
|
|
35
|
+
* Supported query modes:
|
|
36
|
+
* 1. Query directly by priceId.
|
|
37
|
+
* 2. Query by plan and billingType.
|
|
38
|
+
* 3. Query by plan.
|
|
39
39
|
*
|
|
40
|
-
*
|
|
41
|
-
* -
|
|
42
|
-
* -
|
|
43
|
-
* -
|
|
40
|
+
* Security design:
|
|
41
|
+
* - The utility layer parses the config and extracts only matching data.
|
|
42
|
+
* - Only the query result is returned; the full config structure is not exposed.
|
|
43
|
+
* - Application-level wrappers hide the config object from callers.
|
|
44
44
|
*
|
|
45
|
-
* @param priceId -
|
|
46
|
-
* @param plan -
|
|
47
|
-
* @param billingType -
|
|
48
|
-
* @param config - MoneyPriceConfig
|
|
49
|
-
* @returns
|
|
45
|
+
* @param priceId - Optional price ID to query.
|
|
46
|
+
* @param plan - Optional plan name, such as 'P2' or 'U3'.
|
|
47
|
+
* @param billingType - Optional billing type, such as 'monthly' or 'yearly'.
|
|
48
|
+
* @param config - MoneyPriceConfig object provided by the application layer.
|
|
49
|
+
* @returns The matching price config with derived metadata: priceName, description, and interval.
|
|
50
50
|
*/
|
|
51
51
|
export declare function getPriceConfigUtil(priceId: string | undefined, plan: string | undefined, billingType: string | undefined, config: MoneyPriceConfig): (EnhancePricePlan & {
|
|
52
52
|
priceName: string;
|