Skip to content

Commit 76c0e00

Browse files
committed
Merge branch 'main' into 05-30-wip_brige_embed
2 parents a675f08 + 8489844 commit 76c0e00

File tree

101 files changed

+5106
-1381
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+5106
-1381
lines changed

.changeset/better-owls-flash.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
- Add support for blob urls in `MediaRenderer` component
6+
- Fix `className` prop not set in loading state of `MediaRenderer` component

apps/dashboard/framer-rewrites.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ module.exports = [
4040
"/community/ambassadors",
4141
"/community/startup-program",
4242
// -- grants --
43-
"/grant/superchain",
43+
"/grants",
44+
"/superchain",
4445
// -- templates --
4546
"/templates",
4647
"/templates/:template_slug",

apps/dashboard/redirects.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,12 @@ async function redirects() {
368368
destination: "/learn/guides",
369369
permanent: false,
370370
},
371+
// redirect to /grant/superchain to /superchain
372+
{
373+
source: "/grant/superchain",
374+
destination: "/superchain",
375+
permanent: false,
376+
},
371377

372378
...legacyDashboardToTeamRedirects,
373379
];

apps/dashboard/src/@/components/blocks/Img.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type imgElementProps = React.DetailedHTMLProps<
1111
skeleton?: React.ReactNode;
1212
fallback?: React.ReactNode;
1313
src: string | undefined;
14+
containerClassName?: string;
1415
};
1516

