@zerodev/wallet-react-ui 0.0.4 → 0.0.5
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/_types/auth/components/BlobAnimation/index.d.ts +1 -1
- package/dist/_types/auth/components/BlobAnimation/index.d.ts.map +1 -1
- package/dist/_types/auth/components/CodeInput/index.d.ts +1 -1
- package/dist/_types/auth/components/CodeInput/index.d.ts.map +1 -1
- package/dist/_types/auth/index.d.ts +1 -1
- package/dist/_types/auth/index.d.ts.map +1 -1
- package/dist/_types/auth/pages/EmailVerification.d.ts +1 -1
- package/dist/_types/auth/pages/EmailVerification.d.ts.map +1 -1
- package/dist/_types/auth/pages/ErrorScreen.d.ts +1 -1
- package/dist/_types/auth/pages/ErrorScreen.d.ts.map +1 -1
- package/dist/_types/auth/pages/OtpInput.d.ts +1 -1
- package/dist/_types/auth/pages/OtpInput.d.ts.map +1 -1
- package/dist/_types/auth/pages/SignUp.d.ts +1 -1
- package/dist/_types/auth/pages/SignUp.d.ts.map +1 -1
- package/dist/_types/auth/pages/Verifying.d.ts +1 -1
- package/dist/_types/auth/pages/Verifying.d.ts.map +1 -1
- package/dist/_types/auth/pages/WalletSelection.d.ts +1 -1
- package/dist/_types/auth/pages/WalletSelection.d.ts.map +1 -1
- package/dist/_types/shared/components/SignUpFooter/index.d.ts +1 -1
- package/dist/_types/shared/components/SignUpFooter/index.d.ts.map +1 -1
- package/dist/_types/shared/components/StatusScreen/index.d.ts +1 -1
- package/dist/_types/shared/components/StatusScreen/index.d.ts.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +454 -881
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +2 -2
- package/package.json +8 -7
- package/src/auth/index.tsx +3 -4
- package/src/auth/pages/EmailVerification.tsx +1 -2
- package/src/auth/pages/ErrorScreen.tsx +1 -2
- package/src/auth/pages/OtpInput.tsx +1 -2
- package/src/auth/pages/SignUp.tsx +11 -3
- package/src/auth/pages/Verifying.tsx +1 -2
- package/src/auth/pages/WalletSelection.tsx +12 -4
- package/src/shared/components/SignUpFooter/index.tsx +1 -2
- package/dist/_types/shared/components/PoweredBy/index.d.ts +0 -6
- package/dist/_types/shared/components/PoweredBy/index.d.ts.map +0 -1
- package/dist/_types/shared/components/Screen/EllipticalRadial.d.ts +0 -23
- package/dist/_types/shared/components/Screen/EllipticalRadial.d.ts.map +0 -1
- package/dist/_types/shared/components/Screen/MultiRadialBackground.d.ts +0 -4
- package/dist/_types/shared/components/Screen/MultiRadialBackground.d.ts.map +0 -1
- package/dist/_types/shared/components/Screen/index.d.ts +0 -10
- package/dist/_types/shared/components/Screen/index.d.ts.map +0 -1
- package/dist/_types/shared/components/TopNav/index.d.ts +0 -10
- package/dist/_types/shared/components/TopNav/index.d.ts.map +0 -1
- package/src/shared/components/PoweredBy/index.tsx +0 -27
- package/src/shared/components/Screen/EllipticalRadial.tsx +0 -65
- package/src/shared/components/Screen/MultiRadialBackground.tsx +0 -323
- package/src/shared/components/Screen/index.tsx +0 -85
- package/src/shared/components/TopNav/index.tsx +0 -48
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerodev/wallet-react-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "React wallet UI kit for ZeroDev (auth + signing flows)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"web3"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@zerodev/react-ui": "0.0.
|
|
46
|
+
"@zerodev/react-ui": "0.0.4"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@tanstack/react-query": "^5.0.0",
|
|
@@ -67,14 +67,15 @@
|
|
|
67
67
|
"@types/react": "^19",
|
|
68
68
|
"@types/react-dom": "^19",
|
|
69
69
|
"@vitejs/plugin-react": "^4.7.0",
|
|
70
|
-
"postcss": "^8.5.
|
|
71
|
-
"react": "19.2.
|
|
72
|
-
"react-dom": "19.2.
|
|
70
|
+
"postcss": "^8.5.16",
|
|
71
|
+
"react": "19.2.3",
|
|
72
|
+
"react-dom": "19.2.3",
|
|
73
73
|
"storybook": "^10.3.3",
|
|
74
74
|
"tailwindcss": "^4.2.2",
|
|
75
75
|
"typescript": "5.9.3",
|
|
76
|
-
"vite": "^6.4.
|
|
77
|
-
"vite-plugin-node-polyfills": "^0.25.0"
|
|
76
|
+
"vite": "^6.4.3",
|
|
77
|
+
"vite-plugin-node-polyfills": "^0.25.0",
|
|
78
|
+
"vocs": "^1.4.1"
|
|
78
79
|
},
|
|
79
80
|
"scripts": {
|
|
80
81
|
"build": "pnpm run clean && pnpm run build:css && pnpm run build:js && pnpm run build:types",
|
package/src/auth/index.tsx
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { Screen, TopNav } from '@zerodev/react-ui'
|
|
1
2
|
import { type ReactNode, useEffect } from 'react'
|
|
2
3
|
import { useStore } from 'zustand'
|
|
3
|
-
import { Screen } from '../shared/components/Screen'
|
|
4
4
|
import { StatusScreen } from '../shared/components/StatusScreen'
|
|
5
|
-
import { TopNav } from '../shared/components/TopNav'
|
|
6
5
|
import { useKitStore } from '../shared/hooks/useKitStore'
|
|
7
6
|
import { useAuth } from './hooks/useAuth'
|
|
8
7
|
import { EmailVerification } from './pages/EmailVerification'
|
|
@@ -95,8 +94,8 @@ export function AuthFlow({
|
|
|
95
94
|
contentClassName={step === 'sign-up' ? 'zd:px-0' : undefined}
|
|
96
95
|
topNav={
|
|
97
96
|
<TopNav
|
|
98
|
-
{...(goBack !== null && {
|
|
99
|
-
|
|
97
|
+
{...(goBack !== null && { onLeftButtonClick: goBack })}
|
|
98
|
+
onRightButtonClick={handleClose}
|
|
100
99
|
{...(title && { title })}
|
|
101
100
|
{...(step === 'sign-up' && {
|
|
102
101
|
...(logo && { logo }),
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Text } from '@zerodev/react-ui'
|
|
1
|
+
import { PoweredBy, Text } from '@zerodev/react-ui'
|
|
2
2
|
import { useSendMagicLink } from '@zerodev/wallet-react'
|
|
3
3
|
import { useEffect, useState } from 'react'
|
|
4
|
-
import { PoweredBy } from '../../shared/components/PoweredBy'
|
|
5
4
|
import { StatusScreen } from '../../shared/components/StatusScreen'
|
|
6
5
|
import { useAuth } from '../hooks/useAuth'
|
|
7
6
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Button } from '@zerodev/react-ui'
|
|
2
|
-
import { PoweredBy } from '../../shared/components/PoweredBy'
|
|
1
|
+
import { Button, PoweredBy } from '@zerodev/react-ui'
|
|
3
2
|
import { StatusScreen } from '../../shared/components/StatusScreen'
|
|
4
3
|
import { useAuth } from '../hooks/useAuth'
|
|
5
4
|
import { stripMagicLinkCodeFromUrl } from '../utils/url'
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Button, Text } from '@zerodev/react-ui'
|
|
1
|
+
import { Button, PoweredBy, Text } from '@zerodev/react-ui'
|
|
2
2
|
import { useSendOTP, useVerifyOTP } from '@zerodev/wallet-react'
|
|
3
3
|
import { useEffect, useState } from 'react'
|
|
4
|
-
import { PoweredBy } from '../../shared/components/PoweredBy'
|
|
5
4
|
import { CodeInput } from '../components/CodeInput'
|
|
6
5
|
import { useAuth } from '../hooks/useAuth'
|
|
7
6
|
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
Icon,
|
|
4
|
+
Input,
|
|
5
|
+
ListItem,
|
|
6
|
+
ListItemChevron,
|
|
7
|
+
ListItemIcon,
|
|
8
|
+
Text,
|
|
9
|
+
} from '@zerodev/react-ui'
|
|
2
10
|
import {
|
|
3
11
|
useAuthenticateOAuth,
|
|
4
12
|
useLoginPasskey,
|
|
@@ -235,9 +243,9 @@ export function SignUp() {
|
|
|
235
243
|
<div className="zd:px-4 zd:flex zd:flex-col zd:gap-2">
|
|
236
244
|
{enabledMethods.includes('google') && (
|
|
237
245
|
<ListItem
|
|
238
|
-
|
|
246
|
+
icon={<ListItemIcon name="google" />}
|
|
239
247
|
title="Google"
|
|
240
|
-
|
|
248
|
+
trailing={<ListItemChevron />}
|
|
241
249
|
className="zd:rounded-3xl"
|
|
242
250
|
disabled={anyPending}
|
|
243
251
|
onClick={handleGoogleAuth}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Button } from '@zerodev/react-ui'
|
|
1
|
+
import { Button, PoweredBy } from '@zerodev/react-ui'
|
|
2
2
|
import { useVerifyMagicLink } from '@zerodev/wallet-react'
|
|
3
3
|
import { useEffect, useRef, useState } from 'react'
|
|
4
|
-
import { PoweredBy } from '../../shared/components/PoweredBy'
|
|
5
4
|
import { StatusScreen } from '../../shared/components/StatusScreen'
|
|
6
5
|
import { useAuth } from '../hooks/useAuth'
|
|
7
6
|
import { stripMagicLinkCodeFromUrl } from '../utils/url'
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ListItem, Text } from '@zerodev/react-ui'
|
|
1
|
+
import { ListItem, ListItemIcon, PoweredBy, Text } from '@zerodev/react-ui'
|
|
2
2
|
import { useConnect } from 'wagmi'
|
|
3
|
-
import { PoweredBy } from '../../shared/components/PoweredBy'
|
|
4
3
|
import { useAuth } from '../hooks/useAuth'
|
|
5
4
|
|
|
6
5
|
export function WalletSelection() {
|
|
@@ -36,8 +35,17 @@ export function WalletSelection() {
|
|
|
36
35
|
<ListItem
|
|
37
36
|
key={connector.uid}
|
|
38
37
|
title={connector.name}
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
icon={
|
|
39
|
+
connector.icon ? (
|
|
40
|
+
<img
|
|
41
|
+
src={connector.icon}
|
|
42
|
+
alt=""
|
|
43
|
+
className="zd:w-6 zd:h-6"
|
|
44
|
+
/>
|
|
45
|
+
) : (
|
|
46
|
+
<ListItemIcon name="walletOutline" />
|
|
47
|
+
)
|
|
48
|
+
}
|
|
41
49
|
disabled={isPending}
|
|
42
50
|
onClick={() => handleSelect(connector)}
|
|
43
51
|
className="zd:rounded-3xl"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/shared/components/PoweredBy/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,KAAK,GACN,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;CACtB,2CAiBA"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
interface RadialStop {
|
|
2
|
-
offset: number;
|
|
3
|
-
color: string;
|
|
4
|
-
opacity: number;
|
|
5
|
-
}
|
|
6
|
-
export interface RadialLayer {
|
|
7
|
-
id: string;
|
|
8
|
-
matrix: [number, number, number, number, number, number];
|
|
9
|
-
fillOpacity: number;
|
|
10
|
-
stops: RadialStop[];
|
|
11
|
-
}
|
|
12
|
-
interface RadialRect {
|
|
13
|
-
x: number;
|
|
14
|
-
y: number;
|
|
15
|
-
width: number;
|
|
16
|
-
height: number;
|
|
17
|
-
}
|
|
18
|
-
export declare function EllipticalRadial({ layer, rect, }: {
|
|
19
|
-
layer: RadialLayer;
|
|
20
|
-
rect: RadialRect;
|
|
21
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=EllipticalRadial.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EllipticalRadial.d.ts","sourceRoot":"","sources":["../../../../../src/shared/components/Screen/EllipticalRadial.tsx"],"names":[],"mappings":"AAAA,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IAGV,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAExD,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAGD,UAAU,UAAU;IAClB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,EAAE,WAAW,CAAA;IAClB,IAAI,EAAE,UAAU,CAAA;CACjB,2CAkCA"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export declare function MultiRadialBackground(): import("react/jsx-runtime").JSX.Element;
|
|
2
|
-
export declare function CardGlow(): import("react/jsx-runtime").JSX.Element;
|
|
3
|
-
export declare function WrapperBorder(): import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
//# sourceMappingURL=MultiRadialBackground.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MultiRadialBackground.d.ts","sourceRoot":"","sources":["../../../../../src/shared/components/Screen/MultiRadialBackground.tsx"],"names":[],"mappings":"AAYA,wBAAgB,qBAAqB,4CAkBpC;AAYD,wBAAgB,QAAQ,4CAiJvB;AAeD,wBAAgB,aAAa,4CAwH5B"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { CSSProperties, ReactNode } from 'react';
|
|
2
|
-
export declare function Screen({ children, className, contentClassName, size, style, topNav, }: {
|
|
3
|
-
children: ReactNode;
|
|
4
|
-
className?: string | undefined;
|
|
5
|
-
contentClassName?: string | undefined;
|
|
6
|
-
size?: 'sm' | 'md' | 'lg' | undefined;
|
|
7
|
-
style?: CSSProperties | undefined;
|
|
8
|
-
topNav?: ReactNode;
|
|
9
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/shared/components/Screen/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAUrD,wBAAgB,MAAM,CAAC,EACrB,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,IAAW,EACX,KAAK,EACL,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAA;IACrC,KAAK,CAAC,EAAE,aAAa,GAAG,SAAS,CAAA;IACjC,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB,2CA2DA"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
export declare const TOP_NAV_HEIGHT = 52;
|
|
3
|
-
export declare function TopNav({ onBack, onClose, title, logo, className, }: {
|
|
4
|
-
onBack?: () => void;
|
|
5
|
-
onClose: () => void;
|
|
6
|
-
title?: string;
|
|
7
|
-
logo?: ReactNode;
|
|
8
|
-
className?: string;
|
|
9
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/shared/components/TopNav/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,eAAO,MAAM,cAAc,KAAK,CAAA;AAEhC,wBAAgB,MAAM,CAAC,EACrB,MAAM,EACN,OAAO,EACP,KAAK,EACL,IAAI,EACJ,SAAS,GACV,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,2CA8BA"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { cn, Text, ZeroDevLogo } from '@zerodev/react-ui'
|
|
2
|
-
import type { CSSProperties } from 'react'
|
|
3
|
-
|
|
4
|
-
export function PoweredBy({
|
|
5
|
-
className,
|
|
6
|
-
style,
|
|
7
|
-
}: {
|
|
8
|
-
className?: string
|
|
9
|
-
style?: CSSProperties
|
|
10
|
-
}) {
|
|
11
|
-
return (
|
|
12
|
-
<div
|
|
13
|
-
className={cn(
|
|
14
|
-
'zd:gap-1.5 zd:flex zd:flex-row zd:items-center',
|
|
15
|
-
className,
|
|
16
|
-
)}
|
|
17
|
-
>
|
|
18
|
-
<Text>Powered by</Text>
|
|
19
|
-
<ZeroDevLogo
|
|
20
|
-
variant="lockup"
|
|
21
|
-
tone="black"
|
|
22
|
-
className="zd:h-4.5 zd:w-auto"
|
|
23
|
-
style={style}
|
|
24
|
-
/>
|
|
25
|
-
</div>
|
|
26
|
-
)
|
|
27
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
interface RadialStop {
|
|
2
|
-
offset: number
|
|
3
|
-
color: string
|
|
4
|
-
opacity: number
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface RadialLayer {
|
|
8
|
-
id: string
|
|
9
|
-
// Figma-exported gradientTransform matrix: the unit circle
|
|
10
|
-
// (center 0,0 radius 1) mapped to a rotated/scaled/translated ellipse.
|
|
11
|
-
matrix: [number, number, number, number, number, number]
|
|
12
|
-
// Opacity of the rect the gradient fills (Figma exports this on the <rect>).
|
|
13
|
-
fillOpacity: number
|
|
14
|
-
stops: RadialStop[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// The rect each gradient fills, in the parent SVG's viewBox coordinates.
|
|
18
|
-
interface RadialRect {
|
|
19
|
-
x: number
|
|
20
|
-
y: number
|
|
21
|
-
width: number
|
|
22
|
-
height: number
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function EllipticalRadial({
|
|
26
|
-
layer,
|
|
27
|
-
rect,
|
|
28
|
-
}: {
|
|
29
|
-
layer: RadialLayer
|
|
30
|
-
rect: RadialRect
|
|
31
|
-
}) {
|
|
32
|
-
const { id, matrix, fillOpacity, stops } = layer
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<>
|
|
36
|
-
<defs>
|
|
37
|
-
<radialGradient
|
|
38
|
-
id={id}
|
|
39
|
-
cx="0"
|
|
40
|
-
cy="0"
|
|
41
|
-
r="1"
|
|
42
|
-
gradientUnits="userSpaceOnUse"
|
|
43
|
-
gradientTransform={`matrix(${matrix.join(' ')})`}
|
|
44
|
-
>
|
|
45
|
-
{stops.map((s, i) => (
|
|
46
|
-
<stop
|
|
47
|
-
key={s.color + i.toString()}
|
|
48
|
-
offset={s.offset}
|
|
49
|
-
stopColor={s.color}
|
|
50
|
-
stopOpacity={s.opacity}
|
|
51
|
-
/>
|
|
52
|
-
))}
|
|
53
|
-
</radialGradient>
|
|
54
|
-
</defs>
|
|
55
|
-
<rect
|
|
56
|
-
x={rect.x}
|
|
57
|
-
y={rect.y}
|
|
58
|
-
width={rect.width}
|
|
59
|
-
height={rect.height}
|
|
60
|
-
fill={`url(#${id})`}
|
|
61
|
-
fillOpacity={fillOpacity}
|
|
62
|
-
/>
|
|
63
|
-
</>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
import { useId } from 'react'
|
|
2
|
-
|
|
3
|
-
import { EllipticalRadial, type RadialLayer } from './EllipticalRadial'
|
|
4
|
-
|
|
5
|
-
// The design frame: the gradient layers live on a 412×812 rect offset to
|
|
6
|
-
// (-6,-6) so they bleed 6px past the 400×800 card on every side — that 6px
|
|
7
|
-
// reveal is the wrapper's gradient border. The matrices below are the
|
|
8
|
-
// Figma-exported gradientTransform values verbatim, so rendering the SVG with
|
|
9
|
-
// a matching viewBox + preserveAspectRatio="none" reproduces the design 1:1
|
|
10
|
-
// while still scaling to any container size.
|
|
11
|
-
const FRAME_VIEWBOX = '-6 -6 412 812'
|
|
12
|
-
|
|
13
|
-
export function MultiRadialBackground() {
|
|
14
|
-
// The colorful gradient now lives entirely in CardGlow. This base layer is
|
|
15
|
-
// just a flat, soft warm-white fill behind it so CardGlow's colors read
|
|
16
|
-
// bright and clean, with no gray muddiers underneath.
|
|
17
|
-
return (
|
|
18
|
-
<div className="zd:absolute zd:inset-0 zd:z-0 zd:rounded-4xl zd:pointer-events-none">
|
|
19
|
-
<svg
|
|
20
|
-
width="100%"
|
|
21
|
-
height="100%"
|
|
22
|
-
viewBox={FRAME_VIEWBOX}
|
|
23
|
-
preserveAspectRatio="none"
|
|
24
|
-
role="img"
|
|
25
|
-
aria-label="Decorative gradient background"
|
|
26
|
-
>
|
|
27
|
-
<rect x="-6" y="-6" width="412" height="812" fill="#FBF7F2" />
|
|
28
|
-
</svg>
|
|
29
|
-
</div>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// On-card overlay (400×800), sitting ON TOP of the translucent card body so its
|
|
34
|
-
// color reads at full strength (the card at 0.8 opacity would otherwise wash a
|
|
35
|
-
// behind-card gradient to ~20%). This reproduces the vivid orange + blue that in
|
|
36
|
-
// the source design came from the decorative "Amorphic" blob raster overlaid on
|
|
37
|
-
// the lower card, plus the design's own white card glow (Figma paint6).
|
|
38
|
-
//
|
|
39
|
-
// The orange + blue lobes are NOT verbatim Figma layers — they reconstruct the
|
|
40
|
-
// blob's measured color footprint (orange across the lower card; blue lobe
|
|
41
|
-
// bottom-left ~x 0-150 / y 600-800) as gradients, per the decision to treat the
|
|
42
|
-
// blob as a background effect rather than ship the raster.
|
|
43
|
-
export function CardGlow() {
|
|
44
|
-
const baseId = useId()
|
|
45
|
-
// VERBATIM from the Figma `--Background-Brand-Gradient` token (6 stacked
|
|
46
|
-
// radial-gradients). CSS lists topmost-first; SVG paints last-on-top, so the
|
|
47
|
-
// array is the CSS list REVERSED. Each matrix is the CSS `rx% ry% at cx% cy%`
|
|
48
|
-
// converted over the 400×800 frame. An upward linear fade is applied on top
|
|
49
|
-
// (see the <rect> below) to soften the gradient toward the top.
|
|
50
|
-
const layers: RadialLayer[] = [
|
|
51
|
-
{
|
|
52
|
-
// (CSS #6) blue → top-right. x-radius widened so the lobe reaches further
|
|
53
|
-
// left; y-radius kept short so it stays up top and doesn't bleed into the
|
|
54
|
-
// orange band.
|
|
55
|
-
id: `${baseId}-blue`,
|
|
56
|
-
matrix: [1850, 0, 0, 645, 381.44, 0],
|
|
57
|
-
fillOpacity: 1,
|
|
58
|
-
stops: [
|
|
59
|
-
{ offset: 0, color: '#45ABFB', opacity: 0.66 },
|
|
60
|
-
{ offset: 0.4615, color: '#1E9AFB', opacity: 0.35 },
|
|
61
|
-
{ offset: 1, color: '#45ABFB', opacity: 0 },
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
// (CSS #5) offWhite → blue, very faint
|
|
66
|
-
id: `${baseId}-offwhite-tr`,
|
|
67
|
-
matrix: [55.28, 0, 0, 773.36, 386.68, 13.28],
|
|
68
|
-
fillOpacity: 1,
|
|
69
|
-
stops: [
|
|
70
|
-
{ offset: 0, color: '#F7F5F0', opacity: 0.1 },
|
|
71
|
-
{ offset: 1, color: '#45ABFB', opacity: 0 },
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
// (CSS #4) warmGrey
|
|
76
|
-
id: `${baseId}-warmgrey`,
|
|
77
|
-
matrix: [326.72, 0, 0, 855.52, 0, 50.32],
|
|
78
|
-
fillOpacity: 1,
|
|
79
|
-
stops: [
|
|
80
|
-
{ offset: 0, color: '#E3CFC3', opacity: 1 },
|
|
81
|
-
{ offset: 1, color: '#E3CFC3', opacity: 0 },
|
|
82
|
-
],
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
// (CSS #3) orange — spans the full width across the bottom ~30%, uniform.
|
|
86
|
-
id: `${baseId}-orange`,
|
|
87
|
-
matrix: [580, 0, 0, 380, 200, 835],
|
|
88
|
-
fillOpacity: 1,
|
|
89
|
-
stops: [
|
|
90
|
-
{ offset: 0, color: '#EE6C2E', opacity: 0.8 },
|
|
91
|
-
{ offset: 0.55, color: '#EE6C2E', opacity: 0.6 },
|
|
92
|
-
{ offset: 1, color: '#EE6C2E', opacity: 0.15 },
|
|
93
|
-
],
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
// (CSS #2) peach — spread further up (~30% of the bottom), a bit more vivid
|
|
97
|
-
id: `${baseId}-peach`,
|
|
98
|
-
matrix: [520, 0, 0, 560, 180, 830],
|
|
99
|
-
fillOpacity: 1,
|
|
100
|
-
stops: [
|
|
101
|
-
{ offset: 0, color: '#FAC8AC', opacity: 1 },
|
|
102
|
-
{ offset: 1, color: '#F27B3E', opacity: 0 },
|
|
103
|
-
],
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
// (CSS #1) white glow (topmost of the colour stack)
|
|
107
|
-
id: `${baseId}-white-bl`,
|
|
108
|
-
matrix: [90.72, 0, 0, 550.48, 38.04, 702.64],
|
|
109
|
-
fillOpacity: 1,
|
|
110
|
-
stops: [
|
|
111
|
-
{ offset: 0, color: 'white', opacity: 0.58 },
|
|
112
|
-
{ offset: 1, color: 'white', opacity: 0 },
|
|
113
|
-
],
|
|
114
|
-
},
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<div className="zd:absolute zd:inset-0 zd:z-0 zd:rounded-4xl zd:pointer-events-none zd:overflow-hidden">
|
|
119
|
-
<svg
|
|
120
|
-
width="100%"
|
|
121
|
-
height="100%"
|
|
122
|
-
viewBox="0 0 400 800"
|
|
123
|
-
preserveAspectRatio="none"
|
|
124
|
-
role="presentation"
|
|
125
|
-
>
|
|
126
|
-
{layers.map((layer) => (
|
|
127
|
-
<EllipticalRadial
|
|
128
|
-
key={layer.id}
|
|
129
|
-
layer={layer}
|
|
130
|
-
rect={{ x: 0, y: 0, width: 400, height: 800 }}
|
|
131
|
-
/>
|
|
132
|
-
))}
|
|
133
|
-
{/* Vertical white fade — strongest at the bottom, easing linearly to
|
|
134
|
-
nothing at the top. Softens the lower (most vivid) part of the
|
|
135
|
-
gradient. A gradient layer (not an opaque card) so the frosted
|
|
136
|
-
buttons composite over it cleanly. */}
|
|
137
|
-
<defs>
|
|
138
|
-
<linearGradient
|
|
139
|
-
id={`${baseId}-vfade`}
|
|
140
|
-
x1="0"
|
|
141
|
-
y1="0"
|
|
142
|
-
x2="0"
|
|
143
|
-
y2="800"
|
|
144
|
-
gradientUnits="userSpaceOnUse"
|
|
145
|
-
>
|
|
146
|
-
<stop offset="0" stopColor="white" stopOpacity="0.55" />
|
|
147
|
-
<stop offset="0.45" stopColor="white" stopOpacity="0.52" />
|
|
148
|
-
<stop offset="0.65" stopColor="white" stopOpacity="0.5" />
|
|
149
|
-
<stop offset="0.85" stopColor="white" stopOpacity="0.5" />
|
|
150
|
-
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
|
151
|
-
</linearGradient>
|
|
152
|
-
</defs>
|
|
153
|
-
<rect
|
|
154
|
-
x="0"
|
|
155
|
-
y="0"
|
|
156
|
-
width="400"
|
|
157
|
-
height="800"
|
|
158
|
-
fill={`url(#${baseId}-vfade)`}
|
|
159
|
-
/>
|
|
160
|
-
{/* Blue — a diagonal linear gradient from the bottom-left corner fading
|
|
161
|
-
to transparent toward the top-right, so it blends smoothly into the
|
|
162
|
-
orange with no hard edge. On top of the fade so #A7B8E2 reads true. */}
|
|
163
|
-
<defs>
|
|
164
|
-
<linearGradient
|
|
165
|
-
id={`${baseId}-bluefade`}
|
|
166
|
-
x1="0"
|
|
167
|
-
y1="800"
|
|
168
|
-
x2="120"
|
|
169
|
-
y2="640"
|
|
170
|
-
gradientUnits="userSpaceOnUse"
|
|
171
|
-
>
|
|
172
|
-
<stop offset="0" stopColor="#A7B8E2" stopOpacity="1" />
|
|
173
|
-
<stop offset="0.33" stopColor="#A7B8E2" stopOpacity="0.7" />
|
|
174
|
-
<stop offset="0.66" stopColor="#A7B8E2" stopOpacity="0.35" />
|
|
175
|
-
<stop offset="1" stopColor="#A7B8E2" stopOpacity="0" />
|
|
176
|
-
</linearGradient>
|
|
177
|
-
</defs>
|
|
178
|
-
<rect
|
|
179
|
-
x="0"
|
|
180
|
-
y="0"
|
|
181
|
-
width="400"
|
|
182
|
-
height="800"
|
|
183
|
-
fill={`url(#${baseId}-bluefade)`}
|
|
184
|
-
/>
|
|
185
|
-
</svg>
|
|
186
|
-
</div>
|
|
187
|
-
)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// The wrapper's gradient BORDER. Renders full-frame behind the inner card; the
|
|
191
|
-
// card sits on top with a 6px margin so this gradient shows as the border ring.
|
|
192
|
-
// Uses normalized cx/cy/rx/ry radial gradients (scale-transform) over a #130E0B
|
|
193
|
-
// base — the original border look.
|
|
194
|
-
type BorderLayer = {
|
|
195
|
-
id: string
|
|
196
|
-
cx: number
|
|
197
|
-
cy: number
|
|
198
|
-
rx: number
|
|
199
|
-
ry: number
|
|
200
|
-
stops: { offset: number; color: string; opacity: number }[]
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export function WrapperBorder() {
|
|
204
|
-
const baseId = useId()
|
|
205
|
-
// VERBATIM from the Figma `--Background-Brand-Gradient` token (6 stacked
|
|
206
|
-
// radial-gradients). CSS lists topmost-first, SVG paints last-on-top, so the
|
|
207
|
-
// array is the CSS list REVERSED. Each CSS `rx% ry% at cx% cy%` maps to
|
|
208
|
-
// normalized cx/cy/rx/ry (÷100); the inline <radialGradient> below applies
|
|
209
|
-
// the cx=(cx/rx)*100% + scale(rx,ry) convention.
|
|
210
|
-
const layers: BorderLayer[] = [
|
|
211
|
-
{
|
|
212
|
-
id: `${baseId}-g6`, // (CSS #6) blue, top-right
|
|
213
|
-
cx: 0.9536,
|
|
214
|
-
cy: 0.0,
|
|
215
|
-
rx: 0.9385,
|
|
216
|
-
ry: 1.2256,
|
|
217
|
-
stops: [
|
|
218
|
-
{ offset: 0, color: '#45ABFB', opacity: 0.6 },
|
|
219
|
-
{ offset: 0.4615, color: '#1E9AFB', opacity: 0.32 },
|
|
220
|
-
{ offset: 1, color: '#45ABFB', opacity: 0 },
|
|
221
|
-
],
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
id: `${baseId}-g5`, // (CSS #5) faint light, top-right
|
|
225
|
-
cx: 0.9667,
|
|
226
|
-
cy: 0.0166,
|
|
227
|
-
rx: 0.1382,
|
|
228
|
-
ry: 0.9667,
|
|
229
|
-
stops: [
|
|
230
|
-
{ offset: 0, color: '#F7F5F0', opacity: 0.1 },
|
|
231
|
-
{ offset: 1, color: '#45ABFB', opacity: 0 },
|
|
232
|
-
],
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
id: `${baseId}-g4`, // (CSS #4) warm grey, top-left
|
|
236
|
-
cx: 0.0,
|
|
237
|
-
cy: 0.0629,
|
|
238
|
-
rx: 0.8168,
|
|
239
|
-
ry: 1.0694,
|
|
240
|
-
stops: [
|
|
241
|
-
{ offset: 0, color: '#E3CFC3', opacity: 1 },
|
|
242
|
-
{ offset: 1, color: '#E3CFC3', opacity: 0 },
|
|
243
|
-
],
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
id: `${baseId}-g3`, // (CSS #3) orange, bottom-left
|
|
247
|
-
cx: 0.0393,
|
|
248
|
-
cy: 1.0,
|
|
249
|
-
rx: 1.0628,
|
|
250
|
-
ry: 1.0303,
|
|
251
|
-
stops: [
|
|
252
|
-
{ offset: 0, color: '#FF6B1F', opacity: 1 },
|
|
253
|
-
{ offset: 0.476, color: '#E76000', opacity: 0.72 },
|
|
254
|
-
{ offset: 1, color: '#E76000', opacity: 0 },
|
|
255
|
-
],
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
id: `${baseId}-g2`, // (CSS #2) peach, bottom-center
|
|
259
|
-
cx: 0.3476,
|
|
260
|
-
cy: 1.0,
|
|
261
|
-
rx: 0.9614,
|
|
262
|
-
ry: 0.338,
|
|
263
|
-
stops: [
|
|
264
|
-
{ offset: 0, color: '#FAC8AC', opacity: 0.7 },
|
|
265
|
-
{ offset: 1, color: '#F27B3E', opacity: 0 },
|
|
266
|
-
],
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
id: `${baseId}-g1`, // (CSS #1) white glow, bottom-left
|
|
270
|
-
cx: 0.0951,
|
|
271
|
-
cy: 0.8783,
|
|
272
|
-
rx: 0.2268,
|
|
273
|
-
ry: 0.6881,
|
|
274
|
-
stops: [
|
|
275
|
-
{ offset: 0, color: '#FFFFFF', opacity: 0.58 },
|
|
276
|
-
{ offset: 1, color: '#FFFFFF', opacity: 0 },
|
|
277
|
-
],
|
|
278
|
-
},
|
|
279
|
-
]
|
|
280
|
-
|
|
281
|
-
return (
|
|
282
|
-
<div className="zd:absolute zd:inset-0 zd:z-0 zd:rounded-4xl zd:pointer-events-none zd:overflow-hidden">
|
|
283
|
-
<svg
|
|
284
|
-
width="100%"
|
|
285
|
-
height="100%"
|
|
286
|
-
preserveAspectRatio="none"
|
|
287
|
-
role="presentation"
|
|
288
|
-
>
|
|
289
|
-
<rect width="100%" height="100%" fill="#130E0B" />
|
|
290
|
-
<defs>
|
|
291
|
-
{layers.map((layer) => (
|
|
292
|
-
<radialGradient
|
|
293
|
-
key={layer.id}
|
|
294
|
-
id={layer.id}
|
|
295
|
-
cx={`${(layer.cx / layer.rx) * 100}%`}
|
|
296
|
-
cy={`${(layer.cy / layer.ry) * 100}%`}
|
|
297
|
-
r="100%"
|
|
298
|
-
gradientUnits="objectBoundingBox"
|
|
299
|
-
gradientTransform={`scale(${layer.rx}, ${layer.ry})`}
|
|
300
|
-
>
|
|
301
|
-
{layer.stops.map((s, i) => (
|
|
302
|
-
<stop
|
|
303
|
-
key={s.color + i.toString()}
|
|
304
|
-
offset={s.offset}
|
|
305
|
-
stopColor={s.color}
|
|
306
|
-
stopOpacity={s.opacity}
|
|
307
|
-
/>
|
|
308
|
-
))}
|
|
309
|
-
</radialGradient>
|
|
310
|
-
))}
|
|
311
|
-
</defs>
|
|
312
|
-
{layers.map((layer) => (
|
|
313
|
-
<rect
|
|
314
|
-
key={`${layer.id}-rect`}
|
|
315
|
-
width="100%"
|
|
316
|
-
height="100%"
|
|
317
|
-
fill={`url(#${layer.id})`}
|
|
318
|
-
/>
|
|
319
|
-
))}
|
|
320
|
-
</svg>
|
|
321
|
-
</div>
|
|
322
|
-
)
|
|
323
|
-
}
|