@zerodev/wallet-react-ui 0.0.1
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 +124 -0
- package/dist/_types/auth/authStoreSlice.d.ts +33 -0
- package/dist/_types/auth/authStoreSlice.d.ts.map +1 -0
- package/dist/_types/auth/components/BlobAnimation/index.d.ts +4 -0
- package/dist/_types/auth/components/BlobAnimation/index.d.ts.map +1 -0
- package/dist/_types/auth/components/CodeInput/index.d.ts +11 -0
- package/dist/_types/auth/components/CodeInput/index.d.ts.map +1 -0
- package/dist/_types/auth/hooks/useAuth.d.ts +18 -0
- package/dist/_types/auth/hooks/useAuth.d.ts.map +1 -0
- package/dist/_types/auth/index.d.ts +4 -0
- package/dist/_types/auth/index.d.ts.map +1 -0
- package/dist/_types/auth/pages/EmailVerification.d.ts +2 -0
- package/dist/_types/auth/pages/EmailVerification.d.ts.map +1 -0
- package/dist/_types/auth/pages/ErrorScreen.d.ts +9 -0
- package/dist/_types/auth/pages/ErrorScreen.d.ts.map +1 -0
- package/dist/_types/auth/pages/OtpInput.d.ts +2 -0
- package/dist/_types/auth/pages/OtpInput.d.ts.map +1 -0
- package/dist/_types/auth/pages/SignUp.d.ts +2 -0
- package/dist/_types/auth/pages/SignUp.d.ts.map +1 -0
- package/dist/_types/auth/pages/Verifying.d.ts +2 -0
- package/dist/_types/auth/pages/Verifying.d.ts.map +1 -0
- package/dist/_types/auth/pages/WalletSelection.d.ts +2 -0
- package/dist/_types/auth/pages/WalletSelection.d.ts.map +1 -0
- package/dist/_types/auth/types.d.ts +12 -0
- package/dist/_types/auth/types.d.ts.map +1 -0
- package/dist/_types/auth/utils/url.d.ts +3 -0
- package/dist/_types/auth/utils/url.d.ts.map +1 -0
- package/dist/_types/connector.d.ts +17 -0
- package/dist/_types/connector.d.ts.map +1 -0
- package/dist/_types/index.d.ts +10 -0
- package/dist/_types/index.d.ts.map +1 -0
- package/dist/_types/shared/components/PoweredBy/index.d.ts +6 -0
- package/dist/_types/shared/components/PoweredBy/index.d.ts.map +1 -0
- package/dist/_types/shared/components/Screen/EllipticalRadial.d.ts +23 -0
- package/dist/_types/shared/components/Screen/EllipticalRadial.d.ts.map +1 -0
- package/dist/_types/shared/components/Screen/MultiRadialBackground.d.ts +4 -0
- package/dist/_types/shared/components/Screen/MultiRadialBackground.d.ts.map +1 -0
- package/dist/_types/shared/components/Screen/index.d.ts +9 -0
- package/dist/_types/shared/components/Screen/index.d.ts.map +1 -0
- package/dist/_types/shared/components/SignUpFooter/index.d.ts +8 -0
- package/dist/_types/shared/components/SignUpFooter/index.d.ts.map +1 -0
- package/dist/_types/shared/components/StatusScreen/index.d.ts +10 -0
- package/dist/_types/shared/components/StatusScreen/index.d.ts.map +1 -0
- package/dist/_types/shared/components/TopNav/index.d.ts +10 -0
- package/dist/_types/shared/components/TopNav/index.d.ts.map +1 -0
- package/dist/_types/shared/hooks/useKitStore.d.ts +11 -0
- package/dist/_types/shared/hooks/useKitStore.d.ts.map +1 -0
- package/dist/_types/shared/utils/common.d.ts +5 -0
- package/dist/_types/shared/utils/common.d.ts.map +1 -0
- package/dist/_types/shared/utils/store.d.ts +4 -0
- package/dist/_types/shared/utils/store.d.ts.map +1 -0
- package/dist/_types/store.d.ts +25 -0
- package/dist/_types/store.d.ts.map +1 -0
- package/dist/_types/types.d.ts +38 -0
- package/dist/_types/types.d.ts.map +1 -0
- package/dist/blob.webm +0 -0
- package/dist/error.webp +0 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +1374 -0
- package/dist/index.mjs.map +1 -0
- package/dist/loading.webp +0 -0
- package/dist/send.webp +0 -0
- package/dist/styles.css +2 -0
- package/dist/success.webp +0 -0
- package/package.json +96 -0
- package/src/assets.d.ts +14 -0
- package/src/auth/authStoreSlice.ts +180 -0
- package/src/auth/components/BlobAnimation/index.tsx +24 -0
- package/src/auth/components/CodeInput/index.tsx +118 -0
- package/src/auth/hooks/useAuth.ts +32 -0
- package/src/auth/index.tsx +108 -0
- package/src/auth/pages/EmailVerification.tsx +76 -0
- package/src/auth/pages/ErrorScreen.tsx +53 -0
- package/src/auth/pages/OtpInput.tsx +124 -0
- package/src/auth/pages/SignUp.tsx +303 -0
- package/src/auth/pages/Verifying.tsx +108 -0
- package/src/auth/pages/WalletSelection.tsx +53 -0
- package/src/auth/types.ts +23 -0
- package/src/auth/utils/url.ts +12 -0
- package/src/connector.ts +182 -0
- package/src/index.ts +25 -0
- package/src/shared/components/PoweredBy/index.tsx +26 -0
- package/src/shared/components/Screen/EllipticalRadial.tsx +65 -0
- package/src/shared/components/Screen/MultiRadialBackground.tsx +323 -0
- package/src/shared/components/Screen/index.tsx +65 -0
- package/src/shared/components/SignUpFooter/index.tsx +66 -0
- package/src/shared/components/StatusScreen/index.tsx +49 -0
- package/src/shared/components/TopNav/index.tsx +45 -0
- package/src/shared/hooks/useKitStore.ts +20 -0
- package/src/shared/utils/common.ts +26 -0
- package/src/shared/utils/store.ts +9 -0
- package/src/store.ts +44 -0
- package/src/types.ts +48 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zerodev/wallet-react-ui
|
|
3
|
+
* React UI components and enhanced connector for ZeroDev Wallet SDK
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Auth
|
|
7
|
+
export { AuthFlow } from './auth'
|
|
8
|
+
export { useAuth } from './auth/hooks/useAuth'
|
|
9
|
+
export type { AuthMethod, AuthStep } from './auth/types'
|
|
10
|
+
|
|
11
|
+
// Connector
|
|
12
|
+
export type {
|
|
13
|
+
// SigningConfig,
|
|
14
|
+
ZeroDevKitConfig,
|
|
15
|
+
ZeroDevKitConnectorParams,
|
|
16
|
+
} from './connector.js'
|
|
17
|
+
export { zeroDevWallet } from './connector.js'
|
|
18
|
+
|
|
19
|
+
// Signing
|
|
20
|
+
// export type { SignatureRequestProps } from './signing'
|
|
21
|
+
// export { SignatureRequest } from './signing'
|
|
22
|
+
// export { usePendingRequest } from './signing/hooks/usePendingRequest.js'
|
|
23
|
+
// export { usePendingRequests } from './signing/hooks/usePendingRequests.js'
|
|
24
|
+
//
|
|
25
|
+
// export type { PendingRequest, Request, RequestMethod } from './types.js'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cn, Icon, Text } 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
|
+
<Icon
|
|
20
|
+
name="zerodevLogo"
|
|
21
|
+
className="zd:h-[18px] zd:w-auto"
|
|
22
|
+
style={style}
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { cn } from '@zerodev/react-ui'
|
|
2
|
+
import type { CSSProperties, ReactNode } from 'react'
|
|
3
|
+
import { TOP_NAV_HEIGHT } from '../TopNav'
|
|
4
|
+
import {
|
|
5
|
+
CardGlow,
|
|
6
|
+
MultiRadialBackground,
|
|
7
|
+
WrapperBorder,
|
|
8
|
+
} from './MultiRadialBackground'
|
|
9
|
+
|
|
10
|
+
const CONTENT_PADDING_TOP = TOP_NAV_HEIGHT + 16
|
|
11
|
+
|
|
12
|
+
export function Screen({
|
|
13
|
+
children,
|
|
14
|
+
className,
|
|
15
|
+
contentClassName,
|
|
16
|
+
style,
|
|
17
|
+
topNav,
|
|
18
|
+
}: {
|
|
19
|
+
children: ReactNode
|
|
20
|
+
className?: string | undefined
|
|
21
|
+
contentClassName?: string | undefined
|
|
22
|
+
style?: CSSProperties | undefined
|
|
23
|
+
topNav?: ReactNode
|
|
24
|
+
}) {
|
|
25
|
+
return (
|
|
26
|
+
<div
|
|
27
|
+
className={cn(
|
|
28
|
+
'zd:flex zd:flex-col zd:overflow-hidden zd:text-left',
|
|
29
|
+
'zd:fixed zd:inset-0 zd:z-50 zd:w-screen zd:h-[100dvh] zd:rounded-[36px]',
|
|
30
|
+
'zd:sm:relative zd:sm:z-auto zd:sm:w-100 zd:sm:max-w-full zd:sm:h-[810px] zd:sm:max-h-[100dvh]',
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
style={style}
|
|
34
|
+
>
|
|
35
|
+
{/* Gradient border layer — fills the frame; the card on top has a 6px
|
|
36
|
+
margin so this shows as the border ring. */}
|
|
37
|
+
<WrapperBorder />
|
|
38
|
+
{/* Inner card sits on top with a 6px margin, exposing the border ring.
|
|
39
|
+
Its own gradient (base + CardGlow) fills the card so the colour stays
|
|
40
|
+
vivid and distinct from the border. */}
|
|
41
|
+
<div
|
|
42
|
+
className={cn(
|
|
43
|
+
'zd:flex zd:flex-1 zd:flex-col zd:m-1.5 zd:px-4 zd:overflow-hidden zd:rounded-4xl zd:relative',
|
|
44
|
+
contentClassName,
|
|
45
|
+
)}
|
|
46
|
+
// clip-path clips backdrop-filter to the rounded corners; plain
|
|
47
|
+
// overflow-hidden does not (WebKit/Chromium leaves scrolled blurred
|
|
48
|
+
// children bleeding past the radius). Must match rounded-4xl (32px).
|
|
49
|
+
style={{ clipPath: 'inset(0 round 32px)' }}
|
|
50
|
+
>
|
|
51
|
+
<MultiRadialBackground />
|
|
52
|
+
<CardGlow />
|
|
53
|
+
<div className="zd:relative zd:z-10 zd:flex zd:flex-1 zd:flex-col zd:min-h-0">
|
|
54
|
+
{topNav}
|
|
55
|
+
<div
|
|
56
|
+
className="zd:flex zd:flex-1 zd:flex-col zd:min-h-0 zd:overflow-y-auto zd:overflow-x-hidden"
|
|
57
|
+
style={{ paddingTop: `${CONTENT_PADDING_TOP}px` }}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Text } from '@zerodev/react-ui'
|
|
2
|
+
import { PoweredBy } from '../PoweredBy'
|
|
3
|
+
|
|
4
|
+
export function SignUpFooter({
|
|
5
|
+
termsAndConditionsUrl,
|
|
6
|
+
privacyPolicyUrl,
|
|
7
|
+
agreedToTerms,
|
|
8
|
+
setAgreedToTerms,
|
|
9
|
+
highlight = false,
|
|
10
|
+
}: {
|
|
11
|
+
termsAndConditionsUrl?: string | undefined
|
|
12
|
+
privacyPolicyUrl?: string | undefined
|
|
13
|
+
agreedToTerms: boolean
|
|
14
|
+
setAgreedToTerms: (agreed: boolean) => void
|
|
15
|
+
highlight?: boolean
|
|
16
|
+
}) {
|
|
17
|
+
const showAgreement = !!(termsAndConditionsUrl || privacyPolicyUrl)
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="zd:flex zd:flex-col zd:items-center zd:gap-5">
|
|
21
|
+
{showAgreement && (
|
|
22
|
+
<div
|
|
23
|
+
className={`zd:flex zd:flex-row zd:items-center zd:gap-2 zd:rounded-md zd:p-2 zd:transition-colors ${
|
|
24
|
+
highlight
|
|
25
|
+
? 'zd:border zd:border-negative'
|
|
26
|
+
: 'zd:border zd:border-transparent'
|
|
27
|
+
}`}
|
|
28
|
+
>
|
|
29
|
+
<input
|
|
30
|
+
type="checkbox"
|
|
31
|
+
checked={agreedToTerms}
|
|
32
|
+
onChange={(e) => setAgreedToTerms(e.target.checked)}
|
|
33
|
+
className="zd:cursor-pointer zd:[color-scheme:light]"
|
|
34
|
+
/>
|
|
35
|
+
<Text className="zd:flex-1">
|
|
36
|
+
I agree to the{' '}
|
|
37
|
+
{termsAndConditionsUrl && (
|
|
38
|
+
<Text
|
|
39
|
+
as="a"
|
|
40
|
+
href={termsAndConditionsUrl}
|
|
41
|
+
target="_blank"
|
|
42
|
+
rel="noopener noreferrer"
|
|
43
|
+
className="zd:underline"
|
|
44
|
+
>
|
|
45
|
+
Terms & Conditions
|
|
46
|
+
</Text>
|
|
47
|
+
)}
|
|
48
|
+
{termsAndConditionsUrl && privacyPolicyUrl && ' and '}
|
|
49
|
+
{privacyPolicyUrl && (
|
|
50
|
+
<Text
|
|
51
|
+
as="a"
|
|
52
|
+
href={privacyPolicyUrl}
|
|
53
|
+
target="_blank"
|
|
54
|
+
rel="noopener noreferrer"
|
|
55
|
+
className="zd:underline"
|
|
56
|
+
>
|
|
57
|
+
Privacy Policy
|
|
58
|
+
</Text>
|
|
59
|
+
)}
|
|
60
|
+
</Text>
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
|
+
<PoweredBy />
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { cn, Text } from '@zerodev/react-ui'
|
|
2
|
+
import type { ReactNode } from 'react'
|
|
3
|
+
import errorImg from '../../../../assets/states/error.webp?no-inline'
|
|
4
|
+
import loadingImg from '../../../../assets/states/loading.webp?no-inline'
|
|
5
|
+
import sendImg from '../../../../assets/states/send.webp?no-inline'
|
|
6
|
+
import successImg from '../../../../assets/states/success.webp?no-inline'
|
|
7
|
+
|
|
8
|
+
export type StateImageName = 'error' | 'loading' | 'send' | 'success'
|
|
9
|
+
|
|
10
|
+
const STATE_IMAGES: Record<StateImageName, string> = {
|
|
11
|
+
error: errorImg,
|
|
12
|
+
loading: loadingImg,
|
|
13
|
+
send: sendImg,
|
|
14
|
+
success: successImg,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface StatusScreenProps {
|
|
18
|
+
imageName: StateImageName
|
|
19
|
+
title: string
|
|
20
|
+
children: ReactNode
|
|
21
|
+
className?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function StatusScreen({
|
|
25
|
+
imageName,
|
|
26
|
+
title,
|
|
27
|
+
children,
|
|
28
|
+
className,
|
|
29
|
+
}: StatusScreenProps) {
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
className={cn('zd:flex zd:flex-col zd:gap-8 zd:items-center', className)}
|
|
33
|
+
>
|
|
34
|
+
<img
|
|
35
|
+
src={STATE_IMAGES[imageName]}
|
|
36
|
+
alt={imageName}
|
|
37
|
+
className="zd:w-[118px] zd:h-[118px] zd:bg-transparent"
|
|
38
|
+
/>
|
|
39
|
+
<div className="zd:flex zd:flex-col zd:gap-4 zd:items-center">
|
|
40
|
+
<Text className="zd:text-h2 zd:text-center zd:whitespace-pre-wrap">
|
|
41
|
+
{title}
|
|
42
|
+
</Text>
|
|
43
|
+
<Text className="zd:text-center zd:whitespace-pre-wrap">
|
|
44
|
+
{children}
|
|
45
|
+
</Text>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cn, IconButton, Text } from '@zerodev/react-ui'
|
|
2
|
+
import type { ReactNode } from 'react'
|
|
3
|
+
|
|
4
|
+
export const TOP_NAV_HEIGHT = 52
|
|
5
|
+
|
|
6
|
+
export function TopNav({
|
|
7
|
+
onBack,
|
|
8
|
+
onClose,
|
|
9
|
+
title,
|
|
10
|
+
logo,
|
|
11
|
+
className,
|
|
12
|
+
}: {
|
|
13
|
+
onBack?: () => void
|
|
14
|
+
onClose: () => void
|
|
15
|
+
title?: string
|
|
16
|
+
logo?: ReactNode
|
|
17
|
+
className?: string
|
|
18
|
+
}) {
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
className={cn(
|
|
22
|
+
'zd:absolute zd:top-4 zd:left-0 zd:right-0 zd:flex zd:flex-row zd:items-center zd:justify-between',
|
|
23
|
+
className,
|
|
24
|
+
)}
|
|
25
|
+
style={{ height: TOP_NAV_HEIGHT }}
|
|
26
|
+
>
|
|
27
|
+
{onBack ? (
|
|
28
|
+
<IconButton iconName="chevronLeft" onClick={onBack} />
|
|
29
|
+
) : (
|
|
30
|
+
<div className="zd:h-13 zd:w-13" />
|
|
31
|
+
)}
|
|
32
|
+
{logo && (
|
|
33
|
+
<div className="zd:absolute zd:left-0 zd:right-0 zd:flex zd:items-center zd:justify-center zd:pointer-events-none">
|
|
34
|
+
{logo}
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
37
|
+
{title && (
|
|
38
|
+
<div className="zd:absolute zd:left-0 zd:right-0 zd:flex zd:items-center zd:justify-center zd:pointer-events-none">
|
|
39
|
+
<Text className="zd:text-body1">{title}</Text>
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
<IconButton iconName="x" onClick={onClose} />
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useConfig } from 'wagmi'
|
|
2
|
+
import type { createStore } from '../../store'
|
|
3
|
+
|
|
4
|
+
type KitStore = ReturnType<typeof createStore>
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the zustand store attached to the `zeroDevWallet` connector.
|
|
8
|
+
* Throws when the kit connector isn't present on the wagmi config.
|
|
9
|
+
*
|
|
10
|
+
* Read individual fields with `useStore(useKitStore(), (s) => s.field)`.
|
|
11
|
+
*/
|
|
12
|
+
export function useKitStore(): KitStore {
|
|
13
|
+
const config = useConfig()
|
|
14
|
+
const connector = config.connectors.find((c) => c.id === 'zerodev-wallet')
|
|
15
|
+
if (!connector || !('getKitStore' in connector)) {
|
|
16
|
+
throw new Error('useKitStore must be used with the zeroDevWallet connector')
|
|
17
|
+
}
|
|
18
|
+
// @ts-expect-error - getKitStore is a custom method on the kit connector
|
|
19
|
+
return connector.getKitStore()
|
|
20
|
+
}
|