1617
export function Img(props: imgElementProps) {
@@ -23,7 +24,8 @@ export function Img(props: imgElementProps) {
2324
: props.src === ""
2425
? "fallback"
2526
: _status;
26-
const { className, fallback, skeleton, ...restProps } = props;
27+
const { className, fallback, skeleton, containerClassName, ...restProps } =
28+
props;
2729
const defaultSkeleton = <div className="animate-pulse bg-accent" />;
2830
const defaultFallback = <div className="bg-accent" />;
2931
const imgRef = useRef<HTMLImageElement>(null);
@@ -47,7 +49,7 @@ export function Img(props: imgElementProps) {
4749
}, []);
4850

4951
return (
50-
<div className="relative shrink-0">
52+
<div className={cn("relative shrink-0", containerClassName)}>
5153
<img
5254
{...restProps}
5355
// avoid setting empty src string to prevent request to the entire page

apps/dashboard/src/@/components/blocks/TokenSelector.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,17 @@ export function TokenSelector(props: {
159159
? `${props.selectedToken.chainId}:${props.selectedToken.address}`
160160
: undefined;
161161

162+
// if selected value is not in options, add it
163+
if (
164+
selectedValue &&
165+
!options.find((option) => option.value === selectedValue)
166+
) {
167+
options.push({
168+
label: props.selectedToken?.address || "Unknown",
169+
value: selectedValue,
170+
});
171+
}
172+
162173
return (
163174
<SelectWithSearch
164175
searchPlaceholder="Search by name or symbol"
@@ -175,7 +186,7 @@ export function TokenSelector(props: {
175186
showCheck={props.showCheck}
176187
placeholder={
177188
tokensQuery.isPending
178-
? "Loading Tokens..."
189+
? "Loading Tokens"
179190
: props.placeholder || "Select Token"
180191
}
181192
overrideSearchFn={searchFn}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { DropZone } from "./drop-zone";
3+
4+
const meta = {
5+
title: "blocks/DropZone",
6+
component: DropZone,
7+
decorators: [
8+
(Story) => (
9+
<div className="container max-w-6xl py-10">
10+
<Story />
11+
</div>
12+
),
13+
],
14+
} satisfies Meta<typeof DropZone>;
15+
16+
export default meta;
17+
type Story = StoryObj<typeof meta>;
18+
19+
export const Default: Story = {
20+
args: {
21+
isError: false,
22+
onDrop: () => {},
23+
title: "This is a title",
24+
description: "This is a description for drop zone",
25+
accept: undefined,
26+
resetButton: undefined,
27+
},
28+
};
29+
30+
export const ErrorState: Story = {
31+
args: {
32+
isError: true,
33+
onDrop: () => {},
34+
title: "this is title",
35+
description: "This is a description",
36+
accept: undefined,
37+
resetButton: undefined,
38+
},
39+
};
40+
41+
export const ErrorStateWithResetButton: Story = {
42+
args: {
43+
isError: true,
44+
onDrop: () => {},
45+
title: "this is title",
46+
description: "This is a description",
47+
accept: undefined,
48+
resetButton: {
49+
label: "Remove Files",
50+
onClick: () => {},
51+
},
52+
},
53+
};
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { Button } from "@/components/ui/button";
2+
import { cn } from "@/lib/utils";
3+
import { UploadIcon, XIcon } from "lucide-react";
4+
import { useDropzone } from "react-dropzone";
5+
6+
export function DropZone(props: {
7+
isError: boolean;
8+
onDrop: (acceptedFiles: File[]) => void;
9+
title: string;
10+
description: string;
11+
resetButton:
12+
| {
13+
label: string;
14+
onClick: () => void;
15+
}
16+
| undefined;
17+
className?: string;
18+
accept: string | undefined;
19+
}) {
20+
const { getRootProps, getInputProps } = useDropzone({
21+
onDrop: props.onDrop,
22+
});
23+
24+
const { resetButton } = props;
25+
26+
return (
27+
<div
28+
className={cn(
29+
"flex cursor-pointer items-center justify-center rounded-md border border-dashed bg-card py-10 hover:border-active-border",
30+
props.isError &&
31+
"border-red-500 bg-red-200/30 text-red-500 hover:border-red-600 dark:border-red-900 dark:bg-red-900/30 dark:hover:border-red-800",
32+
props.className,
33+
)}
34+
{...getRootProps()}
35+
>
36+
<input {...getInputProps()} accept={props.accept} />
37+
<div className="flex flex-col items-center justify-center gap-3">
38+
{!props.isError && (
39+
<div className="flex flex-col items-center">
40+
<div className="mb-3 flex size-11 items-center justify-center rounded-full border bg-card">
41+
<UploadIcon className="size-5" />
42+
</div>
43+
<h2 className="mb-0.5 text-center font-medium text-lg">
44+
{props.title}
45+
</h2>
46+
<p className="text-center font-medium text-muted-foreground text-sm">
47+
{props.description}
48+
</p>
49+
</div>
50+
)}
51+
52+
{props.isError && (
53+
<div className="flex flex-col items-center">
54+
<div className="mb-3 flex size-11 items-center justify-center rounded-full border border-red-500 bg-red-200/50 text-red-500 dark:border-red-900 dark:bg-red-900/30 dark:text-foreground">
55+
<XIcon className="size-5" />
56+
</div>
57+
<h2 className="mb-0.5 text-center font-medium text-foreground text-lg">
58+
{props.title}
59+
</h2>
60+
<p className="text-balance text-center text-sm">
61+
{props.description}
62+
</p>
63+
64+
{resetButton && (
65+
<Button
66+
className="relative z-50 mt-4"
67+
size="sm"
68+
onClick={(e) => {
69+
e.stopPropagation();
70+
resetButton.onClick();
71+
}}
72+
>
73+
{resetButton.label}
74+
</Button>
75+
)}
76+
</div>
77+
)}
78+
</div>
79+
</div>
80+
);
81+
}

apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.stories.tsx

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,45 +16,34 @@ const meta = {
1616
export default meta;
1717
type Story = StoryObj<typeof meta>;
1818

19-
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
20-
2119
export const AllStates: Story = {
2220
args: {
21+
onRetry: () => {},
2322
steps: [
2423
{
2524
status: { type: "completed" },
2625
label: "Connect Wallet",
27-
execute: async () => {
28-
await sleep(1000);
29-
},
26+
id: "connect-wallet",
3027
},
3128
{
3229
status: { type: "pending" },
3330
label: "Sign Message",
34-
execute: async () => {
35-
await sleep(1000);
36-
},
31+
id: "sign-message",
3732
},
3833
{
3934
status: { type: "error", message: "This is an error message" },
4035
label: "Approve Transaction",
41-
execute: async () => {
42-
await sleep(1000);
43-
},
36+
id: "approve-transaction",
4437
},
4538
{
4639
status: { type: "idle" },
4740
label: "Confirm Transaction",
48-
execute: async () => {
49-
await sleep(1000);
50-
},
41+
id: "confirm-transaction",
5142
},
5243
{
5344
status: { type: "idle" },
5445
label: "Finalize",
55-
execute: async () => {
56-
await sleep(1000);
57-
},
46+
id: "finalize",
5847
},
5948
],
6049
},

apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,23 @@ import {
1010
import { DynamicHeight } from "../../ui/DynamicHeight";
1111
import { Spinner } from "../../ui/Spinner/Spinner";
1212

13-
export type MultiStepState = {
13+
export type MultiStepState<T extends string> = {
14+
id: T;
1415
status:
1516
| {
1617
type: "idle" | "pending" | "completed";
1718
}
1819
| {
1920
type: "error";
20-
message: string | React.ReactNode;
21+
message: React.ReactNode;
2122
};
2223
label: string;
23-
execute: () => Promise<void>;
24+
description?: string;
2425
};
2526

26-
export function MultiStepStatus(props: {
27-
steps: MultiStepState[];
27+
export function MultiStepStatus<T extends string>(props: {
28+
steps: MultiStepState<T>[];
29+
onRetry: (step: MultiStepState<T>) => void;
2830
}) {
2931
return (
3032
<DynamicHeight>
@@ -55,6 +57,15 @@ export function MultiStepStatus(props: {
5557
{step.label}
5658
</p>
5759

60+
{/* show description when this step is active */}
61+
{(step.status.type === "pending" ||
62+
step.status.type === "error") &&
63+
step.description && (
64+
<p className="text-muted-foreground text-sm">
65+
{step.description}
66+
</p>
67+
)}
68+
5869
{step.status.type === "error" && (
5970
<div className="mt-1 space-y-2">
6071
<p className="mb-1 text-red-500 text-sm">
@@ -64,7 +75,7 @@ export function MultiStepStatus(props: {
6475
variant="destructive"
6576
size="sm"
6677
className="gap-2"
67-
onClick={() => step.execute()}
78+
onClick={() => props.onRetry(step)}
6879
>
6980
<RefreshCwIcon className="size-4" />
7081
Retry

0 commit comments

Comments
 (0)