@b3dotfun/sdk 0.0.65-test.3 → 0.0.65-test.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/cjs/anyspend/react/components/AnySpend.js +1 -1
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +1 -1
- package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
- package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
- package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +71 -4
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +1 -1
- package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +1 -1
- package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.js +1 -1
- package/dist/cjs/global-account/react/components/ManageAccount/Header.js +2 -2
- package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.js +2 -2
- package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.js +1 -1
- package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +1 -1
- package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +1 -1
- package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.js +1 -1
- package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +1 -1
- package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.d.ts +2 -1
- package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.js +2 -2
- package/dist/cjs/global-account/react/components/ui/dialog.js +1 -1
- package/dist/cjs/global-account/react/components/ui/drawer.js +1 -1
- package/dist/esm/anyspend/react/components/AnySpend.js +1 -1
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +1 -1
- package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
- package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
- package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +72 -5
- package/dist/esm/global-account/react/components/B3DynamicModal.js +1 -1
- package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +1 -1
- package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.js +1 -1
- package/dist/esm/global-account/react/components/ManageAccount/Header.js +2 -2
- package/dist/esm/global-account/react/components/ManageAccount/HomeActions.js +2 -2
- package/dist/esm/global-account/react/components/ManageAccount/HomeContent.js +1 -1
- package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +1 -1
- package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +1 -1
- package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.js +1 -1
- package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +1 -1
- package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.d.ts +2 -1
- package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.js +3 -3
- package/dist/esm/global-account/react/components/ui/dialog.js +1 -1
- package/dist/esm/global-account/react/components/ui/drawer.js +1 -1
- package/dist/styles/index.css +1 -1
- package/dist/types/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
- package/dist/types/global-account/react/components/ModalHeader/ModalHeader.d.ts +2 -1
- package/package.json +2 -1
- package/src/anyspend/react/components/AnySpend.tsx +1 -1
- package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +1 -1
- package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +1 -1
- package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +123 -6
- package/src/global-account/react/components/B3DynamicModal.tsx +1 -1
- package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +1 -1
- package/src/global-account/react/components/ManageAccount/BottomNavigation.tsx +1 -1
- package/src/global-account/react/components/ManageAccount/Header.tsx +9 -9
- package/src/global-account/react/components/ManageAccount/HomeActions.tsx +2 -2
- package/src/global-account/react/components/ManageAccount/HomeContent.tsx +2 -2
- package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +9 -2
- package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +2 -2
- package/src/global-account/react/components/ManageAccount/SettingsMenuItem.tsx +1 -1
- package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +3 -1
- package/src/global-account/react/components/ModalHeader/ModalHeader.tsx +21 -10
- package/src/global-account/react/components/ui/dialog.tsx +2 -2
- package/src/global-account/react/components/ui/drawer.tsx +1 -1
|
@@ -7,7 +7,10 @@ import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
|
7
7
|
import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
|
|
8
8
|
import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
|
|
9
9
|
import { Loader2, Upload, X } from "lucide-react";
|
|
10
|
-
import { useRef, useState } from "react";
|
|
10
|
+
import { useCallback, useRef, useState } from "react";
|
|
11
|
+
import type { Area } from "react-easy-crop";
|
|
12
|
+
import Cropper from "react-easy-crop";
|
|
13
|
+
import "react-easy-crop/react-easy-crop.css";
|
|
11
14
|
import { toast } from "sonner";
|
|
12
15
|
import { useActiveAccount } from "thirdweb/react";
|
|
13
16
|
import { upload } from "thirdweb/storage";
|
|
@@ -17,6 +20,16 @@ import ModalHeader from "../ModalHeader/ModalHeader";
|
|
|
17
20
|
|
|
18
21
|
const debug = debugB3React("AvatarEditor");
|
|
19
22
|
|
|
23
|
+
// Helper function to create an image element from a URL
|
|
24
|
+
const createImage = (url: string): Promise<HTMLImageElement> =>
|
|
25
|
+
new Promise((resolve, reject) => {
|
|
26
|
+
const image = new Image();
|
|
27
|
+
image.addEventListener("load", () => resolve(image));
|
|
28
|
+
image.addEventListener("error", error => reject(error));
|
|
29
|
+
image.setAttribute("crossOrigin", "anonymous");
|
|
30
|
+
image.src = url;
|
|
31
|
+
});
|
|
32
|
+
|
|
20
33
|
interface AvatarEditorProps {
|
|
21
34
|
onSetAvatar?: () => void;
|
|
22
35
|
className?: string;
|
|
@@ -33,6 +46,9 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
|
|
|
33
46
|
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
|
34
47
|
const [isSaving, setIsSaving] = useState(false);
|
|
35
48
|
const [isDragging, setIsDragging] = useState(false);
|
|
49
|
+
const [crop, setCrop] = useState({ x: 0, y: 0 });
|
|
50
|
+
const [zoom, setZoom] = useState(1);
|
|
51
|
+
const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null);
|
|
36
52
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
37
53
|
const { setUser, user, partnerId } = useB3();
|
|
38
54
|
const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
|
|
@@ -50,6 +66,48 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
|
|
|
50
66
|
const currentAvatar = validateImageUrl(rawCurrentAvatar);
|
|
51
67
|
const safePreviewUrl = validateImageUrl(previewUrl);
|
|
52
68
|
|
|
69
|
+
const onCropComplete = useCallback((_croppedArea: Area, croppedAreaPixels: Area) => {
|
|
70
|
+
setCroppedAreaPixels(croppedAreaPixels);
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
73
|
+
const createCroppedImage = async (imageSrc: string, pixelCrop: Area): Promise<Blob> => {
|
|
74
|
+
const image = await createImage(imageSrc);
|
|
75
|
+
const canvas = document.createElement("canvas");
|
|
76
|
+
const ctx = canvas.getContext("2d");
|
|
77
|
+
|
|
78
|
+
if (!ctx) {
|
|
79
|
+
throw new Error("Failed to get canvas context");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Set canvas size to the crop area
|
|
83
|
+
canvas.width = pixelCrop.width;
|
|
84
|
+
canvas.height = pixelCrop.height;
|
|
85
|
+
|
|
86
|
+
// Draw the cropped image
|
|
87
|
+
ctx.drawImage(
|
|
88
|
+
image,
|
|
89
|
+
pixelCrop.x,
|
|
90
|
+
pixelCrop.y,
|
|
91
|
+
pixelCrop.width,
|
|
92
|
+
pixelCrop.height,
|
|
93
|
+
0,
|
|
94
|
+
0,
|
|
95
|
+
pixelCrop.width,
|
|
96
|
+
pixelCrop.height,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Return as blob
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
canvas.toBlob(blob => {
|
|
102
|
+
if (!blob) {
|
|
103
|
+
reject(new Error("Canvas is empty"));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
resolve(blob);
|
|
107
|
+
}, "image/jpeg");
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
|
|
53
111
|
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
54
112
|
const file = event.target.files?.[0];
|
|
55
113
|
if (file) {
|
|
@@ -87,6 +145,10 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
|
|
|
87
145
|
if (fileInputRef.current) {
|
|
88
146
|
fileInputRef.current.value = "";
|
|
89
147
|
}
|
|
148
|
+
// Reset crop state
|
|
149
|
+
setCrop({ x: 0, y: 0 });
|
|
150
|
+
setZoom(1);
|
|
151
|
+
setCroppedAreaPixels(null);
|
|
90
152
|
};
|
|
91
153
|
|
|
92
154
|
const handleSaveChanges = async () => {
|
|
@@ -99,8 +161,20 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
|
|
|
99
161
|
try {
|
|
100
162
|
let fileToUpload: File | null = null;
|
|
101
163
|
|
|
102
|
-
// If user uploaded a new file
|
|
103
|
-
if (selectedFile) {
|
|
164
|
+
// If user uploaded a new file and cropped it
|
|
165
|
+
if (selectedFile && previewUrl && croppedAreaPixels) {
|
|
166
|
+
try {
|
|
167
|
+
const croppedBlob = await createCroppedImage(previewUrl, croppedAreaPixels);
|
|
168
|
+
const extension = selectedFile.name.split(".").pop() || "jpg";
|
|
169
|
+
fileToUpload = new File([croppedBlob], `avatar-cropped.${extension}`, { type: "image/jpeg" });
|
|
170
|
+
} catch (error) {
|
|
171
|
+
debug("Error cropping image:", error);
|
|
172
|
+
toast.error("Failed to crop image. Please try again.");
|
|
173
|
+
setIsSaving(false);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
} else if (selectedFile) {
|
|
177
|
+
// Fallback if no crop was made
|
|
104
178
|
fileToUpload = selectedFile;
|
|
105
179
|
} else if (selectedProfileType && selectedAvatar) {
|
|
106
180
|
// User selected from existing profile avatars
|
|
@@ -319,7 +393,7 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
|
|
|
319
393
|
{/* Upload Image Button */}
|
|
320
394
|
<button
|
|
321
395
|
onClick={handleUploadImageClick}
|
|
322
|
-
className="font-inter
|
|
396
|
+
className="font-inter mb-6 flex w-full items-center justify-center gap-2 rounded-xl border border-[#e4e4e7] bg-white px-4 py-3 text-sm font-semibold text-[#18181b] shadow-sm transition-colors hover:bg-[#f4f4f5]"
|
|
323
397
|
>
|
|
324
398
|
<Upload className="h-4 w-4" />
|
|
325
399
|
Upload image
|
|
@@ -419,13 +493,56 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
|
|
|
419
493
|
</div>
|
|
420
494
|
) : (
|
|
421
495
|
<div className="mb-6 w-full">
|
|
422
|
-
<div className="aspect-square w-full overflow-hidden rounded-xl bg-[#f4f4f5]">
|
|
496
|
+
<div className="relative aspect-square w-full overflow-hidden rounded-xl bg-[#f4f4f5]">
|
|
423
497
|
{safePreviewUrl ? (
|
|
424
|
-
|
|
498
|
+
<>
|
|
499
|
+
<Cropper
|
|
500
|
+
image={safePreviewUrl}
|
|
501
|
+
crop={crop}
|
|
502
|
+
zoom={zoom}
|
|
503
|
+
aspect={1}
|
|
504
|
+
onCropChange={setCrop}
|
|
505
|
+
onCropComplete={onCropComplete}
|
|
506
|
+
onZoomChange={setZoom}
|
|
507
|
+
cropShape="rect"
|
|
508
|
+
showGrid={false}
|
|
509
|
+
style={{
|
|
510
|
+
containerStyle: {
|
|
511
|
+
width: "100%",
|
|
512
|
+
height: "100%",
|
|
513
|
+
backgroundColor: "#f4f4f5",
|
|
514
|
+
},
|
|
515
|
+
cropAreaStyle: {
|
|
516
|
+
border: "2px solid #3368ef",
|
|
517
|
+
borderRadius: "0px",
|
|
518
|
+
},
|
|
519
|
+
}}
|
|
520
|
+
/>
|
|
521
|
+
<button
|
|
522
|
+
onClick={handleRemovePreview}
|
|
523
|
+
className="absolute right-4 top-4 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-[#51525c] text-white transition-colors hover:bg-[#71717a]"
|
|
524
|
+
>
|
|
525
|
+
<X className="h-4 w-4" />
|
|
526
|
+
</button>
|
|
527
|
+
</>
|
|
425
528
|
) : (
|
|
426
529
|
<div className="bg-b3-primary-wash h-full w-full" />
|
|
427
530
|
)}
|
|
428
531
|
</div>
|
|
532
|
+
{safePreviewUrl && (
|
|
533
|
+
<div className="mt-4 flex items-center gap-3">
|
|
534
|
+
<label className="flex-shrink-0 text-sm font-semibold text-[#475467]">Zoom</label>
|
|
535
|
+
<input
|
|
536
|
+
type="range"
|
|
537
|
+
min={1}
|
|
538
|
+
max={3}
|
|
539
|
+
step={0.1}
|
|
540
|
+
value={zoom}
|
|
541
|
+
onChange={e => setZoom(Number(e.target.value))}
|
|
542
|
+
className="flex-1 accent-[#3368ef]"
|
|
543
|
+
/>
|
|
544
|
+
</div>
|
|
545
|
+
)}
|
|
429
546
|
</div>
|
|
430
547
|
)}
|
|
431
548
|
</>
|
|
@@ -186,7 +186,7 @@ export function B3DynamicModal() {
|
|
|
186
186
|
<ModalDescription className="sr-only hidden">{contentType?.type || "Modal Body"}</ModalDescription>
|
|
187
187
|
|
|
188
188
|
<div className={cn("no-scrollbar max-h-[90dvh] overflow-auto sm:max-h-[80dvh]")}>
|
|
189
|
-
{
|
|
189
|
+
{!hideCloseButton && (
|
|
190
190
|
<button
|
|
191
191
|
onClick={navigateBack}
|
|
192
192
|
className="flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
|
|
@@ -249,7 +249,7 @@ export const LinkAccount = ({
|
|
|
249
249
|
<Button
|
|
250
250
|
onClick={handleOpenLinkModal}
|
|
251
251
|
disabled={isLinking}
|
|
252
|
-
className="bg-b3-primary-blue hover:bg-b3-primary-blue/90 border-white/12 group relative h-12 w-full rounded-xl border-2 px-[18px] text-base font-semibold text-white shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18),inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] transition-all"
|
|
252
|
+
className="b3-modal-link-new-account-button bg-b3-primary-blue hover:bg-b3-primary-blue/90 border-white/12 group relative h-12 w-full rounded-xl border-2 px-[18px] text-base font-semibold text-white shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18),inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] transition-all"
|
|
253
253
|
>
|
|
254
254
|
<div className="flex items-center justify-center gap-1.5">
|
|
255
255
|
<svg
|
|
@@ -44,7 +44,7 @@ const BottomNavigation = () => {
|
|
|
44
44
|
const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
|
|
45
45
|
|
|
46
46
|
return (
|
|
47
|
-
<div className="sticky bottom-0 left-0 w-full rounded-b-xl border-t border-gray-200 bg-[#FAFAFA]">
|
|
47
|
+
<div className="b3-modal-bottom-navigation sticky bottom-0 left-0 w-full rounded-b-xl border-t border-gray-200 bg-[#FAFAFA]">
|
|
48
48
|
<TabsListPrimitive className="flex h-[68px] w-full items-center justify-center gap-4 border-none bg-transparent">
|
|
49
49
|
<TabTriggerPrimitive
|
|
50
50
|
value="home"
|
|
@@ -58,9 +58,9 @@ function WalletItem({ wallet, isActive, onClick }: { wallet: Wallet; isActive: b
|
|
|
58
58
|
|
|
59
59
|
return (
|
|
60
60
|
<div
|
|
61
|
-
className={`
|
|
62
|
-
isActive ? "bg-[#F4F4F5]" : "hover:bg-b3-line/50"
|
|
63
|
-
}`}
|
|
61
|
+
className={`b3-modal-wallet-item ${
|
|
62
|
+
isActive ? "b3-modal-wallet-item-active bg-[#F4F4F5]" : "hover:bg-b3-line/50"
|
|
63
|
+
} box-border flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 transition-colors`}
|
|
64
64
|
onClick={onClick}
|
|
65
65
|
>
|
|
66
66
|
<div className="relative size-10 shrink-0 overflow-clip rounded-full">
|
|
@@ -137,11 +137,11 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
|
|
|
137
137
|
type="single"
|
|
138
138
|
collapsible
|
|
139
139
|
value={isExpanded ? "wallet-switcher" : ""}
|
|
140
|
-
className="bg-b3-background border-b3-line relative border-b"
|
|
140
|
+
className="b3-modal-wallet-switcher bg-b3-background border-b3-line relative border-b"
|
|
141
141
|
onValueChange={(value: string) => setIsExpanded(value === "wallet-switcher")}
|
|
142
142
|
>
|
|
143
143
|
<AccordionPrimitive.Item value="wallet-switcher" className="border-none">
|
|
144
|
-
<AccordionPrimitive.Trigger className="group flex w-full items-center justify-between border-none bg-transparent px-5 py-3 outline-none">
|
|
144
|
+
<AccordionPrimitive.Trigger className="b3-modal-wallet-switcher-trigger group flex w-full items-center justify-between border-none bg-transparent px-5 py-3 outline-none">
|
|
145
145
|
<div className="flex items-center gap-2">
|
|
146
146
|
<div className="relative size-10 shrink-0 overflow-clip rounded-full">
|
|
147
147
|
{isActiveGlobalAccount ? (
|
|
@@ -166,7 +166,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
|
|
|
166
166
|
</div>
|
|
167
167
|
</div>
|
|
168
168
|
</div>
|
|
169
|
-
<ChevronDownIcon className="text-b3-grey transition-transform duration-200 group-data-[state=open]:rotate-180" />
|
|
169
|
+
<ChevronDownIcon className="b3-modal-wallet-switcher-chevron text-b3-grey transition-transform duration-200 group-data-[state=open]:rotate-180" />
|
|
170
170
|
</AccordionPrimitive.Trigger>
|
|
171
171
|
|
|
172
172
|
<AnimatePresence>
|
|
@@ -177,7 +177,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
|
|
|
177
177
|
animate={{ opacity: 1, y: 0 }}
|
|
178
178
|
exit={{ opacity: 0, y: -10 }}
|
|
179
179
|
transition={{ duration: 0.2, ease: "easeInOut" }}
|
|
180
|
-
className="flex flex-col gap-3 rounded-bl-3xl rounded-br-3xl bg-white px-2 pb-5 pt-3 shadow-[0px_32px_64px_-12px_rgba(10,13,18,0.14),0px_5px_5px_-2.5px_rgba(10,13,18,0.04)]"
|
|
180
|
+
className="b3-modal-wallet-switcher-content flex flex-col gap-3 rounded-bl-3xl rounded-br-3xl bg-white px-2 pb-5 pt-3 shadow-[0px_32px_64px_-12px_rgba(10,13,18,0.14),0px_5px_5px_-2.5px_rgba(10,13,18,0.04)]"
|
|
181
181
|
>
|
|
182
182
|
{/* Connected Wallets */}
|
|
183
183
|
<div className="flex flex-col gap-3">
|
|
@@ -192,7 +192,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
|
|
|
192
192
|
|
|
193
193
|
{/* Link Another Wallet */}
|
|
194
194
|
<div
|
|
195
|
-
className="hover:bg-b3-line/50 box-border flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 transition-colors"
|
|
195
|
+
className="b3-modal-link-another-wallet hover:bg-b3-line/50 box-border flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 transition-colors"
|
|
196
196
|
onClick={handleLinkWallet}
|
|
197
197
|
>
|
|
198
198
|
<div className="bg-b3-line flex size-10 shrink-0 items-center justify-center rounded-full">
|
|
@@ -206,7 +206,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
|
|
|
206
206
|
|
|
207
207
|
{/* Sign Out Button */}
|
|
208
208
|
<button
|
|
209
|
-
className="border-b3-line hover:bg-b3-line bg-b3-background flex items-center justify-center gap-1.5 rounded-xl border border-solid p-2.5 transition-colors"
|
|
209
|
+
className="b3-modal-sign-out-button border-b3-line hover:bg-b3-line bg-b3-background flex items-center justify-center gap-1.5 rounded-xl border border-solid p-2.5 transition-colors"
|
|
210
210
|
onClick={onLogoutEnhanced}
|
|
211
211
|
disabled={logoutLoading}
|
|
212
212
|
style={{
|
|
@@ -41,7 +41,7 @@ const HomeActionButton = ({
|
|
|
41
41
|
return (
|
|
42
42
|
<Button
|
|
43
43
|
className={cn(
|
|
44
|
-
"border-b3-line hover:border-b3-primary-blue
|
|
44
|
+
"border-b3-line hover:border-b3-primary-blue flex h-[84px] w-full flex-col items-center justify-center gap-2 rounded-2xl border-[1.5px] bg-[#FAFAFA] shadow-[0_0_0_1px_rgba(10,13,18,0.18)_inset,0_-2px_0_0_rgba(10,13,18,0.05)_inset,0_1px_2px_0_rgba(10,13,18,0.05)] hover:bg-[#FAFAFA]",
|
|
45
45
|
customClass,
|
|
46
46
|
)}
|
|
47
47
|
onClick={onClick}
|
|
@@ -57,7 +57,7 @@ const HomeActions = ({ showDeposit, showSwap }: { showDeposit: boolean; showSwap
|
|
|
57
57
|
const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
|
|
58
58
|
|
|
59
59
|
return (
|
|
60
|
-
<div className="border-b3-line grid grid-cols-4 gap-3 border-b px-5 pb-6">
|
|
60
|
+
<div className="b3-modal-home-actions border-b3-line grid grid-cols-4 gap-3 border-b px-5 pb-6">
|
|
61
61
|
{showDeposit && (
|
|
62
62
|
<HomeActionButton
|
|
63
63
|
customClass="manage-account-deposit"
|
|
@@ -18,9 +18,9 @@ export function HomeContent({ showDeposit = false, showSwap = true }: HomeConten
|
|
|
18
18
|
<ProfileSection />
|
|
19
19
|
|
|
20
20
|
<HomeActions showDeposit={showDeposit} showSwap={showSwap} />
|
|
21
|
-
<div className="space-y-2 p-5">
|
|
21
|
+
<div className="b3-modal-balance-content space-y-2 p-5">
|
|
22
22
|
<Tabs defaultValue={"balance"}>
|
|
23
|
-
<TabsList>
|
|
23
|
+
<TabsList className="b3-modal-balance-tabs-list">
|
|
24
24
|
<TabTrigger value="balance" className="font-neue-montreal-semibold p-0 pr-3">
|
|
25
25
|
Balance
|
|
26
26
|
</TabTrigger>
|
|
@@ -49,7 +49,12 @@ const ProfileSection = () => {
|
|
|
49
49
|
<div className="flex items-center justify-between px-5 py-6">
|
|
50
50
|
<div className="global-account-profile flex items-center gap-4">
|
|
51
51
|
<div className="global-account-profile-avatar relative">
|
|
52
|
-
<IPFSMediaRenderer
|
|
52
|
+
<IPFSMediaRenderer
|
|
53
|
+
src={avatarSrc}
|
|
54
|
+
alt="Profile Avatar"
|
|
55
|
+
className="border-b3-line border-1 bg-b3-primary-wash size-14 rounded-full border"
|
|
56
|
+
/>
|
|
57
|
+
|
|
53
58
|
<button
|
|
54
59
|
onClick={handleEditAvatar}
|
|
55
60
|
className="border-b3-background hover:bg-b3-grey/80 absolute -bottom-1 -right-1 flex size-6 items-center justify-center rounded-full border-4 bg-[#a0a0ab] transition-colors"
|
|
@@ -62,7 +67,9 @@ const ProfileSection = () => {
|
|
|
62
67
|
<div className="text-b3-foreground-muted"> $</div>
|
|
63
68
|
<div className="text-[30px]">{formatDisplayNumber(totalBalanceUsd, { fractionDigits: 2 })}</div>
|
|
64
69
|
</h2>
|
|
65
|
-
<div className="font-neue-montreal-semibold text-base leading-none text-[#0B57C2]">
|
|
70
|
+
<div className="b3-modal-username font-neue-montreal-semibold text-base leading-none text-[#0B57C2]">
|
|
71
|
+
{currentUsername}
|
|
72
|
+
</div>
|
|
66
73
|
</div>
|
|
67
74
|
</div>
|
|
68
75
|
</div>
|
|
@@ -50,11 +50,11 @@ const SettingsContent = ({
|
|
|
50
50
|
|
|
51
51
|
return (
|
|
52
52
|
<div className="flex h-[470px] flex-col">
|
|
53
|
-
<ModalHeader title="Settings" />
|
|
53
|
+
<ModalHeader showBackButton={false} showCloseButton={false} title="Settings" />
|
|
54
54
|
|
|
55
55
|
{/* Profile Section */}
|
|
56
56
|
<div className="p-5">
|
|
57
|
-
<div className="flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4">
|
|
57
|
+
<div className="b3-modal-settings-profile-card flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4">
|
|
58
58
|
<SettingsProfileCard />
|
|
59
59
|
</div>
|
|
60
60
|
</div>
|
|
@@ -12,7 +12,7 @@ const SettingsMenuItem = ({ icon, title, subtitle, onClick }: SettingsMenuItemPr
|
|
|
12
12
|
return (
|
|
13
13
|
<button
|
|
14
14
|
onClick={onClick}
|
|
15
|
-
className="flex w-full items-center gap-2 rounded-xl px-3 py-2 transition-colors hover:bg-[#f4f4f5]"
|
|
15
|
+
className="b3-modal-settings-menu-item flex w-full items-center gap-2 rounded-xl px-3 py-2 transition-colors hover:bg-[#f4f4f5]"
|
|
16
16
|
>
|
|
17
17
|
<div className="flex size-10 items-center justify-center rounded-full bg-[#f4f4f5]">{icon}</div>
|
|
18
18
|
<div className="flex flex-1 flex-col items-start gap-1 text-left">
|
|
@@ -162,7 +162,9 @@ const SettingsProfileCard = () => {
|
|
|
162
162
|
/* Display mode */
|
|
163
163
|
<>
|
|
164
164
|
<div className="flex items-center gap-1">
|
|
165
|
-
<p className="font-neue-montreal-semibold text-lg leading-none text-[#0B57C2]">
|
|
165
|
+
<p className="b3-modal-username font-neue-montreal-semibold text-lg leading-none text-[#0B57C2]">
|
|
166
|
+
{currentUsername}
|
|
167
|
+
</p>
|
|
166
168
|
</div>
|
|
167
169
|
<button
|
|
168
170
|
onClick={handleEditUsername}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { cn } from "@b3dotfun/sdk/shared/utils";
|
|
2
|
-
import {
|
|
2
|
+
import { ChevronLeft, X } from "lucide-react";
|
|
3
3
|
import { useModalStore } from "../../stores";
|
|
4
4
|
|
|
5
5
|
const ModalHeader = ({
|
|
6
|
+
showBackButton = true,
|
|
6
7
|
handleBack,
|
|
7
8
|
handleClose,
|
|
8
9
|
title,
|
|
@@ -11,6 +12,7 @@ const ModalHeader = ({
|
|
|
11
12
|
className,
|
|
12
13
|
showBackWord = false,
|
|
13
14
|
}: {
|
|
15
|
+
showBackButton?: boolean;
|
|
14
16
|
handleBack?: () => void;
|
|
15
17
|
handleClose?: () => void;
|
|
16
18
|
title: string;
|
|
@@ -24,23 +26,32 @@ const ModalHeader = ({
|
|
|
24
26
|
|
|
25
27
|
return (
|
|
26
28
|
<div
|
|
27
|
-
className={cn(
|
|
29
|
+
className={cn(
|
|
30
|
+
"b3-modal-header flex h-16 items-center justify-between border-b border-[#e4e4e7] bg-white px-5 py-3",
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
28
33
|
>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
{showBackButton ? (
|
|
35
|
+
<button
|
|
36
|
+
onClick={handleBack || navigateBack}
|
|
37
|
+
className="flex h-6 w-6 items-center justify-center transition-opacity hover:opacity-70"
|
|
38
|
+
>
|
|
39
|
+
<ChevronLeft className="h-6 w-6 text-[#51525c]" />
|
|
40
|
+
{showBackWord && <span className="text-sm font-medium">Back</span>}
|
|
41
|
+
</button>
|
|
42
|
+
) : (
|
|
43
|
+
<div className="w-2" />
|
|
44
|
+
)}
|
|
36
45
|
<p className="font-inter text-lg font-semibold leading-7 text-[#18181b]">{title}</p>
|
|
37
|
-
{showCloseButton
|
|
46
|
+
{showCloseButton ? (
|
|
38
47
|
<button
|
|
39
48
|
onClick={handleClose || (() => setB3ModalOpen(false))}
|
|
40
49
|
className="flex h-6 w-6 items-center justify-center transition-opacity hover:opacity-70"
|
|
41
50
|
>
|
|
42
51
|
<X className="h-6 w-6 text-[#51525c]" />
|
|
43
52
|
</button>
|
|
53
|
+
) : (
|
|
54
|
+
<div className="w-2" />
|
|
44
55
|
)}
|
|
45
56
|
{children}
|
|
46
57
|
</div>
|
|
@@ -60,7 +60,7 @@ const DialogContent: React.ForwardRefExoticComponent<DialogContentProps & React.
|
|
|
60
60
|
)}
|
|
61
61
|
{...props}
|
|
62
62
|
>
|
|
63
|
-
<div className="flex flex-1 flex-col overflow-hidden rounded-xl border border-[#D1D1D6] bg-white shadow-[0_20px_24px_-4px_rgba(10,13,18,0.08),0_8px_8px_-4px_rgba(10,13,18,0.03),0_3px_3px_-1.5px_rgba(10,13,18,0.04)]">
|
|
63
|
+
<div className="modal-inner-content flex flex-1 flex-col overflow-hidden rounded-xl border border-[#D1D1D6] bg-white shadow-[0_20px_24px_-4px_rgba(10,13,18,0.08),0_8px_8px_-4px_rgba(10,13,18,0.03),0_3px_3px_-1.5px_rgba(10,13,18,0.04)]">
|
|
64
64
|
{children}
|
|
65
65
|
{!hideCloseButton && (
|
|
66
66
|
<DialogPrimitive.Close
|
|
@@ -75,7 +75,7 @@ const DialogContent: React.ForwardRefExoticComponent<DialogContentProps & React.
|
|
|
75
75
|
)}
|
|
76
76
|
</div>
|
|
77
77
|
{/* Global Account Footer */}
|
|
78
|
-
<div className="flex items-center justify-center gap-1.5 pt-[10px]">
|
|
78
|
+
<div className="b3-modal-ga-branding flex items-center justify-center gap-1.5 pt-[10px]">
|
|
79
79
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
80
80
|
<path
|
|
81
81
|
d="M2 4.66667C2 3.19391 3.19391 2 4.66667 2H11.3333C12.8061 2 14 3.19391 14 4.66667V11.3333C14 12.8061 12.8061 14 11.3333 14H4.66667C3.19391 14 2 12.8061 2 11.3333V4.66667Z"
|
|
@@ -35,7 +35,7 @@ const DrawerContent = React.forwardRef<
|
|
|
35
35
|
<DrawerPrimitive.Content
|
|
36
36
|
ref={ref}
|
|
37
37
|
className={cn(
|
|
38
|
-
"bg-b3-react-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border py-6",
|
|
38
|
+
"bg-b3-react-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border py-6 pt-5",
|
|
39
39
|
className,
|
|
40
40
|
)}
|
|
41
41
|
{...props}
|