Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98f2b56c19 | ||
|
|
500970e001 | ||
|
|
9c58c08945 | ||
|
|
587804d5a8 | ||
|
|
3f83a377bc | ||
|
|
5ab3a81f79 | ||
|
|
931569b374 | ||
|
|
d76618fc00 | ||
|
|
46acf33b5a | ||
|
|
10a84d2810 | ||
|
|
3e8c074011 | ||
|
|
206340cc1d | ||
|
|
6153d57c34 | ||
|
|
39aeb140d2 | ||
|
|
8e9d13c95c | ||
|
|
d35f0b2cc6 | ||
|
|
2f010fa3fc | ||
|
|
944d56f6d8 | ||
|
|
1f1f99ddd0 | ||
|
|
de63195d43 | ||
|
|
e2b3484764 | ||
|
|
c0d81dcaca | ||
|
|
0aea48e37d | ||
|
|
f91e32f133 | ||
|
|
e38400195f | ||
|
|
e02d87b831 | ||
|
|
d5312304f7 | ||
|
|
b80b61b0a6 | ||
|
|
d37e3fe6e3 | ||
|
|
3b91dad963 |
@@ -57,6 +57,9 @@ module.exports = {
|
||||
"MenuItem",
|
||||
"VStack",
|
||||
"HStack",
|
||||
"AspectRatio",
|
||||
"useToast",
|
||||
"useClipboard",
|
||||
// also the types
|
||||
"ButtonProps",
|
||||
"BadgeProps",
|
||||
@@ -67,6 +70,7 @@ module.exports = {
|
||||
"HelpTextProps",
|
||||
"MenuGroupProps",
|
||||
"MenuItemProps",
|
||||
"AspectRatioProps",
|
||||
],
|
||||
message:
|
||||
'Use the equivalent component from "tw-components" instead.',
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"start": "next start",
|
||||
"format": "biome format ./src --write",
|
||||
"lint": "biome check ./src && knip && eslint ./src",
|
||||
"fix": "biome check ./src --fix --unsafe && eslint ./src --fix",
|
||||
"fix": "biome check ./src --fix && eslint ./src --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"gen:theme-typings": "chakra-cli tokens src/theme/index.ts",
|
||||
"postinstall": "pnpm run gen:theme-typings",
|
||||
@@ -31,7 +31,6 @@
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@n8tb1t/use-scroll-position": "^2.0.3",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.1",
|
||||
"@radix-ui/react-aspect-ratio": "^1.0.3",
|
||||
"@radix-ui/react-avatar": "^1.1.0",
|
||||
"@radix-ui/react-checkbox": "^1.1.1",
|
||||
"@radix-ui/react-dialog": "1.1.1",
|
||||
@@ -138,7 +137,7 @@
|
||||
"eslint-config-biome": "1.8.4",
|
||||
"eslint-plugin-react-compiler": "0.0.0-experimental-ca16900-20240916",
|
||||
"eslint-plugin-storybook": "^0.8.0",
|
||||
"knip": "^5.30.4",
|
||||
"knip": "^5.30.5",
|
||||
"next-sitemap": "^4.2.3",
|
||||
"postcss": "8.4.47",
|
||||
"storybook": "8.3.2",
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { ImageIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { BadgeContainer } from "../../../stories/utils";
|
||||
import { Spinner } from "../ui/Spinner/Spinner";
|
||||
import { Button } from "../ui/button";
|
||||
import { Img } from "./Img";
|
||||
|
||||
const meta = {
|
||||
title: "blocks/Img",
|
||||
component: Story,
|
||||
parameters: {},
|
||||
} satisfies Meta<typeof Story>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Desktop: Story = {
|
||||
args: {},
|
||||
};
|
||||
|
||||
function Story() {
|
||||
return (
|
||||
<div className="flex flex-col gap-10 p-10">
|
||||
<p> All images below are set with size-20 className </p>
|
||||
|
||||
<BadgeContainer label="No Src - pending">
|
||||
<Img className="size-20" src={undefined} />
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="Failed to load - fallback">
|
||||
<Img className="size-20" src="invalid-src" />
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="No Src, pending - rounded-full">
|
||||
<Img className="size-20 rounded-full" src={undefined} />
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="Failed to load - fallback - rounded-full">
|
||||
<Img className="size-20 rounded-full" src="invalid-src" />
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="Valid Src">
|
||||
<Img className="size-20" src="https://picsum.photos/200" />
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="Valid Src, rounded">
|
||||
<Img className="size-20 rounded-full" src="https://picsum.photos/200" />
|
||||
</BadgeContainer>
|
||||
|
||||
<ToggleTest />
|
||||
|
||||
<BadgeContainer label="Custom Skeleton">
|
||||
<Img
|
||||
src={undefined}
|
||||
skeleton={
|
||||
<div className="flex items-center justify-center rounded-lg border">
|
||||
<Spinner className="size-6" />
|
||||
</div>
|
||||
}
|
||||
className="size-20"
|
||||
/>
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="Custom Fallback">
|
||||
<Img
|
||||
fallback={
|
||||
<div className="flex items-center justify-center rounded-lg border">
|
||||
<ImageIcon className="size-10 text-muted-foreground" />
|
||||
</div>
|
||||
}
|
||||
className="size-20"
|
||||
src="invalid-src"
|
||||
/>
|
||||
</BadgeContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ToggleTest() {
|
||||
const [src, setSrc] = useState<undefined | string>(undefined);
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col gap-10 border p-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
if (src) {
|
||||
setSrc(undefined);
|
||||
} else {
|
||||
setSrc("https://picsum.photos/400");
|
||||
}
|
||||
}}
|
||||
className="absolute top-6 right-6 inline-flex"
|
||||
>
|
||||
Toggle Src
|
||||
</Button>
|
||||
|
||||
<p> Src is {src ? "set" : "not set"} </p>
|
||||
|
||||
<BadgeContainer label="Valid Src">
|
||||
<Img className="size-20" src={src} />
|
||||
</BadgeContainer>
|
||||
|
||||
<BadgeContainer label="invalid Src">
|
||||
<Img
|
||||
className="size-20 rounded-full"
|
||||
src={src ? "invalid-src" : undefined}
|
||||
/>
|
||||
</BadgeContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
type imgElementProps = React.DetailedHTMLProps<
|
||||
React.ImgHTMLAttributes<HTMLImageElement>,
|
||||
HTMLImageElement
|
||||
> & {
|
||||
skeleton?: React.ReactNode;
|
||||
fallback?: React.ReactNode;
|
||||
src: string | undefined;
|
||||
};
|
||||
|
||||
export function Img(props: imgElementProps) {
|
||||
const [_status, setStatus] = useState<"pending" | "fallback" | "loaded">(
|
||||
"pending",
|
||||
);
|
||||
const status =
|
||||
props.src === undefined
|
||||
? "pending"
|
||||
: props.src === ""
|
||||
? "fallback"
|
||||
: _status;
|
||||
const { className, fallback, skeleton, ...restProps } = props;
|
||||
const defaultSkeleton = <div className="animate-pulse bg-accent" />;
|
||||
const defaultFallback = <div className="bg-muted" />;
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<img
|
||||
{...restProps}
|
||||
onLoad={() => {
|
||||
setStatus("loaded");
|
||||
}}
|
||||
onError={() => {
|
||||
setStatus("fallback");
|
||||
}}
|
||||
style={{
|
||||
opacity: status === "loaded" ? 1 : 0,
|
||||
}}
|
||||
alt={restProps.alt || ""}
|
||||
className={cn(
|
||||
"fade-in-0 object-cover transition-opacity duration-300",
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
|
||||
{status !== "loaded" && (
|
||||
<div
|
||||
className={cn(
|
||||
"fade-in-0 absolute inset-0 overflow-hidden transition-opacity duration-300 [&>*]:h-full [&>*]:w-full",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{status === "pending" && (skeleton || defaultSkeleton)}
|
||||
{status === "fallback" && (fallback || defaultFallback)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio";
|
||||
|
||||
const AspectRatio = AspectRatioPrimitive.Root;
|
||||
|
||||
export { AspectRatio };
|
||||
+2
-2
@@ -141,7 +141,7 @@ export function FaucetButton({
|
||||
<Button variant="outline" className="!opacity-100 w-full " disabled>
|
||||
{canClaimFaucetQuery.data.type === "throttle" && (
|
||||
<>
|
||||
Your next claim is available
|
||||
Your next claim is available{" "}
|
||||
{formatTime(canClaimFaucetQuery.data.ttlSeconds)}
|
||||
</>
|
||||
)}
|
||||
@@ -186,7 +186,7 @@ export function FaucetButton({
|
||||
|
||||
{faucetWalletBalanceQuery.data && (
|
||||
<p className="mt-3 text-muted-foreground text-xs">
|
||||
{Number(faucetWalletBalanceQuery.data.displayValue).toFixed(3)}
|
||||
{Number(faucetWalletBalanceQuery.data.displayValue).toFixed(3)}{" "}
|
||||
{faucetWalletBalanceQuery.data.symbol} left in the faucet
|
||||
</p>
|
||||
)}
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ export async function FaucetSection(props: { chain: ChainMetadata }) {
|
||||
<div className="h-2" />
|
||||
|
||||
<p className="max-w-[520px] px-4 text-center text-muted-foreground text-sm">
|
||||
Get free {chain.nativeCurrency.symbol} fast and reliably.
|
||||
Get free {chain.nativeCurrency.symbol} fast and reliably.{" "}
|
||||
{amountToGive} {chain.nativeCurrency.symbol}/day.
|
||||
</p>
|
||||
|
||||
|
||||
+6
-5
@@ -1,4 +1,3 @@
|
||||
import { AspectRatio } from "@/components/ui/aspect-ratio";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Link from "next/link";
|
||||
@@ -20,9 +19,11 @@ export function ChainHeader(props: ChainHeaderProps) {
|
||||
// force the banner image to be 4:1 aspect ratio and full-width on mobile devices
|
||||
<div className="flex flex-col">
|
||||
{!props.headerImageUrl && <div className="h-8 md:hidden" />}
|
||||
<AspectRatio
|
||||
ratio={props.headerImageUrl ? 4 : 8}
|
||||
className="max-sm:-mx-4 border-border border-b"
|
||||
<div
|
||||
className={cn(
|
||||
"max-sm:-mx-4 relative border-border border-b",
|
||||
props.headerImageUrl ? "aspect-[4/1]" : "aspect-[8/1]",
|
||||
)}
|
||||
>
|
||||
{props.headerImageUrl && (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
@@ -32,7 +33,7 @@ export function ChainHeader(props: ChainHeaderProps) {
|
||||
className="h-full w-full object-cover object-center"
|
||||
/>
|
||||
)}
|
||||
</AspectRatio>
|
||||
</div>
|
||||
{/* below header */}
|
||||
<div className="relative flex flex-row items-end justify-end">
|
||||
{/* chain logo */}
|
||||
|
||||
@@ -46,7 +46,7 @@ export default async function Page(props: {
|
||||
<header className="flex flex-col gap-y-2">
|
||||
<p className="font-bold text-3xl">Transaction Details</p>
|
||||
<div className="flex gap-x-2">
|
||||
{shortenAddress(transaction.from)} called on
|
||||
{shortenAddress(transaction.from)} called on{" "}
|
||||
{shortenAddress(transaction.to || ZERO_ADDRESS)}
|
||||
</div>
|
||||
</header>
|
||||
@@ -131,8 +131,8 @@ export default async function Page(props: {
|
||||
<div className="grid grid-cols-2">
|
||||
<div className="flex items-center gap-x-2">Gas fees (Gwei)</div>
|
||||
<p>
|
||||
Base: {toTokens(block.baseFeePerGas || 0n, 9)} | Max:
|
||||
{toTokens(transaction.maxFeePerGas || 0n, 9)} | Max priority:
|
||||
Base: {toTokens(block.baseFeePerGas || 0n, 9)} | Max:{" "}
|
||||
{toTokens(transaction.maxFeePerGas || 0n, 9)} | Max priority:{" "}
|
||||
{transaction.maxPriorityFeePerGas?.toString()}
|
||||
</p>
|
||||
</div>
|
||||
@@ -150,7 +150,7 @@ export default async function Page(props: {
|
||||
<div className="flex items-center gap-x-2">Other</div>
|
||||
<p>
|
||||
Txn type: {hexToNumber(transaction.typeHex || "0x0")} (
|
||||
{transaction.type}) | Nonce: {transaction.nonce} | Position:
|
||||
{transaction.type}) | Nonce: {transaction.nonce} | Position:{" "}
|
||||
{transaction.transactionIndex}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -115,7 +115,7 @@ export default async function ChainListLayout(props: {
|
||||
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div className="flex flex-row items-center justify-between gap-4 lg:flex-col lg:justify-start">
|
||||
<h1 className="font-semibold text-4xl tracking-tighter lg:text-5xl">
|
||||
List of
|
||||
List of{" "}
|
||||
{props.params.chain_type.charAt(0).toUpperCase() +
|
||||
props.params.chain_type.slice(1)}
|
||||
</h1>
|
||||
|
||||
+5
-5
@@ -236,13 +236,13 @@ export async function ChainsData(props: {
|
||||
)}
|
||||
<div className="h-4" />
|
||||
<p className="text-balance text-center text-muted-foreground text-sm">
|
||||
Showing
|
||||
<span className="text-accent-foreground">{paginatedChains.length}</span>
|
||||
out of
|
||||
Showing{" "}
|
||||
<span className="text-accent-foreground">{paginatedChains.length}</span>{" "}
|
||||
out of{" "}
|
||||
{filteredCount !== totalCount ? (
|
||||
<>
|
||||
<span className="text-accent-foreground">{filteredCount}</span>
|
||||
chains that match filters. (Total:
|
||||
<span className="text-accent-foreground">{filteredCount}</span>{" "}
|
||||
chains that match filters. (Total:{" "}
|
||||
<span className="text-accent-foreground">{totalCount}</span>)
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ContractPublishForm } from "components/contract-components/contract-pub
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { redirect } from "next/navigation";
|
||||
import { fetchDeployMetadata } from "thirdweb/contract";
|
||||
import { getPublishedContractsWithPublisherMapping } from "../../../published-contract/[publisher]/[contract_id]/utils/getPublishedContractsWithPublisherMapping";
|
||||
|
||||
type DirectDeployPageProps = {
|
||||
params: {
|
||||
@@ -20,11 +21,13 @@ export default async function PublishContractPage(
|
||||
? decodedPublishUri
|
||||
: `ipfs://${decodedPublishUri}`;
|
||||
|
||||
const publishMetadata = await fetchDeployMetadata({
|
||||
const publishMetadataFromUri = await fetchDeployMetadata({
|
||||
uri: publishUri,
|
||||
client: getThirdwebClient(),
|
||||
});
|
||||
|
||||
let publishMetadata = publishMetadataFromUri;
|
||||
|
||||
const pathname = `/contracts/publish/${props.params.publish_uri}`;
|
||||
|
||||
const address = getActiveAccountCookie();
|
||||
@@ -32,6 +35,29 @@ export default async function PublishContractPage(
|
||||
redirect(`/login?next=${encodeURIComponent(pathname)}`);
|
||||
}
|
||||
|
||||
// Deploying the next version of a contract scenario:
|
||||
// check if this is a pre-deployed metadata ( doesn't have a version )
|
||||
// If that's the case:
|
||||
// - get the publish metadata with name+publisher address
|
||||
// - merge the two objects with publishMetadataFromUri taking higher precedence
|
||||
if (!publishMetadataFromUri.version) {
|
||||
const publishedContractVersions =
|
||||
await getPublishedContractsWithPublisherMapping({
|
||||
publisher: address,
|
||||
contract_id: publishMetadataFromUri.name,
|
||||
});
|
||||
|
||||
const publishedContract = publishedContractVersions[0];
|
||||
|
||||
if (publishedContract) {
|
||||
publishMetadata = {
|
||||
...publishedContract,
|
||||
...publishMetadataFromUri,
|
||||
version: publishedContract.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const token = getJWTCookie(address);
|
||||
if (!token) {
|
||||
redirect(`/login?next=${encodeURIComponent(pathname)}`);
|
||||
|
||||
+2
@@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
import { AuthOptionsSection } from "./components/server/auth-options-section";
|
||||
import { EcosystemPartnersSection } from "./components/server/ecosystem-partners-section";
|
||||
import { IntegrationPermissionsSection } from "./components/server/integration-permissions-section";
|
||||
import { useEcosystem } from "./hooks/use-ecosystem";
|
||||
@@ -11,6 +12,7 @@ export function EcosystemPermissionsPage({
|
||||
return (
|
||||
<div className="flex flex-col gap-12">
|
||||
<IntegrationPermissionsSection ecosystem={ecosystem} />
|
||||
<AuthOptionsSection ecosystem={ecosystem} />
|
||||
{ecosystem?.permission === "PARTNER_WHITELIST" && (
|
||||
<EcosystemPartnersSection ecosystem={ecosystem} />
|
||||
)}
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
"use client";
|
||||
import { ConfirmationDialog } from "@/components/ui/ConfirmationDialog";
|
||||
import { Checkbox, CheckboxWithLabel } from "@/components/ui/checkbox";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import invariant from "tiny-invariant";
|
||||
import { type Ecosystem, authOptions } from "../../../../types";
|
||||
import { useUpdateEcosystem } from "../../hooks/use-update-ecosystem";
|
||||
|
||||
export function AuthOptionsForm({ ecosystem }: { ecosystem: Ecosystem }) {
|
||||
const [messageToConfirm, setMessageToConfirm] = useState<
|
||||
| {
|
||||
title: string;
|
||||
description: string;
|
||||
authOptions: typeof ecosystem.authOptions;
|
||||
}
|
||||
| undefined
|
||||
>();
|
||||
const {
|
||||
mutateAsync: updateEcosystem,
|
||||
variables,
|
||||
isPending,
|
||||
} = useUpdateEcosystem({
|
||||
onError: (error) => {
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Failed to create ecosystem";
|
||||
toast.error(message);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-5 md:gap-2">
|
||||
{authOptions.map((option) => (
|
||||
<CheckboxWithLabel
|
||||
key={option}
|
||||
className={cn(
|
||||
isPending &&
|
||||
variables?.authOptions?.includes(option) &&
|
||||
"animate-pulse",
|
||||
"hover:cursor-pointer hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
<Checkbox
|
||||
checked={ecosystem.authOptions.includes(option)}
|
||||
onClick={() => {
|
||||
if (ecosystem.authOptions.includes(option)) {
|
||||
setMessageToConfirm({
|
||||
title: `Are you sure you want to remove ${option.slice(0, 1).toUpperCase() + option.slice(1)} as an authentication option for this ecosystem?`,
|
||||
description:
|
||||
"Users will no longer be able to log into your ecosystem using this option. Any users that previously used this option will be unable to log in.",
|
||||
authOptions: ecosystem.authOptions.filter(
|
||||
(o) => o !== option,
|
||||
),
|
||||
});
|
||||
} else {
|
||||
setMessageToConfirm({
|
||||
title: `Are you sure you want to add ${option.slice(0, 1).toUpperCase() + option.slice(1)} as an authentication option for this ecosystem?`,
|
||||
description:
|
||||
"Users will be able to log into your ecosystem using this option. If you later remove this option users that used it will no longer be able to log in.",
|
||||
authOptions: [...ecosystem.authOptions, option],
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{option.slice(0, 1).toUpperCase() + option.slice(1)}
|
||||
</CheckboxWithLabel>
|
||||
))}
|
||||
<ConfirmationDialog
|
||||
open={!!messageToConfirm}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setMessageToConfirm(undefined);
|
||||
}
|
||||
}}
|
||||
title={messageToConfirm?.title}
|
||||
description={messageToConfirm?.description}
|
||||
onSubmit={() => {
|
||||
invariant(messageToConfirm, "Must have message for modal to be open");
|
||||
updateEcosystem({
|
||||
ecosystem,
|
||||
authOptions: messageToConfirm.authOptions,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function AuthOptionsFormSkeleton() {
|
||||
return (
|
||||
<div className="flex flex-col gap-2 py-2 md:flex-row md:gap-4">
|
||||
{authOptions.map((option) => (
|
||||
<Skeleton key={option} className="h-14 w-full md:w-32" />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import type { Ecosystem } from "../../../../types";
|
||||
import {
|
||||
AuthOptionsForm,
|
||||
AuthOptionsFormSkeleton,
|
||||
} from "../client/auth-options-form.client";
|
||||
|
||||
export function AuthOptionsSection({ ecosystem }: { ecosystem?: Ecosystem }) {
|
||||
return (
|
||||
<section className="flex flex-col gap-4 md:gap-8">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h4 className="font-semibold text-2xl text-foreground">
|
||||
Authentication Options
|
||||
</h4>
|
||||
{ecosystem ? (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Configure the authentication options your ecosystem supports.
|
||||
</p>
|
||||
) : (
|
||||
<Skeleton className="h-6 w-[300px]" />
|
||||
)}
|
||||
</div>
|
||||
{ecosystem ? (
|
||||
<AuthOptionsForm ecosystem={ecosystem} />
|
||||
) : (
|
||||
<AuthOptionsFormSkeleton />
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ export function EcosystemPartnersSection({
|
||||
</h4>
|
||||
<p className="text-muted-foreground text-sm leading-normal">
|
||||
Configure apps that can use your wallet. Creating a partner will
|
||||
generate a unique partner ID that can access your ecosystem. <br />
|
||||
generate a unique partner ID that can access your ecosystem. <br />{" "}
|
||||
You will need to generate at least one partner ID for use in your
|
||||
own app.
|
||||
</p>
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ function PartnerRow(props: {
|
||||
description={
|
||||
<span>
|
||||
Their partner key will no longer be able to use your ecosystem
|
||||
wallet. Their users will still have access to their assets at
|
||||
wallet. Their users will still have access to their assets at{" "}
|
||||
<Link
|
||||
href={`https://${props.ecosystem.slug}.ecosystem.thirdweb.com`}
|
||||
target="_blank"
|
||||
|
||||
+4
-2
@@ -4,11 +4,12 @@ import {
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
import type { Ecosystem } from "../../../types";
|
||||
import type { AuthOption, Ecosystem } from "../../../types";
|
||||
|
||||
type UpdateEcosystemParams = {
|
||||
ecosystem: Ecosystem;
|
||||
permission: "PARTNER_WHITELIST" | "ANYONE";
|
||||
permission?: "PARTNER_WHITELIST" | "ANYONE";
|
||||
authOptions?: AuthOption[];
|
||||
};
|
||||
|
||||
export function useUpdateEcosystem(
|
||||
@@ -38,6 +39,7 @@ export function useUpdateEcosystem(
|
||||
},
|
||||
body: JSON.stringify({
|
||||
permission: params.permission,
|
||||
authOptions: params.authOptions,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ export function EcosystemWalletPricingCard(props: { className?: string }) {
|
||||
<Image src={headerImage} alt="" sizes="50vw" className="w-full" />
|
||||
<div className="relative border-border border-t p-4 pb-8 md:p-6 md:pb-8">
|
||||
<h4 className="font-bold text-4xl text-foreground">
|
||||
$250
|
||||
$250{" "}
|
||||
<span className="font-normal text-lg text-muted-foreground">
|
||||
per month
|
||||
</span>
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
export const authOptions = [
|
||||
"google",
|
||||
"facebook",
|
||||
"x",
|
||||
"discord",
|
||||
"farcaster",
|
||||
"telegram",
|
||||
"phone",
|
||||
"email",
|
||||
"guest",
|
||||
"apple",
|
||||
"coinbase",
|
||||
"line",
|
||||
] as const;
|
||||
export type AuthOption = (typeof authOptions)[number];
|
||||
|
||||
export type Ecosystem = {
|
||||
name: string;
|
||||
imageUrl?: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
permission: "PARTNER_WHITELIST" | "ANYONE";
|
||||
authOptions: unknown;
|
||||
authOptions: (typeof authOptions)[number][];
|
||||
url: string;
|
||||
status: "active" | "requested" | "paymentFailed";
|
||||
createdAt: string;
|
||||
|
||||
@@ -13,7 +13,7 @@ export default async function Layout(props: {
|
||||
<p className="text-muted-foreground leading-7">
|
||||
Pay allows your users to purchase cryptocurrencies and execute
|
||||
transactions with their credit card or debit card, or with any token
|
||||
via cross-chain routing.
|
||||
via cross-chain routing.{" "}
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://portal.thirdweb.com/connect/pay/overview"
|
||||
|
||||
@@ -72,7 +72,7 @@ export default async function ExploreCategoryPage(
|
||||
{category.displayName || category.name}
|
||||
</h1>
|
||||
<p className="max-w-screen-md text-base text-muted-foreground lg:text-lg">
|
||||
{category.description}
|
||||
{category.description}{" "}
|
||||
{category.learnMore && (
|
||||
<Link href={category.learnMore}>Learn more</Link>
|
||||
)}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ export const Keccak256Converter = () => {
|
||||
|
||||
<Card className="flex flex-col gap-2 p-4">
|
||||
<p>
|
||||
Or use the
|
||||
Or use the{" "}
|
||||
<a
|
||||
href="https://portal.thirdweb.com/typescript/v5"
|
||||
target="_blank"
|
||||
|
||||
@@ -75,7 +75,7 @@ export const WeiConverter = () => {
|
||||
|
||||
<Card className="flex flex-col gap-2 p-4">
|
||||
<p>
|
||||
Or use the
|
||||
Or use the{" "}
|
||||
<a
|
||||
href="https://portal.thirdweb.com/typescript/v5"
|
||||
target="_blank"
|
||||
|
||||
@@ -45,6 +45,8 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
|
||||
throw new Error("API_SERVER_SECRET is not set");
|
||||
}
|
||||
|
||||
const cookieStore = cookies();
|
||||
|
||||
// forward the request to the API server
|
||||
const res = await fetch(`${THIRDWEB_API_HOST}/v2/siwe/login`, {
|
||||
method: "POST",
|
||||
@@ -52,10 +54,21 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
|
||||
"Content-Type": "application/json",
|
||||
"x-service-api-key": THIRDWEB_API_SECRET,
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
// set the createAccount flag to true to create a new account if it does not exist
|
||||
body: JSON.stringify({ ...payload, createAccount: true }),
|
||||
});
|
||||
|
||||
// if the request failed, log the error and throw an error
|
||||
if (!res.ok) {
|
||||
try {
|
||||
// clear the cookies to prevent any weird issues
|
||||
cookieStore.delete(
|
||||
COOKIE_PREFIX_TOKEN + getAddress(payload.payload.address),
|
||||
);
|
||||
cookieStore.delete(COOKIE_ACTIVE_ACCOUNT);
|
||||
} catch {
|
||||
// ignore any errors on this
|
||||
}
|
||||
try {
|
||||
const response = await res.text();
|
||||
// try to log the rich error message
|
||||
@@ -86,35 +99,6 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
|
||||
throw new Error("Failed to login - invalid json");
|
||||
}
|
||||
|
||||
// check if we have a thirdweb account for the token
|
||||
const userRes = await fetch(`${THIRDWEB_API_HOST}/v1/account/me`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${jwt}`,
|
||||
},
|
||||
});
|
||||
// if we do not have a user, create one
|
||||
if (userRes.status === 404) {
|
||||
const newUserRes = await fetch(`${THIRDWEB_API_HOST}/v1/account/create`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${jwt}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (newUserRes.status !== 200) {
|
||||
console.error(
|
||||
"Failed to create new user",
|
||||
newUserRes.status,
|
||||
newUserRes.statusText,
|
||||
);
|
||||
throw new Error("Failed to create new user");
|
||||
}
|
||||
}
|
||||
|
||||
const cookieStore = cookies();
|
||||
|
||||
// set the token cookie
|
||||
cookieStore.set(
|
||||
COOKIE_PREFIX_TOKEN + getAddress(payload.payload.address),
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ export function AccountAbstractionPage(props: {
|
||||
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Easily integrate Account abstraction (ERC-4337) compliant smart accounts
|
||||
into your apps.
|
||||
into your apps.{" "}
|
||||
<TrackedLinkTW
|
||||
target="_blank"
|
||||
label="docs-wallets"
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ export default async function Page(props: {
|
||||
<p className="mt-3 mb-7 max-w-[700px] text-muted-foreground">
|
||||
A wallet infrastructure that enables apps to create, manage, and control
|
||||
their users wallets. Email login, social login, and bring-your-own auth
|
||||
supported.
|
||||
supported.{" "}
|
||||
<TrackedLinkTW
|
||||
target="_blank"
|
||||
href="https://portal.thirdweb.com/connect/in-app-wallet/overview"
|
||||
|
||||
@@ -31,7 +31,7 @@ export default async function Layout(props: {
|
||||
<p className="text-muted-foreground text-sm leading-relaxed md:text-base">
|
||||
Pay allows your users to purchase cryptocurrencies and execute
|
||||
transactions with their credit card or debit card, or with any token
|
||||
via cross-chain routing.
|
||||
via cross-chain routing.{" "}
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://portal.thirdweb.com/connect/pay/overview"
|
||||
|
||||
+8
-8
@@ -310,27 +310,27 @@ function AllowedDomainsSetting(props: {
|
||||
const helperText = (
|
||||
<ul className="flex list-disc flex-col gap-1.5 py-1 pl-3 text-muted-foreground text-sm [&>li]:pl-1">
|
||||
<li>
|
||||
Authorize all domains with
|
||||
Authorize all domains with{" "}
|
||||
<span className="inline-block rounded bg-muted px-2 font-mono text-xs">
|
||||
*
|
||||
</span>
|
||||
.
|
||||
{". "}
|
||||
<span>
|
||||
Example:
|
||||
Example:{" "}
|
||||
<span className="inline-block rounded bg-muted px-2 font-mono text-xs">
|
||||
*.thirdweb.com
|
||||
</span>
|
||||
</span>{" "}
|
||||
accepts all
|
||||
<span className="inline-block rounded bg-muted px-2 font-mono text-xs">
|
||||
.thirdweb.com
|
||||
</span>
|
||||
</span>{" "}
|
||||
sites
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
Authorize localhost URLs with
|
||||
Authorize localhost URLs with{" "}
|
||||
<span className="inline-block rounded bg-muted px-2 font-mono text-xs">
|
||||
localhost:<port>
|
||||
{"localhost:<port>"}
|
||||
</span>
|
||||
</li>
|
||||
<li>Enter domains separated by commas or new lines</li>
|
||||
@@ -647,7 +647,7 @@ function APIKeyDetails({
|
||||
<div>
|
||||
<h3>Secret Key</h3>
|
||||
<p className="mb-2 text-muted-foreground text-sm">
|
||||
Identifies and authenticates your application from a backend. <br />
|
||||
Identifies and authenticates your application from a backend. <br />{" "}
|
||||
This is not the full secret key, Refer to your saved secret key at
|
||||
the time of creation for the full secret key.
|
||||
</p>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet";
|
||||
import { Box, ButtonGroup, Center, Flex } from "@chakra-ui/react";
|
||||
import { Box, ButtonGroup, Flex } from "@chakra-ui/react";
|
||||
import { motion } from "framer-motion";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { FiArrowRight } from "react-icons/fi";
|
||||
@@ -98,7 +98,7 @@ export const ContentContainer: React.FC<SlideStateProps> = ({
|
||||
h="100%"
|
||||
justify="space-between"
|
||||
>
|
||||
<Center flexGrow={1} position="relative">
|
||||
<div className="relative flex grow items-center justify-center">
|
||||
<Flex gap={8} direction="column" height="100%" width="100%">
|
||||
<Box position="relative" w="full" mt="auto">
|
||||
<SlideContent
|
||||
@@ -128,7 +128,7 @@ export const ContentContainer: React.FC<SlideStateProps> = ({
|
||||
)}
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
</Center>
|
||||
</div>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AspectRatio, Center } from "@chakra-ui/react";
|
||||
import { Center } from "@chakra-ui/react";
|
||||
import { motion } from "framer-motion";
|
||||
import type { SlideStateProps } from "../shared";
|
||||
import { slides } from "../slides";
|
||||
@@ -21,7 +21,8 @@ export const GraphicContainer: React.FC<SlideStateProps> = ({
|
||||
const Graphic = slides[slideIndex].graphic;
|
||||
|
||||
return (
|
||||
<AspectRatio ratio={{ base: 16 / 9, md: 1 }} w="100%" position="relative">
|
||||
<div className="relative aspect-[16/9] w-full md:aspect-square">
|
||||
{/* @to be completed */}
|
||||
<Center
|
||||
as={motion.div}
|
||||
initial={`slide-${slideIndex}`}
|
||||
@@ -33,6 +34,6 @@ export const GraphicContainer: React.FC<SlideStateProps> = ({
|
||||
>
|
||||
<Graphic slideIndex={slideIndex} setSlideIndex={setSlideIndex} />
|
||||
</Center>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Center, Flex } from "@chakra-ui/react";
|
||||
import { Flex } from "@chakra-ui/react";
|
||||
import { ChakraNextImage } from "components/Image";
|
||||
import { motion } from "framer-motion";
|
||||
import { Heading } from "tw-components";
|
||||
@@ -48,25 +48,25 @@ export const Titles: React.FC<SlideStateProps> = ({
|
||||
|
||||
export const DashboardImage: React.FC = () => (
|
||||
<motion.div {...moveDown}>
|
||||
<Center>
|
||||
<div className="flex items-center justify-center">
|
||||
<ChakraNextImage
|
||||
priority
|
||||
w={{ base: "45%", md: "90%" }}
|
||||
src={require("../../../../public/assets/product-pages/dashboard/hero.png")}
|
||||
alt=""
|
||||
/>
|
||||
</Center>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
export const ConnectWalletImage: React.FC = () => (
|
||||
<motion.div {...moveDown}>
|
||||
<Center h="100%" w="100%">
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<ChakraNextImage
|
||||
alt=""
|
||||
boxSize="75px"
|
||||
src={require("../../../../public/logos/wallet.png")}
|
||||
/>
|
||||
</Center>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
@@ -50,8 +50,8 @@ export const slides: Slide[] = [
|
||||
color="blue.500"
|
||||
>
|
||||
Hooks
|
||||
</TrackedLink>
|
||||
and
|
||||
</TrackedLink>{" "}
|
||||
and{" "}
|
||||
<TrackedLink
|
||||
category={TRACK_CATEGORY}
|
||||
href="https://portal.thirdweb.com/typescript"
|
||||
@@ -60,7 +60,7 @@ export const slides: Slide[] = [
|
||||
color="blue.500"
|
||||
>
|
||||
functions
|
||||
</TrackedLink>
|
||||
</TrackedLink>{" "}
|
||||
that let you easily interact with contracts, wallets, and
|
||||
transactions.
|
||||
</ListItem>
|
||||
@@ -73,7 +73,7 @@ export const slides: Slide[] = [
|
||||
color="blue.500"
|
||||
>
|
||||
In-App wallets
|
||||
</TrackedLink>
|
||||
</TrackedLink>{" "}
|
||||
with different key management structures.
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
@@ -85,7 +85,7 @@ export const slides: Slide[] = [
|
||||
color="blue.500"
|
||||
>
|
||||
Plug and play UI components
|
||||
</TrackedLink>
|
||||
</TrackedLink>{" "}
|
||||
that you can drop into your app to easily integrate web3
|
||||
functionality
|
||||
</ListItem>
|
||||
@@ -147,7 +147,7 @@ export const slides: Slide[] = [
|
||||
color="blue.500"
|
||||
>
|
||||
Interact
|
||||
</TrackedLink>
|
||||
</TrackedLink>{" "}
|
||||
with contracts.
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
@@ -159,7 +159,7 @@ export const slides: Slide[] = [
|
||||
color="blue.500"
|
||||
>
|
||||
Deploy
|
||||
</TrackedLink>
|
||||
</TrackedLink>{" "}
|
||||
contracts to blockchain.
|
||||
</ListItem>
|
||||
</UnorderedList>
|
||||
@@ -203,8 +203,8 @@ export const slides: Slide[] = [
|
||||
}}
|
||||
>
|
||||
Privacy Policy
|
||||
</TrackedLink>
|
||||
and
|
||||
</TrackedLink>{" "}
|
||||
and{" "}
|
||||
<TrackedLink
|
||||
href="/tos"
|
||||
isExternal
|
||||
|
||||
@@ -16,7 +16,6 @@ import { useDashboardEVMChainId } from "@3rdweb-sdk/react";
|
||||
import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet";
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Icon,
|
||||
Popover,
|
||||
PopoverArrow,
|
||||
@@ -446,23 +445,23 @@ const MismatchNotice: React.FC<{
|
||||
}, [chain?.name, isMobile]);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap={4}>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Heading size="label.lg">
|
||||
<Flex gap={2} align="center">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Icon boxSize={6} as={AiOutlineWarning} />
|
||||
<span>Network Mismatch</span>
|
||||
</Flex>
|
||||
</div>
|
||||
</Heading>
|
||||
|
||||
<Text>
|
||||
Your wallet is connected to the
|
||||
Your wallet is connected to the{" "}
|
||||
<Box as="strong" textTransform="capitalize">
|
||||
{walletConnectedNetworkInfo?.name}
|
||||
</Box>
|
||||
network but this action requires you to connect to the
|
||||
</Box>{" "}
|
||||
network but this action requires you to connect to the{" "}
|
||||
<Box as="strong" textTransform="capitalize">
|
||||
{chain?.name}
|
||||
</Box>
|
||||
</Box>{" "}
|
||||
network.
|
||||
</Text>
|
||||
|
||||
@@ -487,7 +486,7 @@ const MismatchNotice: React.FC<{
|
||||
Please manually switch the network in your wallet.
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ export const TransactionButton: React.FC<TransactionButtonProps> = ({
|
||||
: `This action will trigger ${transactionCount} ${transactionCount > 1 ? "transactions" : "transaction"}`
|
||||
}
|
||||
>
|
||||
{/* to be completed */}
|
||||
<Center
|
||||
_groupHover={{
|
||||
bg:
|
||||
@@ -202,12 +203,12 @@ const ExternalApprovalNotice: React.FC<ExternalApprovalNoticeProps> = ({
|
||||
if (walletId === "global.safe") {
|
||||
const isChainIdSupported = chainId in CHAIN_ID_TO_GNOSIS;
|
||||
return (
|
||||
<Flex direction="column" gap={4}>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Heading size="label.lg">
|
||||
<Flex gap={2} align="center">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Icon color="primary.500" boxSize={6} as={FiInfo} />
|
||||
<span>Execute Transaction</span>
|
||||
</Flex>
|
||||
</div>
|
||||
</Heading>
|
||||
<Text>
|
||||
You will need to execute this transaction in your Safe to continue.
|
||||
@@ -232,17 +233,17 @@ const ExternalApprovalNotice: React.FC<ExternalApprovalNoticeProps> = ({
|
||||
>
|
||||
Go To Safe
|
||||
</LinkButton>
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (walletId === "walletConnect") {
|
||||
return (
|
||||
<Flex direction="column" gap={4}>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Heading size="label.lg">
|
||||
<Flex gap={2} align="center">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Icon color="primary.500" boxSize={6} as={FiInfo} />
|
||||
<span>Approve Transaction</span>
|
||||
</Flex>
|
||||
</div>
|
||||
</Heading>
|
||||
<Text>
|
||||
You will need to approve this transaction in your connected wallet.
|
||||
@@ -254,7 +255,7 @@ const ExternalApprovalNotice: React.FC<ExternalApprovalNoticeProps> = ({
|
||||
action will continue automatically.
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
Code,
|
||||
Flex,
|
||||
FormControl,
|
||||
Icon,
|
||||
Input,
|
||||
@@ -67,7 +66,7 @@ const ChainValidation: React.FC = () => {
|
||||
|
||||
return (
|
||||
<Card maxW="xl">
|
||||
<Flex direction="column" gap={6}>
|
||||
<div className="flex flex-col gap-6">
|
||||
<FormControl gap={6}>
|
||||
<FormLabel>RPC URL</FormLabel>
|
||||
<InputGroup gap={2}>
|
||||
@@ -134,7 +133,7 @@ const ChainValidation: React.FC = () => {
|
||||
{validationReport.chainIdSupported && (
|
||||
<Tr>
|
||||
<Td>
|
||||
Chain ID
|
||||
Chain ID{" "}
|
||||
{existingChain?.id ? (
|
||||
<Code mr={1}>{existingChain.id}</Code>
|
||||
) : (
|
||||
@@ -177,7 +176,7 @@ const ChainValidation: React.FC = () => {
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -340,7 +340,7 @@ const SearchResult: React.FC<SearchResultProps> = ({
|
||||
</Link>
|
||||
</h3>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{result.chainMetadata.name} -
|
||||
{result.chainMetadata.name} -{" "}
|
||||
<span className="font-mono">
|
||||
{shortenIfAddress(result.contractAddress)}
|
||||
</span>
|
||||
|
||||
@@ -23,14 +23,14 @@ export const NetworkIDInput: React.FC<{
|
||||
dashboard.
|
||||
<p className="mt-2 mb-1 font-semibold">Example</p>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
thirdweb.com/<slug>/...
|
||||
{"thirdweb.com/<slug>..."}
|
||||
</p>
|
||||
</span>
|
||||
}
|
||||
errorMessage={
|
||||
form.formState.errors.slug?.type === "taken" ? (
|
||||
<>
|
||||
Can not use {`"${slug}"`}.
|
||||
Can not use {`"${slug}"`}.{" "}
|
||||
{slug &&
|
||||
existingChain &&
|
||||
`It is being used by "${existingChain.name}"`}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "react-responsive-carousel/lib/styles/carousel.min.css";
|
||||
import { Box, Flex, SimpleGrid } from "@chakra-ui/react";
|
||||
import { Box, SimpleGrid } from "@chakra-ui/react";
|
||||
import { ChakraNextImage } from "components/Image";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
@@ -68,12 +68,7 @@ const Carousel = ({ TRACKING_CATEGORY }: { TRACKING_CATEGORY: string }) => {
|
||||
}, [selectedShowCaseIdx, canAnimate]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
flexDir={{ base: "column", md: "row" }}
|
||||
gap={{ base: "24px", md: 0 }}
|
||||
alignItems="stretch"
|
||||
w="full"
|
||||
>
|
||||
<div className="flex w-full flex-col items-stretch gap-6 md:flex-row md:gap-0">
|
||||
<Box
|
||||
w="full"
|
||||
display={{ base: "flex", md: "none" }}
|
||||
@@ -153,7 +148,7 @@ const Carousel = ({ TRACKING_CATEGORY }: { TRACKING_CATEGORY: string }) => {
|
||||
);
|
||||
})}
|
||||
</SimpleGrid>
|
||||
<Flex width="full" maxW="786px">
|
||||
<div className="flex w-full max-w-[786px] flex-row">
|
||||
{showcaseImages.map((img, idx) => (
|
||||
<ChakraNextImage
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
|
||||
@@ -175,8 +170,8 @@ const Carousel = ({ TRACKING_CATEGORY }: { TRACKING_CATEGORY: string }) => {
|
||||
priority
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+6
-2
@@ -37,6 +37,7 @@ import {
|
||||
} from "thirdweb/deploys";
|
||||
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
|
||||
import { upload } from "thirdweb/storage";
|
||||
import { isZkSyncChain } from "thirdweb/utils";
|
||||
import { FormHelperText, FormLabel, Heading, Text } from "tw-components";
|
||||
import { useCustomFactoryAbi, useFunctionParamsFromABI } from "../hooks";
|
||||
import { addContractToMultiChainRegistry } from "../utils";
|
||||
@@ -385,6 +386,8 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
|
||||
throw new Error("no chain");
|
||||
}
|
||||
|
||||
const compilerType = isZkSyncChain(walletChain) ? "zksolc" : "solc";
|
||||
|
||||
let _contractURI = "";
|
||||
|
||||
if (hasContractURI && params.contractMetadata) {
|
||||
@@ -449,6 +452,7 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
|
||||
deployMetadata: m,
|
||||
initializeParams: params.moduleData[m.name],
|
||||
})),
|
||||
compilerType,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -805,7 +809,7 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
|
||||
|
||||
<p className="mb-3 text-muted-foreground text-sm">
|
||||
Select a network to deploy this contract on. We recommend
|
||||
starting with a testnet.
|
||||
starting with a testnet.{" "}
|
||||
<TrackedLinkTW
|
||||
href="/chainlist"
|
||||
category="deploy"
|
||||
@@ -917,7 +921,7 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
|
||||
}
|
||||
/>
|
||||
<span>
|
||||
Import so I can find it in the list of my contracts at
|
||||
Import so I can find it in the list of my contracts at{" "}
|
||||
<TrackedLinkTW
|
||||
className="text-link-foreground hover:text-foreground"
|
||||
href="/dashboard"
|
||||
|
||||
+2
-2
@@ -106,7 +106,7 @@ export const CustomFactory: React.FC<CustomFactoryProps> = ({
|
||||
</FormControl>
|
||||
</div>
|
||||
))}
|
||||
<Box>
|
||||
<div>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
@@ -117,7 +117,7 @@ export const CustomFactory: React.FC<CustomFactoryProps> = ({
|
||||
>
|
||||
Add Network
|
||||
</Button>
|
||||
</Box>
|
||||
</div>
|
||||
</Flex>
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<Flex flexDir="column" gap={2}>
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ export const DefaultFactory: React.FC<DefaultFactoryProps> = ({ abi }) => {
|
||||
<Flex px={0} pb={0} flexDir="column" gap={12}>
|
||||
<UnorderedList>
|
||||
<Text as={ListItem}>
|
||||
Default factory lets users deploy your contract to
|
||||
Default factory lets users deploy your contract to{" "}
|
||||
<strong>any EVM network</strong>.
|
||||
</Text>
|
||||
<Text as={ListItem}>
|
||||
@@ -24,7 +24,7 @@ export const DefaultFactory: React.FC<DefaultFactoryProps> = ({ abi }) => {
|
||||
makes it much cheaper to deploy.
|
||||
</Text>
|
||||
<Text as={ListItem}>
|
||||
The factory is
|
||||
The factory is{" "}
|
||||
<Link
|
||||
color="primary.500"
|
||||
isExternal
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { Box, Flex, Icon } from "@chakra-ui/react";
|
||||
import { Flex, Icon } from "@chakra-ui/react";
|
||||
import { useEffect } from "react";
|
||||
import { useFieldArray, useFormContext } from "react-hook-form";
|
||||
import { FiPlus } from "react-icons/fi";
|
||||
@@ -37,7 +37,7 @@ export const ExternalLinksFieldset = () => {
|
||||
{fields.map((item, index) => (
|
||||
<ExternalLinksInput key={item.id} remove={remove} index={index} />
|
||||
))}
|
||||
<Box>
|
||||
<div>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
@@ -53,7 +53,7 @@ export const ExternalLinksFieldset = () => {
|
||||
>
|
||||
Add Resource
|
||||
</Button>
|
||||
</Box>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -295,7 +295,7 @@ export function ContractPublishForm(props: {
|
||||
gap={6}
|
||||
>
|
||||
{fieldsetToShow !== "landing" && (
|
||||
<Box>
|
||||
<div>
|
||||
<IconButton
|
||||
w="inherit"
|
||||
variant="ghost"
|
||||
@@ -314,7 +314,7 @@ export function ContractPublishForm(props: {
|
||||
>
|
||||
Back
|
||||
</IconButton>
|
||||
</Box>
|
||||
</div>
|
||||
)}
|
||||
{fieldsetToShow === "landing" && (
|
||||
<LandingFieldset
|
||||
|
||||
+7
-7
@@ -78,7 +78,7 @@ export const LandingFieldset: React.FC<LandingFieldsetProps> = ({
|
||||
</Heading>
|
||||
<Text fontStyle="normal">
|
||||
Publishing your contract makes it shareable, discoverable, and
|
||||
deployable in a single click.
|
||||
deployable in a single click.{" "}
|
||||
<Link
|
||||
color="blue.500"
|
||||
isExternal
|
||||
@@ -145,7 +145,7 @@ export const LandingFieldset: React.FC<LandingFieldsetProps> = ({
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Box>
|
||||
<div>
|
||||
<Heading size="title.md" mb={2}>
|
||||
README
|
||||
</Heading>
|
||||
@@ -186,9 +186,9 @@ export const LandingFieldset: React.FC<LandingFieldsetProps> = ({
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</div>
|
||||
<ExternalLinksFieldset />
|
||||
<Box>
|
||||
<div>
|
||||
<Heading size="title.md" mb={2}>
|
||||
Version information
|
||||
</Heading>
|
||||
@@ -267,8 +267,8 @@ export const LandingFieldset: React.FC<LandingFieldsetProps> = ({
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
</div>
|
||||
<div>
|
||||
<Heading size="title.md" mb={2}>
|
||||
Deployment options
|
||||
</Heading>
|
||||
@@ -294,7 +294,7 @@ export const LandingFieldset: React.FC<LandingFieldsetProps> = ({
|
||||
width="full"
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
</div>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@ import { useV5DashboardChain } from "lib/v5-adapter";
|
||||
import { useMemo } from "react";
|
||||
import { type ThirdwebContract, getContract } from "thirdweb";
|
||||
import {
|
||||
getBytecode,
|
||||
resolveContractAbi,
|
||||
fetchDeployMetadata as sdkFetchDeployMetadata,
|
||||
} from "thirdweb/contract";
|
||||
@@ -16,7 +15,11 @@ import {
|
||||
getContractPublisher,
|
||||
getPublishedUriFromCompilerUri,
|
||||
} from "thirdweb/extensions/thirdweb";
|
||||
import { extractIPFSUri, isAddress } from "thirdweb/utils";
|
||||
import {
|
||||
extractIPFSUri,
|
||||
isAddress,
|
||||
resolveImplementation,
|
||||
} from "thirdweb/utils";
|
||||
import invariant from "tiny-invariant";
|
||||
import {
|
||||
type PublishedContractWithVersion,
|
||||
@@ -111,7 +114,7 @@ export function usePublishedContractsFromDeploy(contract: ThirdwebContract) {
|
||||
contract.address,
|
||||
],
|
||||
queryFn: async () => {
|
||||
const bytecode = await getBytecode(contract);
|
||||
const { bytecode } = await resolveImplementation(contract);
|
||||
const contractUri = extractIPFSUri(bytecode);
|
||||
if (!contractUri) {
|
||||
throw new Error("No IPFS URI found in bytecode");
|
||||
|
||||
@@ -232,7 +232,7 @@ export const PublishedContract: React.FC<PublishedContractProps> = ({
|
||||
<Heading as="h5" size="label.sm">
|
||||
{publishedContract?.isDeployableViaFactory
|
||||
? "Factory"
|
||||
: "Proxy"}
|
||||
: "Proxy"}{" "}
|
||||
Enabled
|
||||
</Heading>
|
||||
{implementationAddresses &&
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
FormControl,
|
||||
Icon,
|
||||
Input,
|
||||
@@ -177,10 +176,10 @@ export const EditProfile: React.FC<EditProfileProps> = ({
|
||||
>
|
||||
<FormControl isInvalid={!!errors.avatar}>
|
||||
<FormLabel>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Icon as={BiImage} boxSize={4} />
|
||||
Avatar
|
||||
</Flex>
|
||||
</div>
|
||||
</FormLabel>
|
||||
<Box width={{ base: "auto", md: "250px" }}>
|
||||
<FileInput
|
||||
@@ -200,10 +199,10 @@ export const EditProfile: React.FC<EditProfileProps> = ({
|
||||
</FormControl>
|
||||
<FormControl isInvalid={!!errors.bio}>
|
||||
<FormLabel>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Icon as={HiPencilAlt} boxSize={4} />
|
||||
Bio
|
||||
</Flex>
|
||||
</div>
|
||||
</FormLabel>
|
||||
<Textarea
|
||||
{...register("bio")}
|
||||
@@ -214,10 +213,10 @@ export const EditProfile: React.FC<EditProfileProps> = ({
|
||||
</FormControl>
|
||||
<FormControl isInvalid={!!errors.github}>
|
||||
<FormLabel>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Icon as={SiGithub} boxSize={4} />
|
||||
GitHub
|
||||
</Flex>
|
||||
</div>
|
||||
</FormLabel>
|
||||
<Input
|
||||
{...register("github")}
|
||||
@@ -227,10 +226,10 @@ export const EditProfile: React.FC<EditProfileProps> = ({
|
||||
</FormControl>
|
||||
<FormControl isInvalid={!!errors.twitter}>
|
||||
<FormLabel>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Icon as={SiTwitter} boxSize={4} />
|
||||
Twitter
|
||||
</Flex>
|
||||
</div>
|
||||
</FormLabel>
|
||||
<Input
|
||||
{...register("twitter")}
|
||||
@@ -240,10 +239,10 @@ export const EditProfile: React.FC<EditProfileProps> = ({
|
||||
</FormControl>
|
||||
<FormControl isInvalid={!!errors.website}>
|
||||
<FormLabel>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Icon as={FiGlobe} boxSize={4} />
|
||||
Website
|
||||
</Flex>
|
||||
</div>
|
||||
</FormLabel>
|
||||
<Input
|
||||
{...register("website")}
|
||||
@@ -253,10 +252,10 @@ export const EditProfile: React.FC<EditProfileProps> = ({
|
||||
</FormControl>
|
||||
<FormControl isInvalid={!!errors.discord}>
|
||||
<FormLabel>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Icon as={SiDiscord} boxSize={4} />
|
||||
Discord
|
||||
</Flex>
|
||||
</div>
|
||||
</FormLabel>
|
||||
<Input
|
||||
{...register("discord")}
|
||||
|
||||
@@ -16,7 +16,7 @@ export const SourcesPanel: React.FC<SourcesPanelProps> = ({ sources, abi }) => {
|
||||
<SourcesAccordion sources={sources} abi={abi} />
|
||||
) : (
|
||||
<Text>
|
||||
Contract source code not available. Try deploying with
|
||||
Contract source code not available. Try deploying with{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/contracts/deploy/overview"
|
||||
isExternal
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
AlertTitle,
|
||||
Center,
|
||||
Flex,
|
||||
Spinner,
|
||||
} from "@chakra-ui/react";
|
||||
import { Alert, AlertIcon, AlertTitle, Flex, Spinner } from "@chakra-ui/react";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { useMemo, useState } from "react";
|
||||
import { IoRefreshSharp } from "react-icons/io5";
|
||||
@@ -90,15 +83,15 @@ export const PublishedContracts: React.FC<PublishedContractsProps> = ({
|
||||
hidePublisher
|
||||
>
|
||||
{publishedContractsQuery.isPending && (
|
||||
<Center>
|
||||
<div className="flex items-center justify-center">
|
||||
<Flex py={4} direction="row" gap={4} align="center">
|
||||
<Spinner size="sm" />
|
||||
<Text>Loading published contracts</Text>
|
||||
</Flex>
|
||||
</Center>
|
||||
</div>
|
||||
)}
|
||||
{publishedContractsQuery.isError && (
|
||||
<Center>
|
||||
<div className="flex items-center justify-center">
|
||||
<Flex mt={4} py={4} direction="column" gap={4} align="center">
|
||||
<Alert status="error" borderRadius="md">
|
||||
<AlertIcon />
|
||||
@@ -116,15 +109,15 @@ export const PublishedContracts: React.FC<PublishedContractsProps> = ({
|
||||
</Button>
|
||||
</Alert>
|
||||
</Flex>
|
||||
</Center>
|
||||
</div>
|
||||
)}
|
||||
{publishedContractsQuery.isSuccess &&
|
||||
publishedContractsQuery.data.length === 0 && (
|
||||
<Center>
|
||||
<div className="flex items-center justify-center">
|
||||
<Flex py={4} direction="column" gap={4} align="center">
|
||||
<Text>No published contracts found.</Text>
|
||||
</Flex>
|
||||
</Center>
|
||||
</div>
|
||||
)}
|
||||
{publishedContractsQuery.isSuccess &&
|
||||
publishedContractsQuery.data.length > slicedData.length && (
|
||||
|
||||
@@ -93,9 +93,9 @@ export const ContractFunctionsOverview: React.FC<ContractFunctionsOverview> = ({
|
||||
) : null}
|
||||
{abi && (
|
||||
<TabPanel>
|
||||
<Flex direction="column" gap={6}>
|
||||
<div className="flex flex-col gap-6">
|
||||
<CodeOverview abi={abi} noSidebar />
|
||||
</Flex>
|
||||
</div>
|
||||
</TabPanel>
|
||||
)}
|
||||
{(sources || abi) && (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import { Center, Flex, Skeleton, useBreakpointValue } from "@chakra-ui/react";
|
||||
import { Flex, Skeleton, useBreakpointValue } from "@chakra-ui/react";
|
||||
import { ChainIcon } from "components/icons/ChainIcon";
|
||||
import Link from "next/link";
|
||||
import type { ChainMetadata } from "thirdweb/chains";
|
||||
@@ -119,13 +119,9 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
|
||||
cursor="pointer"
|
||||
>
|
||||
{chain.icon?.url && (
|
||||
<Center
|
||||
boxSize={5}
|
||||
mr={{ base: 0, md: -0.5 }}
|
||||
borderRadius="full"
|
||||
>
|
||||
<div className="md:-mr-0.5 mr-0 flex h-5 w-5 items-center justify-center rounded-full">
|
||||
<ChainIcon ipfsSrc={chain.icon.url} size={24} />
|
||||
</Center>
|
||||
</div>
|
||||
)}
|
||||
<Heading
|
||||
display={{
|
||||
@@ -158,7 +154,7 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
|
||||
</Text>
|
||||
</Skeleton>
|
||||
)}
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<AddressCopyButton size="xs" address={address} />
|
||||
{validBlockExplorers?.map((validBlockExplorer) => (
|
||||
<LinkButton
|
||||
@@ -182,7 +178,7 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
|
||||
{e.name}
|
||||
</LinkButton>
|
||||
))}
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Flex, Icon, Image } from "@chakra-ui/react";
|
||||
import { Flex, Icon, Image } from "@chakra-ui/react";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { FiCalendar, FiClock } from "react-icons/fi";
|
||||
import { Card, Heading, LinkButton, Text } from "tw-components";
|
||||
@@ -75,7 +75,7 @@ export const DevRelEvent: React.FC<EventProps> = ({
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Box>
|
||||
<div>
|
||||
<LinkButton
|
||||
href={link}
|
||||
onClick={() =>
|
||||
@@ -92,7 +92,7 @@ export const DevRelEvent: React.FC<EventProps> = ({
|
||||
>
|
||||
Register
|
||||
</LinkButton>
|
||||
</Box>
|
||||
</div>
|
||||
</Flex>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -295,7 +295,7 @@ function BrandingFieldset(props: {
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
Name that will be displayed in the emails sent to users.
|
||||
Name that will be displayed in the emails sent to users.{" "}
|
||||
<br className="max-sm:hidden" /> Defaults to your API Key's
|
||||
name.
|
||||
</FormDescription>
|
||||
@@ -315,7 +315,7 @@ function BrandingFieldset(props: {
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
Logo that will display in the emails sent to users.
|
||||
Logo that will display in the emails sent to users.{" "}
|
||||
<br className="max-sm:hidden" /> The image must be squared with
|
||||
recommended size of 72x72 px.
|
||||
</FormDescription>
|
||||
@@ -341,7 +341,7 @@ function JSONWebTokenFields(props: {
|
||||
title="Custom JSON Web Token"
|
||||
description={
|
||||
<>
|
||||
Optionally allow users to authenticate with a custom JWT.
|
||||
Optionally allow users to authenticate with a custom JWT.{" "}
|
||||
<TrackedLinkTW
|
||||
target="_blank"
|
||||
href="https://portal.thirdweb.com/connect/in-app-wallet/custom-auth/custom-jwt-auth-server"
|
||||
@@ -436,7 +436,7 @@ function AuthEndpointFields(props: {
|
||||
description={
|
||||
<>
|
||||
Optionally allow users to authenticate with any arbitrary payload
|
||||
that you provide.
|
||||
that you provide.{" "}
|
||||
<TrackedLinkTW
|
||||
target="_blank"
|
||||
href="https://portal.thirdweb.com/connect/in-app-wallet/custom-auth/custom-auth-server"
|
||||
|
||||
@@ -24,7 +24,7 @@ export const EngineWalletConfig: React.FC<EngineWalletConfigProps> = ({
|
||||
<Flex flexDir="column" gap={2}>
|
||||
<Heading size="title.md">Backend Wallets</Heading>
|
||||
<Text>
|
||||
Select the type of backend wallets to use.
|
||||
Select the type of backend wallets to use.{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/infrastructure/engine/features/backend-wallets"
|
||||
color="primary.500"
|
||||
|
||||
@@ -20,7 +20,7 @@ export const EngineWebhooks: React.FC<EngineWebhooksProps> = ({
|
||||
<Heading size="title.md">Webhooks</Heading>
|
||||
<Text>
|
||||
Notify your app backend when transaction and backend wallet events
|
||||
occur.
|
||||
occur.{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/infrastructure/engine/features/webhooks"
|
||||
color="primary.500"
|
||||
|
||||
+2
-2
@@ -352,7 +352,7 @@ const ModalBodyInputData = ({
|
||||
</Radio>
|
||||
<Radio value="true">
|
||||
<Text>
|
||||
Specific events
|
||||
Specific events{" "}
|
||||
{!!filterEvents.length &&
|
||||
`(${filterEvents.length} selected)`}
|
||||
</Text>
|
||||
@@ -408,7 +408,7 @@ const ModalBodyInputData = ({
|
||||
</Radio>
|
||||
<Radio value="true">
|
||||
<Text>
|
||||
Specific functions
|
||||
Specific functions{" "}
|
||||
{!!filterFunctions.length &&
|
||||
`(${filterFunctions.length} selected)`}
|
||||
</Text>
|
||||
|
||||
+2
-2
@@ -413,7 +413,7 @@ const RemoveModal = ({
|
||||
<FormLabel>Filters</FormLabel>
|
||||
{contractSubscription.processEventLogs && (
|
||||
<Text>
|
||||
Logs:
|
||||
Logs:{" "}
|
||||
{contractSubscription.filterEvents.length === 0
|
||||
? "All"
|
||||
: contractSubscription.filterEvents.join(", ")}
|
||||
@@ -421,7 +421,7 @@ const RemoveModal = ({
|
||||
)}
|
||||
{contractSubscription.processTransactionReceipts && (
|
||||
<Text>
|
||||
Receipts:
|
||||
Receipts:{" "}
|
||||
{contractSubscription.filterFunctions.length === 0
|
||||
? "All"
|
||||
: contractSubscription.filterFunctions.join(", ")}
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ export const EngineContractSubscriptions: React.FC<
|
||||
<Flex flexDir="column" gap={2}>
|
||||
<Heading size="title.md">Contract Subscriptions</Heading>
|
||||
<Text>
|
||||
Subscribe to event logs and transaction receipts on any contract.
|
||||
Subscribe to event logs and transaction receipts on any contract.{" "}
|
||||
<TrackedLink
|
||||
href="https://portal.thirdweb.com/engine/features/contract-subscriptions"
|
||||
color="primary.500"
|
||||
@@ -36,7 +36,7 @@ export const EngineContractSubscriptions: React.FC<
|
||||
.
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<FormControl display="flex" alignItems="center">
|
||||
<FormLabel htmlFor="auto-update" mb="0">
|
||||
Auto-Update
|
||||
@@ -47,7 +47,7 @@ export const EngineContractSubscriptions: React.FC<
|
||||
id="auto-update"
|
||||
/>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
<ContractSubscriptionTable
|
||||
instanceUrl={instanceUrl}
|
||||
|
||||
@@ -26,7 +26,7 @@ export const ConfirmEngineTierDialog = (props: {
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="pr-4 leading-snug">
|
||||
Are you sure you want to deploy a
|
||||
Are you sure you want to deploy a{" "}
|
||||
{tier === "STARTER" ? "Standard" : "Premium"} Engine?
|
||||
</DialogTitle>
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ const SendFundsModal = ({
|
||||
</InputRightAddon>
|
||||
</InputGroup>
|
||||
<FormHelperText textAlign="right">
|
||||
Current amount:
|
||||
Current amount:{" "}
|
||||
{prettyPrintCurrency({
|
||||
amount: backendWalletBalance.displayValue,
|
||||
symbol: backendWalletBalance.symbol,
|
||||
|
||||
@@ -40,7 +40,7 @@ export const EngineOverview: React.FC<EngineOverviewProps> = ({
|
||||
<ToolTipLabel
|
||||
label={
|
||||
<>
|
||||
This engine is configured to use
|
||||
This engine is configured to use{" "}
|
||||
{walletConfig.type === "aws-kms"
|
||||
? "backend wallets secured by AWS KMS"
|
||||
: walletConfig.type === "gcp-kms"
|
||||
@@ -60,7 +60,7 @@ export const EngineOverview: React.FC<EngineOverviewProps> = ({
|
||||
</Flex>
|
||||
<Text>
|
||||
Engine performs blockchain actions using backend wallets you own
|
||||
and manage.
|
||||
and manage.{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/infrastructure/engine/features/backend-wallets"
|
||||
color="primary.500"
|
||||
@@ -71,18 +71,18 @@ export const EngineOverview: React.FC<EngineOverviewProps> = ({
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<ImportBackendWalletButton instanceUrl={instanceUrl} />
|
||||
<CreateBackendWalletButton instanceUrl={instanceUrl} />
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
|
||||
<Flex flexDirection="row-reverse">
|
||||
<Flex alignItems="center" gap={2}>
|
||||
<Text>Show balance for</Text>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<NetworkSelectorButton />
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
@@ -104,7 +104,7 @@ export const EngineOverview: React.FC<EngineOverviewProps> = ({
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<FormControl display="flex" alignItems="center">
|
||||
<FormLabel htmlFor="auto-update" mb="0">
|
||||
Auto-Update
|
||||
@@ -115,7 +115,7 @@ export const EngineOverview: React.FC<EngineOverviewProps> = ({
|
||||
id="auto-update"
|
||||
/>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
<TransactionsTable
|
||||
transactions={transactionsQuery.data?.transactions ?? []}
|
||||
|
||||
@@ -480,7 +480,7 @@ const TransactionDetailsDrawer = ({
|
||||
{/* On-chain details */}
|
||||
|
||||
<FormControl>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<FormLabel>Value</FormLabel>
|
||||
<Tooltip
|
||||
label={`The amount of ${symbol} sent to the "To" .`}
|
||||
@@ -488,11 +488,11 @@ const TransactionDetailsDrawer = ({
|
||||
>
|
||||
<FiInfo />
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</div>
|
||||
<Text>
|
||||
{transaction.value
|
||||
? toTokens(BigInt(transaction.value), decimals)
|
||||
: 0}
|
||||
: 0}{" "}
|
||||
{symbol}
|
||||
</Text>
|
||||
</FormControl>
|
||||
@@ -527,7 +527,7 @@ const TransactionDetailsDrawer = ({
|
||||
<Stack spacing={4}>
|
||||
{transaction.nonce && (
|
||||
<FormControl>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<FormLabel>Nonce</FormLabel>
|
||||
<Tooltip
|
||||
label="The nonce value this transaction was submitted to mempool."
|
||||
@@ -535,14 +535,14 @@ const TransactionDetailsDrawer = ({
|
||||
>
|
||||
<FiInfo />
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</div>
|
||||
<Text>{transaction.nonce ?? "N/A"}</Text>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
{transaction.gasLimit && (
|
||||
<FormControl>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<FormLabel>Gas Units</FormLabel>
|
||||
<Tooltip
|
||||
label="The gas units spent for this transaction."
|
||||
@@ -550,14 +550,14 @@ const TransactionDetailsDrawer = ({
|
||||
>
|
||||
<FiInfo />
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</div>
|
||||
<Text>{Number(transaction.gasLimit).toLocaleString()}</Text>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
{transaction.gasPrice && (
|
||||
<FormControl>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<FormLabel>Gas Price</FormLabel>
|
||||
<Tooltip
|
||||
label="The price in wei spent for each gas unit."
|
||||
@@ -565,7 +565,7 @@ const TransactionDetailsDrawer = ({
|
||||
>
|
||||
<FiInfo />
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</div>
|
||||
<Text>{Number(transaction.gasPrice).toLocaleString()}</Text>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
@@ -130,7 +130,7 @@ export const AddKeypairButton: React.FC<AddKeypairButtonProps> = ({
|
||||
<ModalBody as={Flex} flexDir="column" gap={8}>
|
||||
<FormControl>
|
||||
<Stack>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Text>Create a private key using:</Text>
|
||||
<Select
|
||||
w="fit-content"
|
||||
@@ -156,7 +156,7 @@ export const AddKeypairButton: React.FC<AddKeypairButtonProps> = ({
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Flex>
|
||||
</div>
|
||||
|
||||
<CodeBlock
|
||||
fontSize="small"
|
||||
|
||||
@@ -82,7 +82,7 @@ const StandardAccessTokensPanel = ({
|
||||
return (
|
||||
<>
|
||||
<Text>
|
||||
Access tokens allow API access to Engine.
|
||||
Access tokens allow API access to Engine.{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/engine/features/access-tokens"
|
||||
color="primary.500"
|
||||
@@ -132,7 +132,7 @@ const KeypairAuthenticationPanel = ({
|
||||
Keypair authentication allows your app to geneate short-lived access
|
||||
tokens.
|
||||
<br />
|
||||
They are securely signed by your backend and verified with a public key.
|
||||
They are securely signed by your backend and verified with a public key.{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/engine/features/keypair-authentication"
|
||||
color="primary.500"
|
||||
|
||||
@@ -17,7 +17,7 @@ export const EngineAdmins: React.FC<EngineAdminsProps> = ({ instanceUrl }) => {
|
||||
<div className="flex flex-col gap-2">
|
||||
<Heading size="title.md">Admins</Heading>
|
||||
<Text>
|
||||
Admins are allowed to manage your Engine instance from the dashboard.
|
||||
Admins are allowed to manage your Engine instance from the dashboard.{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/engine/features/admins"
|
||||
color="primary.500"
|
||||
|
||||
@@ -21,7 +21,7 @@ export const EngineRelayer: React.FC<EngineRelayerProps> = ({
|
||||
<Heading size="title.md">Relayers</Heading>
|
||||
<Text>
|
||||
Use relayers to submit transactions from your backend wallets on
|
||||
behalf of your users.
|
||||
behalf of your users.{" "}
|
||||
<Link
|
||||
href="https://portal.thirdweb.com/engine/features/relayers"
|
||||
color="primary.500"
|
||||
|
||||
@@ -36,7 +36,7 @@ export const EngineSystemMetrics: React.FC<EngineStatusProps> = ({
|
||||
</Heading>
|
||||
</Flex>
|
||||
<Text>
|
||||
Upgrade to a
|
||||
Upgrade to a{" "}
|
||||
<TrackedLink
|
||||
href="/dashboard/engine/create"
|
||||
isExternal
|
||||
@@ -45,7 +45,7 @@ export const EngineSystemMetrics: React.FC<EngineStatusProps> = ({
|
||||
label="metrics-cloud-hosted-upsell"
|
||||
>
|
||||
Cloud-Hosted Engine managed by thirdweb
|
||||
</TrackedLink>
|
||||
</TrackedLink>{" "}
|
||||
to view these metrics.
|
||||
</Text>
|
||||
</Stack>
|
||||
@@ -112,7 +112,7 @@ export const EngineSystemMetrics: React.FC<EngineStatusProps> = ({
|
||||
<div className="flex-col gap-y-4">
|
||||
<h2 className="font-semibold">Time to send</h2>
|
||||
<p className="text-muted-foreground">
|
||||
p50 {(msToSend.p50 / 1000).toFixed(2)}s, p90
|
||||
p50 {(msToSend.p50 / 1000).toFixed(2)}s, p90{" "}
|
||||
{(msToSend.p90 / 1000).toFixed(2)}s
|
||||
</p>
|
||||
</div>
|
||||
@@ -121,7 +121,7 @@ export const EngineSystemMetrics: React.FC<EngineStatusProps> = ({
|
||||
<div className="flex-col gap-y-4">
|
||||
<h2 className="font-semibold">Time to mine</h2>
|
||||
<p className="text-muted-foreground">
|
||||
p50 {(msToMine.p50 / 1000).toFixed(2)}s, p90
|
||||
p50 {(msToMine.p50 / 1000).toFixed(2)}s, p90{" "}
|
||||
{(msToMine.p90 / 1000).toFixed(2)}s
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ export function ContractRow({ category }: ContractRowProps) {
|
||||
</Link>
|
||||
|
||||
<p className="text-muted-foreground">
|
||||
{category.description}
|
||||
{category.description}{" "}
|
||||
{category.learnMore && (
|
||||
<Link
|
||||
target="_blank"
|
||||
|
||||
@@ -14,7 +14,7 @@ export const DeployUpsellCard: React.FC = () => {
|
||||
<div className="h-8" />
|
||||
|
||||
<p className="text-muted-foreground ">
|
||||
Create a contract with a single command.
|
||||
Create a contract with a single command.{" "}
|
||||
<TrackedLinkTW
|
||||
category="deploy_upsell"
|
||||
label="contract_kit"
|
||||
@@ -38,7 +38,7 @@ export const DeployUpsellCard: React.FC = () => {
|
||||
<div className="h-8" />
|
||||
|
||||
<p className="text-muted-foreground ">
|
||||
Deploy a contract with a single command.
|
||||
Deploy a contract with a single command.{" "}
|
||||
<TrackedLinkTW
|
||||
category="deploy_upsell"
|
||||
label="portal_deploy"
|
||||
|
||||
@@ -26,7 +26,7 @@ export const PublishUpsellCard: React.FC = () => {
|
||||
|
||||
<p className="text-muted-foreground">
|
||||
<span className="font-semibold text-foreground">
|
||||
Save development time.
|
||||
Save development time.{" "}
|
||||
</span>
|
||||
Focus on protocol development and save time by not having to build
|
||||
middleware layer yourself.
|
||||
@@ -41,7 +41,7 @@ export const PublishUpsellCard: React.FC = () => {
|
||||
/>
|
||||
<p className="text-muted-foreground">
|
||||
<span className="font-semibold text-foreground">
|
||||
Shareable landing page.
|
||||
Shareable landing page.{" "}
|
||||
</span>
|
||||
By publishing your contract, your contracts become easily shareable
|
||||
with a landing page for your contract.
|
||||
|
||||
@@ -7,13 +7,13 @@ const faqs = [
|
||||
title: "How do we integrate the Earn Alliance task system?",
|
||||
description: (
|
||||
<Text fontSize="16px" color="#fff">
|
||||
Check out the docs, and email
|
||||
Check out the docs, and email{" "}
|
||||
<Link
|
||||
href="mailto:[email protected]"
|
||||
style={{ color: "lightblue", textDecoration: "underline" }}
|
||||
>
|
||||
hackathon@earnalliance.com
|
||||
</Link>
|
||||
</Link>{" "}
|
||||
to access the test dashboard for Earn Alliance challenges and the event
|
||||
system.
|
||||
</Text>
|
||||
|
||||
@@ -10,7 +10,7 @@ const Reason = () => {
|
||||
|
||||
<Flex flexDir="column" gap={8}>
|
||||
<Text textAlign="left" size="body.xl" color="white">
|
||||
The next wave of web3 mass adoption is already happening.
|
||||
The next wave of web3 mass adoption is already happening.{" "}
|
||||
<b>
|
||||
If you want to be one of the next big crypto apps, the time to build
|
||||
is now!
|
||||
@@ -18,12 +18,12 @@ const Reason = () => {
|
||||
</Text>
|
||||
|
||||
<Text textAlign="left" size="body.xl" color="white">
|
||||
This February, we're excited to host the
|
||||
This February, we're excited to host the{" "}
|
||||
<b>Consumer Crypto Hackathon</b> — bringing the hungriest builders to
|
||||
San Francisco to
|
||||
San Francisco to{" "}
|
||||
<b>discover the next billion-dollar web3 consumer app.</b> Get
|
||||
resources & expertise from top operators, find your next co-founder,
|
||||
and meet builders & investors from
|
||||
and meet builders & investors from{" "}
|
||||
<b>Caldera, Pantera Capital, Founders Inc, and Haun Ventures.</b>
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
@@ -51,7 +51,7 @@ const Timer: React.FC<TimerProps> = ({ date }) => {
|
||||
];
|
||||
|
||||
return (
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
{items.map(({ label, value }) => (
|
||||
<Flex flexDir="column" key={label} align="center">
|
||||
<Text
|
||||
@@ -69,14 +69,14 @@ const Timer: React.FC<TimerProps> = ({ date }) => {
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
}}
|
||||
>
|
||||
{value < 10 ? `0${value}` : value}
|
||||
{value < 10 ? `0${value}` : value}{" "}
|
||||
</Text>
|
||||
<Text fontWeight={500} fontSize="14px" color="#e984f3" mt={1}>
|
||||
{value === 1 ? label : `${label}s`}
|
||||
</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ const FAQs = [
|
||||
question: "Where will this event take place?",
|
||||
answer: (
|
||||
<>
|
||||
The ReadyPlayer3 Hackathon will take place via
|
||||
The ReadyPlayer3 Hackathon will take place via{" "}
|
||||
<Link href="https://readyplayer3.devpost.com/" color="primary.600">
|
||||
DevPost
|
||||
</Link>
|
||||
@@ -51,7 +51,7 @@ const FAQs = [
|
||||
question: "Where can I see all the build tracks?",
|
||||
answer: (
|
||||
<>
|
||||
Check out
|
||||
Check out{" "}
|
||||
<Link
|
||||
href="https://www.notion.so/thirdweb/thirdweb-s-Ready-Player-3-Hackathon-Build-Tracks-f1eede16a3e343f48a9ec25a395d0afc"
|
||||
textDecor="underline"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
AspectRatio,
|
||||
Box,
|
||||
Flex,
|
||||
Modal,
|
||||
@@ -87,14 +86,14 @@ export const GameShowcase = () => {
|
||||
>
|
||||
<ModalCloseButton />
|
||||
</Box>
|
||||
<AspectRatio ratio={{ base: 16 / 9, md: 16 / 9 }} w="100%">
|
||||
<div className="relative aspect-[16/9] w-full">
|
||||
<Box
|
||||
bg="#000"
|
||||
borderRadius={{ base: "md", md: "lg" }}
|
||||
as="iframe"
|
||||
src={selectedGame}
|
||||
/>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</Flex>
|
||||
|
||||
@@ -209,26 +209,24 @@ export const HomePageCodeBlock: React.FC<CodeBlockProps> = ({
|
||||
as={Code}
|
||||
h="full"
|
||||
>
|
||||
<Box>
|
||||
<Box>
|
||||
<Box as="span" display="block" my={1} color="heading">
|
||||
{tokens.map((line, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
|
||||
<Box key={i} {...getLineProps({ line })}>
|
||||
<LineNumbers
|
||||
lineNumber={i + 1}
|
||||
lineHeight={chakraTheme.sizes["5"]}
|
||||
totalLines={tokens.length}
|
||||
/>
|
||||
{line.map((token, key) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
|
||||
<span key={key} {...getTokenProps({ token })} />
|
||||
))}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
<div>
|
||||
<Box as="span" display="block" my={1} color="heading">
|
||||
{tokens.map((line, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
|
||||
<Box key={i} {...getLineProps({ line })}>
|
||||
<LineNumbers
|
||||
lineNumber={i + 1}
|
||||
lineHeight={chakraTheme.sizes["5"]}
|
||||
totalLines={tokens.length}
|
||||
/>
|
||||
{line.map((token, key) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
|
||||
<span key={key} {...getTokenProps({ token })} />
|
||||
))}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</Highlight>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Center, Flex, LightMode } from "@chakra-ui/react";
|
||||
import { Box, Flex, LightMode } from "@chakra-ui/react";
|
||||
import { ChakraNextImage } from "components/Image";
|
||||
import { HomepageSection } from "components/product-pages/homepage/HomepageSection";
|
||||
import { GeneralCta } from "components/shared/GeneralCta";
|
||||
@@ -18,8 +18,8 @@ export const GetStartedSection = () => {
|
||||
align="center"
|
||||
gap={{ base: 6, md: 8 }}
|
||||
>
|
||||
<Center mb={6} pt={{ base: 8, lg: 24 }}>
|
||||
<Center p={2} position="relative" mb={6}>
|
||||
<div className="mb-6 flex items-center justify-center pt-8 lg:pt-24">
|
||||
<div className="relative mb-6 flex items-center justify-center p-2">
|
||||
<Box
|
||||
position="absolute"
|
||||
bgGradient="linear(to-r, #F213A4, #040BBF)"
|
||||
@@ -38,8 +38,8 @@ export const GetStartedSection = () => {
|
||||
placeholder="empty"
|
||||
src={WhiteLogo}
|
||||
/>
|
||||
</Center>
|
||||
</Center>
|
||||
</div>
|
||||
</div>
|
||||
<Heading as="h2" size="display.md" textAlign="center">
|
||||
Get started with thirdweb
|
||||
</Heading>
|
||||
|
||||
@@ -36,7 +36,7 @@ export const HeroSection = ({ TRACKING_CATEGORY }: HeroSectionProps) => {
|
||||
px={{ base: 2, md: 0 }}
|
||||
fontSize={{ base: "36px", sm: "45px" }}
|
||||
>
|
||||
Full-stack, <OpenSource TRACKING_CATEGORY={TRACKING_CATEGORY} />
|
||||
Full-stack, <OpenSource TRACKING_CATEGORY={TRACKING_CATEGORY} />{" "}
|
||||
web3 development platform
|
||||
</Heading>
|
||||
</Flex>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AccountPlan } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { Box, type CardProps, Center, Flex } from "@chakra-ui/react";
|
||||
import { Box, type CardProps, Flex } from "@chakra-ui/react";
|
||||
import {
|
||||
Badge,
|
||||
Card,
|
||||
@@ -60,7 +60,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
|
||||
>
|
||||
<Flex flexDir="column" gap={6}>
|
||||
<Flex flexDir="column" gap={3}>
|
||||
<Flex gap={2}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<Heading
|
||||
as="h3"
|
||||
size={size === "lg" ? "title.lg" : "title.sm"}
|
||||
@@ -79,7 +79,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
|
||||
Current plan
|
||||
</Badge>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
<Text maxW={320} h={12}>
|
||||
{plan.description}
|
||||
</Text>
|
||||
@@ -96,7 +96,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
|
||||
<>
|
||||
<Box as="span" textDecor="line-through" opacity={0.4}>
|
||||
${plan.price}
|
||||
</Box>
|
||||
</Box>{" "}
|
||||
$0
|
||||
</>
|
||||
) : (
|
||||
@@ -108,7 +108,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
|
||||
</Flex>
|
||||
{remainingTrialDays > 0 && (
|
||||
<Text size="body.sm" fontStyle="italic">
|
||||
Your free trial will
|
||||
Your free trial will{" "}
|
||||
{remainingTrialDays > 1
|
||||
? `end in ${remainingTrialDays} days.`
|
||||
: "end today."}
|
||||
@@ -174,7 +174,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
|
||||
|
||||
if (highlighted) {
|
||||
return (
|
||||
<Center position="relative" p={2} m={-2}>
|
||||
<div className="-m-2 relative flex items-center justify-center p-2">
|
||||
<Box
|
||||
position="absolute"
|
||||
bgGradient="linear(to-b, #4DABEE, #692AC1)"
|
||||
@@ -187,7 +187,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
|
||||
filter="blur(8px)"
|
||||
/>
|
||||
{content}
|
||||
</Center>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ export const PricingEngineHomepage: React.FC<PricingSectionProps> = ({
|
||||
textAlign="center"
|
||||
px={{ base: 2, md: 0 }}
|
||||
>
|
||||
Simple, transparent & flexible
|
||||
Simple, transparent & flexible{" "}
|
||||
<Box bgGradient="linear(to-r, #4DABEE, #692AC1)" bgClip="text">
|
||||
pricing for every team.
|
||||
</Box>
|
||||
|
||||
@@ -25,14 +25,14 @@ export const PricingSection: React.FC<PricingSectionProps> = ({
|
||||
textAlign="center"
|
||||
px={{ base: 2, md: 0 }}
|
||||
>
|
||||
Simple, transparent & flexible
|
||||
Simple, transparent & flexible{" "}
|
||||
<Box bgGradient="linear(to-r, #4DABEE, #692AC1)" bgClip="text">
|
||||
pricing for every team.
|
||||
</Box>
|
||||
</Heading>
|
||||
{onHomepage && (
|
||||
<Text textAlign="center" size="body.lg">
|
||||
Learn more about
|
||||
Learn more about{" "}
|
||||
<TrackedLink
|
||||
category={trackingCategory}
|
||||
href="/pricing"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Image,
|
||||
LinkBox,
|
||||
@@ -85,7 +84,7 @@ const SolutionCard: React.FC<SolutionCardProps> = ({
|
||||
py={{ base: 10 }}
|
||||
flexGrow={1}
|
||||
>
|
||||
<Box>
|
||||
<div>
|
||||
<Heading
|
||||
as="h3"
|
||||
fontSize="24px"
|
||||
@@ -106,7 +105,7 @@ const SolutionCard: React.FC<SolutionCardProps> = ({
|
||||
<Text size="body.lg" lineHeight={1.7} color="whiteAlpha.700">
|
||||
{description}
|
||||
</Text>
|
||||
</Box>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AspectRatio, GridItem, SimpleGrid } from "@chakra-ui/react";
|
||||
import { GridItem, SimpleGrid } from "@chakra-ui/react";
|
||||
import { themes } from "prism-react-renderer";
|
||||
import { HomePageCodeBlock } from "../CodeBlock";
|
||||
import { KeyFeatureLayout } from "./key-features/KeyFeatureLayout";
|
||||
@@ -113,7 +113,7 @@ export const WithoutThirdwebSection: React.FC = () => {
|
||||
>
|
||||
<SimpleGrid columns={12} gap={8} w="full">
|
||||
<GridItem colSpan={{ base: 12, md: 6 }}>
|
||||
<AspectRatio ratio={16 / 10} w="full">
|
||||
<div className="relative aspect-[16/10] w-full">
|
||||
<HomePageCodeBlock
|
||||
darkTheme={darkTheme}
|
||||
color="white"
|
||||
@@ -128,10 +128,10 @@ export const WithoutThirdwebSection: React.FC = () => {
|
||||
titleColor="gray.600"
|
||||
borderTopRadius={0}
|
||||
/>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem colSpan={{ base: 12, md: 6 }}>
|
||||
<AspectRatio ratio={16 / 10} w="full">
|
||||
<div className="relative aspect-[16/10] w-full">
|
||||
<HomePageCodeBlock
|
||||
darkTheme={darkTheme}
|
||||
color="white"
|
||||
@@ -146,7 +146,7 @@ export const WithoutThirdwebSection: React.FC = () => {
|
||||
titleColor="white"
|
||||
borderTopRadius={0}
|
||||
/>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
</GridItem>
|
||||
</SimpleGrid>
|
||||
</KeyFeatureLayout>
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useThirdwebClient } from "@/constants/thirdweb.client";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useDashboardStorageUpload } from "@3rdweb-sdk/react/hooks/useDashboardStorageUpload";
|
||||
import {
|
||||
AspectRatio,
|
||||
Box,
|
||||
ButtonGroup,
|
||||
Center,
|
||||
Divider,
|
||||
Flex,
|
||||
GridItem,
|
||||
@@ -17,7 +16,6 @@ import {
|
||||
SimpleGrid,
|
||||
Tooltip,
|
||||
chakra,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { PINNED_FILES_QUERY_KEY_ROOT } from "components/storage/your-files";
|
||||
@@ -28,6 +26,7 @@ import { type Dispatch, type SetStateAction, useMemo, useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import { BsFillCloudUploadFill } from "react-icons/bs";
|
||||
import { FiExternalLink, FiTrash2, FiUploadCloud } from "react-icons/fi";
|
||||
import { toast } from "sonner";
|
||||
import { MediaRenderer } from "thirdweb/react";
|
||||
import { useActiveAccount } from "thirdweb/react";
|
||||
import {
|
||||
@@ -46,7 +45,6 @@ const TRACKING_CATEGORY = "ipfs_uploader";
|
||||
const UNACCEPTED_FILE_TYPES = ["text/html"];
|
||||
|
||||
export const IpfsUploadDropzone: React.FC = () => {
|
||||
const toast = useToast();
|
||||
const address = useActiveAccount()?.address;
|
||||
|
||||
const [droppedFiles, setDroppedFiles] = useState<File[]>([]);
|
||||
@@ -57,13 +55,8 @@ export const IpfsUploadDropzone: React.FC = () => {
|
||||
UNACCEPTED_FILE_TYPES.includes(f.type),
|
||||
);
|
||||
if (invalidFiles.length) {
|
||||
const description = `${invalidFiles.length} ${invalidFiles.length > 1 ? "files have" : "file has"} been removed from the list. Uploading ${UNACCEPTED_FILE_TYPES.join(", ")} files is restricted.`;
|
||||
toast({
|
||||
title: "Error",
|
||||
description,
|
||||
status: "error",
|
||||
isClosable: true,
|
||||
duration: 6000,
|
||||
toast.error("Error", {
|
||||
description: `${invalidFiles.length} ${invalidFiles.length > 1 ? "files have" : "file has"} been removed from the list. Uploading ${UNACCEPTED_FILE_TYPES.join(", ")} files is restricted.`,
|
||||
});
|
||||
}
|
||||
setDroppedFiles((prev) => [
|
||||
@@ -74,23 +67,20 @@ export const IpfsUploadDropzone: React.FC = () => {
|
||||
});
|
||||
return (
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<AspectRatio
|
||||
ratio={{
|
||||
base: droppedFiles.length ? 1 : 8 / 4,
|
||||
md: droppedFiles.length ? 16 / 9 : 36 / 9,
|
||||
}}
|
||||
w="100%"
|
||||
<div
|
||||
className={cn(
|
||||
"relative w-full",
|
||||
droppedFiles.length
|
||||
? "aspect-square md:aspect-[16/9]"
|
||||
: "aspect-[2] md:aspect-[36/9]",
|
||||
)}
|
||||
>
|
||||
{droppedFiles.length ? (
|
||||
<Box border="2px solid" borderColor="borderColor" borderRadius="xl">
|
||||
<div className="h-full rounded-xl border-2 border-border">
|
||||
<FileUpload files={droppedFiles} updateFiles={setDroppedFiles} />
|
||||
</Box>
|
||||
</div>
|
||||
) : !address ? (
|
||||
<Center
|
||||
border="2px solid"
|
||||
borderColor="borderColor"
|
||||
borderRadius="xl"
|
||||
>
|
||||
<div className="flex h-full items-center justify-center rounded-xl border-2 border-border">
|
||||
<Text
|
||||
size="label.lg"
|
||||
className="text-muted-foreground"
|
||||
@@ -98,23 +88,14 @@ export const IpfsUploadDropzone: React.FC = () => {
|
||||
>
|
||||
Please connect your wallet to begin uploading.
|
||||
</Text>
|
||||
</Center>
|
||||
</div>
|
||||
) : (
|
||||
<Center
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center justify-center rounded-xl border-2 border-border border-solid bg-transparent hover:border-blue-600 dark:border-blue-400",
|
||||
address ? "cursor-pointer" : "cursor-default",
|
||||
)}
|
||||
{...getRootProps()}
|
||||
bg="transparent"
|
||||
_hover={{
|
||||
_light: {
|
||||
borderColor: "blue.600",
|
||||
},
|
||||
_dark: {
|
||||
borderColor: "blue.400",
|
||||
},
|
||||
}}
|
||||
border="2px solid"
|
||||
borderColor="borderColor"
|
||||
borderRadius="xl"
|
||||
cursor={address ? "pointer" : "default"}
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
|
||||
@@ -146,9 +127,9 @@ export const IpfsUploadDropzone: React.FC = () => {
|
||||
)}
|
||||
</Flex>
|
||||
}
|
||||
</Center>
|
||||
</div>
|
||||
)}
|
||||
</AspectRatio>
|
||||
</div>
|
||||
<Flex flexDir="column" gap={{ base: 6, md: 3 }} />
|
||||
</Flex>
|
||||
);
|
||||
@@ -232,7 +213,7 @@ const FileUpload: React.FC<FileUploadProps> = ({ files, updateFiles }) => {
|
||||
alignItems="center"
|
||||
>
|
||||
<GridItem colSpan={5} rowSpan={2}>
|
||||
<AspectRatio ratio={1}>
|
||||
<div className="relative aspect-square">
|
||||
<Box
|
||||
rounded="lg"
|
||||
overflow="hidden"
|
||||
@@ -250,7 +231,7 @@ const FileUpload: React.FC<FileUploadProps> = ({ files, updateFiles }) => {
|
||||
client={client}
|
||||
/>
|
||||
</Box>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem colSpan={16} rowSpan={1}>
|
||||
<Heading size="label.md" as="label" noOfLines={2}>
|
||||
@@ -390,7 +371,7 @@ const FileUpload: React.FC<FileUploadProps> = ({ files, updateFiles }) => {
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
<Flex direction="column">
|
||||
<div className="flex flex-col">
|
||||
<Divider flexShrink={0} />
|
||||
<Flex
|
||||
direction={{ base: "column-reverse", md: "row" }}
|
||||
@@ -438,14 +419,7 @@ const FileUpload: React.FC<FileUploadProps> = ({ files, updateFiles }) => {
|
||||
isIndeterminate={storageUpload.isPending}
|
||||
position="relative"
|
||||
/>
|
||||
<Center
|
||||
display={{ base: "none", md: "block" }}
|
||||
position="absolute"
|
||||
left={0}
|
||||
right={0}
|
||||
top={0}
|
||||
bottom={0}
|
||||
>
|
||||
<div className="absolute top-0 right-0 bottom-0 left-0 hidden md:block">
|
||||
{/* <Text
|
||||
mt={0.5}
|
||||
size="label.xs"
|
||||
@@ -472,7 +446,7 @@ const FileUpload: React.FC<FileUploadProps> = ({ files, updateFiles }) => {
|
||||
>
|
||||
{Math.round(progressPercent)}%
|
||||
</Text> */}
|
||||
</Center>
|
||||
</div>
|
||||
</Flex>
|
||||
)}
|
||||
<ButtonGroup ml={{ base: "0", md: "auto" }}>
|
||||
@@ -552,7 +526,7 @@ const FileUpload: React.FC<FileUploadProps> = ({ files, updateFiles }) => {
|
||||
)}
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ export const LandingEndCTA: React.FC<LandingEndCTAProps> = ({
|
||||
<Container maxW={containerMaxW || "container.md"}>
|
||||
<Flex flexDir="column" gap={12}>
|
||||
<Heading pt={{ base: 20, md: 0 }} size="display.md" textAlign="center">
|
||||
{title}
|
||||
{title}{" "}
|
||||
{titleWithGradient && (
|
||||
<Box as="span" bgGradient={gradient} bgClip="text">
|
||||
{titleWithGradient}
|
||||
|
||||
@@ -118,7 +118,7 @@ export const LandingGuidesShowcase: React.FC<LandingGuidesShowcaseProps> = ({
|
||||
lineHeight={{ base: 1.5, md: undefined }}
|
||||
position="relative"
|
||||
>
|
||||
See all of our {solution.replace("-", " ")}
|
||||
See all of our {solution.replace("-", " ")}{" "}
|
||||
{caseStudies ? "case studies" : "guides"}
|
||||
</Heading>
|
||||
<Icon as={FiArrowRight} />
|
||||
|
||||
@@ -69,7 +69,7 @@ export const LandingHeroWithSideImage: React.FC<
|
||||
)}
|
||||
</Flex>
|
||||
<Heading as="h1" size="display.sm" px={{ base: 2, md: 0 }} mr={6}>
|
||||
{title}
|
||||
{title}{" "}
|
||||
<Box as="span" bgGradient={gradient} bgClip="text">
|
||||
{titleWithGradient}
|
||||
</Box>
|
||||
|
||||
@@ -63,7 +63,7 @@ export const LandingHero: React.FC<LandingHeroProps> = ({
|
||||
textAlign="center"
|
||||
px={{ base: 2, md: 0 }}
|
||||
>
|
||||
{title}
|
||||
{title}{" "}
|
||||
<Box as="span" bgGradient={gradient} bgClip="text">
|
||||
{titleWithGradient}
|
||||
</Box>
|
||||
|
||||
@@ -22,7 +22,7 @@ export const LandingSectionHeading: React.FC<LandingSectionHeadingProps> = ({
|
||||
)}
|
||||
|
||||
<Heading size={titleSize} lineHeight={lineHeight}>
|
||||
{title}
|
||||
{title}{" "}
|
||||
{titleWithGradient && (
|
||||
<Box as="span" bgGradient={gradient} bgClip="text">
|
||||
{titleWithGradient}
|
||||
|
||||
@@ -47,7 +47,7 @@ export const SplashImage: React.FC<SplashImageProps> = ({
|
||||
textAlign="center"
|
||||
px={{ base: 2, md: 0 }}
|
||||
>
|
||||
{title}
|
||||
{title}{" "}
|
||||
<Box as="span" bgGradient={gradient} bgClip="text">
|
||||
{titleWithGradient}
|
||||
</Box>
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import {
|
||||
AspectRatio,
|
||||
type AspectRatioProps,
|
||||
Stack,
|
||||
VisuallyHidden,
|
||||
} from "@chakra-ui/react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Stack, VisuallyHidden } from "@chakra-ui/react";
|
||||
|
||||
export const IconLogo: React.FC<Omit<AspectRatioProps, "ratio">> = ({
|
||||
export const IconLogo: React.FC<{ extraClass?: string; color?: string }> = ({
|
||||
color,
|
||||
...props
|
||||
extraClass,
|
||||
}) => {
|
||||
return (
|
||||
<AspectRatio ratio={516 / 321} {...props}>
|
||||
<div className={cn("relative aspect-[516/321]", extraClass || "")}>
|
||||
<svg viewBox="0 0 516 321" fill="none">
|
||||
<title>thirdweb</title>
|
||||
<g clipPath="url(#clip0_3:35)">
|
||||
@@ -81,26 +77,7 @@ export const IconLogo: React.FC<Omit<AspectRatioProps, "ratio">> = ({
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</AspectRatio>
|
||||
);
|
||||
};
|
||||
|
||||
const Wordmark: React.FC<Omit<AspectRatioProps, "ratio">> = ({
|
||||
color = "var(--chakra-colors-wordmark)",
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<AspectRatio ratio={1377 / 267} {...props}>
|
||||
<svg viewBox="0 0 1377 267" fill="none">
|
||||
<title>thirdweb</title>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M351.582 2C335.29 2 321.931 15.2034 321.931 32.0377C321.931 48.542 335.29 61.7454 351.582 61.7454C367.874 61.7454 381.233 48.542 381.233 32.0377C381.233 15.2034 367.874 2 351.582 2ZM377.649 76.9285H325.84V254.844H377.649V76.9285ZM23.4605 8.60203H73.9657V76.9296H112.741V124.462H73.9657V187.178C73.9657 196.42 81.1342 203.682 89.9318 203.682H112.415V254.185H89.9318C53.4378 254.185 23.4605 224.147 23.4605 186.848V124.132H0V76.5995H23.4605V8.60203ZM236.234 72.9686C212.774 72.9686 194.201 82.8711 187.032 98.3851V8.60203H135.224V254.515H187.032V154.83C187.032 134.034 200.392 119.511 219.291 119.511C238.515 119.511 249.268 132.054 249.268 153.179V254.845H301.076V146.577C301.076 100.366 277.616 72.9686 236.234 72.9686ZM451.613 76.5995V101.026C459.433 83.2012 478.332 72.9686 502.118 72.6385C505.703 72.6385 510.264 72.9686 515.804 73.6288V123.141C510.59 122.151 504.725 121.491 498.534 121.491C468.883 121.491 451.613 138.325 451.613 167.703V254.515H399.805V76.5995H451.613ZM661.455 100.036C656.242 84.5216 635.714 73.6288 609.321 73.6288C584.557 73.6288 563.703 82.541 547.085 100.366C530.793 117.86 522.322 139.976 522.322 165.722C522.322 191.469 530.793 213.255 547.085 231.409C563.703 248.904 584.557 257.816 609.321 257.816C635.714 257.816 656.242 246.923 661.455 231.409V254.845H713.264V8.60203H661.455V100.036ZM651.029 197.411C642.231 205.993 631.478 209.954 618.77 209.954C606.388 209.954 595.636 205.663 587.164 197.411C578.366 188.498 574.13 177.936 574.13 165.722C574.13 153.509 578.366 142.947 587.164 134.364C595.961 125.452 606.388 121.161 618.77 121.161C631.804 121.161 642.557 125.452 651.029 134.364C660.152 142.947 664.714 153.509 664.714 165.722C664.714 177.936 660.152 188.498 651.029 197.411ZM862.824 77.5887L909.745 162.09L941.352 76.9285H992.183L919.846 265.077L862.824 162.751L805.803 265.077L733.792 76.9285H784.623L815.904 162.09L862.824 77.5887ZM1077.55 72.6385C1050.83 72.6385 1028.35 81.2207 1010.76 98.3851C993.486 115.219 984.688 137.665 984.688 165.392V167.043C984.688 194.77 993.486 217.216 1010.76 234.05C1028.68 250.554 1051.49 259.136 1080.16 259.136C1106.88 259.136 1128.71 253.855 1145.33 242.962V197.08C1129.04 208.633 1108.18 214.245 1083.09 214.245C1055.72 214.245 1037.8 200.711 1036.82 179.586H1165.53C1166.18 174.305 1166.51 168.363 1166.51 162.422C1166.51 137.005 1158.03 115.88 1141.74 98.7152C1125.45 81.2207 1103.62 72.6385 1077.55 72.6385ZM1036.82 145.587C1037.15 137.335 1041.38 130.403 1049.2 124.792C1057.35 119.18 1066.47 116.21 1077.55 116.21C1098.08 116.21 1114.05 129.743 1114.05 145.587H1036.82ZM1290 73.6288C1314.76 73.6288 1335.62 82.541 1351.91 100.366C1368.53 118.19 1377 139.646 1377 165.392C1377 191.139 1368.53 212.925 1351.91 231.079C1335.62 248.574 1314.76 257.486 1290 257.486C1263.61 257.486 1243.08 246.593 1237.87 231.079V254.515H1186.06V8.60203H1237.87V100.036C1243.08 84.5216 1263.61 73.6288 1290 73.6288ZM1280.55 209.954C1292.93 209.954 1303.36 205.993 1312.16 197.411C1320.95 188.498 1325.19 177.936 1325.19 165.722C1325.19 153.509 1320.95 142.947 1312.16 134.364C1303.69 125.452 1292.93 121.161 1280.55 121.161C1267.84 121.161 1257.09 125.452 1247.97 134.364C1239.17 142.947 1234.61 153.509 1234.61 165.722C1234.61 177.936 1239.17 188.498 1247.97 197.411C1256.76 205.663 1267.52 209.954 1280.55 209.954Z"
|
||||
fill={color as string}
|
||||
/>
|
||||
</svg>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -115,18 +92,29 @@ export const Logo: React.FC<ILogoProps> = ({
|
||||
hideIcon,
|
||||
hideWordmark,
|
||||
forceShowWordMark,
|
||||
color,
|
||||
color = "var(--chakra-colors-wordmark)",
|
||||
}) => {
|
||||
return (
|
||||
<Stack as="h2" align="center" direction="row">
|
||||
{hideIcon ?? <IconLogo w={[9, 9, 10]} flexShrink={0} />}
|
||||
{hideIcon ?? <IconLogo extraClass="w-9 md:w-10 flex-shrink-0" />}
|
||||
{(hideWordmark && !forceShowWordMark) ?? (
|
||||
<Wordmark
|
||||
display={forceShowWordMark ? "block" : { base: "none", md: "block" }}
|
||||
color={color}
|
||||
w={[24, 24, 28]}
|
||||
flexShrink={0}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
"relative aspect-[1377/267] w-24 flex-shrink-0 md:w-28",
|
||||
forceShowWordMark ? "block" : "none md:block",
|
||||
)}
|
||||
style={color ? { color } : undefined}
|
||||
>
|
||||
<svg viewBox="0 0 1377 267" fill="none">
|
||||
<title>thirdweb</title>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M351.582 2C335.29 2 321.931 15.2034 321.931 32.0377C321.931 48.542 335.29 61.7454 351.582 61.7454C367.874 61.7454 381.233 48.542 381.233 32.0377C381.233 15.2034 367.874 2 351.582 2ZM377.649 76.9285H325.84V254.844H377.649V76.9285ZM23.4605 8.60203H73.9657V76.9296H112.741V124.462H73.9657V187.178C73.9657 196.42 81.1342 203.682 89.9318 203.682H112.415V254.185H89.9318C53.4378 254.185 23.4605 224.147 23.4605 186.848V124.132H0V76.5995H23.4605V8.60203ZM236.234 72.9686C212.774 72.9686 194.201 82.8711 187.032 98.3851V8.60203H135.224V254.515H187.032V154.83C187.032 134.034 200.392 119.511 219.291 119.511C238.515 119.511 249.268 132.054 249.268 153.179V254.845H301.076V146.577C301.076 100.366 277.616 72.9686 236.234 72.9686ZM451.613 76.5995V101.026C459.433 83.2012 478.332 72.9686 502.118 72.6385C505.703 72.6385 510.264 72.9686 515.804 73.6288V123.141C510.59 122.151 504.725 121.491 498.534 121.491C468.883 121.491 451.613 138.325 451.613 167.703V254.515H399.805V76.5995H451.613ZM661.455 100.036C656.242 84.5216 635.714 73.6288 609.321 73.6288C584.557 73.6288 563.703 82.541 547.085 100.366C530.793 117.86 522.322 139.976 522.322 165.722C522.322 191.469 530.793 213.255 547.085 231.409C563.703 248.904 584.557 257.816 609.321 257.816C635.714 257.816 656.242 246.923 661.455 231.409V254.845H713.264V8.60203H661.455V100.036ZM651.029 197.411C642.231 205.993 631.478 209.954 618.77 209.954C606.388 209.954 595.636 205.663 587.164 197.411C578.366 188.498 574.13 177.936 574.13 165.722C574.13 153.509 578.366 142.947 587.164 134.364C595.961 125.452 606.388 121.161 618.77 121.161C631.804 121.161 642.557 125.452 651.029 134.364C660.152 142.947 664.714 153.509 664.714 165.722C664.714 177.936 660.152 188.498 651.029 197.411ZM862.824 77.5887L909.745 162.09L941.352 76.9285H992.183L919.846 265.077L862.824 162.751L805.803 265.077L733.792 76.9285H784.623L815.904 162.09L862.824 77.5887ZM1077.55 72.6385C1050.83 72.6385 1028.35 81.2207 1010.76 98.3851C993.486 115.219 984.688 137.665 984.688 165.392V167.043C984.688 194.77 993.486 217.216 1010.76 234.05C1028.68 250.554 1051.49 259.136 1080.16 259.136C1106.88 259.136 1128.71 253.855 1145.33 242.962V197.08C1129.04 208.633 1108.18 214.245 1083.09 214.245C1055.72 214.245 1037.8 200.711 1036.82 179.586H1165.53C1166.18 174.305 1166.51 168.363 1166.51 162.422C1166.51 137.005 1158.03 115.88 1141.74 98.7152C1125.45 81.2207 1103.62 72.6385 1077.55 72.6385ZM1036.82 145.587C1037.15 137.335 1041.38 130.403 1049.2 124.792C1057.35 119.18 1066.47 116.21 1077.55 116.21C1098.08 116.21 1114.05 129.743 1114.05 145.587H1036.82ZM1290 73.6288C1314.76 73.6288 1335.62 82.541 1351.91 100.366C1368.53 118.19 1377 139.646 1377 165.392C1377 191.139 1368.53 212.925 1351.91 231.079C1335.62 248.574 1314.76 257.486 1290 257.486C1263.61 257.486 1243.08 246.593 1237.87 231.079V254.515H1186.06V8.60203H1237.87V100.036C1243.08 84.5216 1263.61 73.6288 1290 73.6288ZM1280.55 209.954C1292.93 209.954 1303.36 205.993 1312.16 197.411C1320.95 188.498 1325.19 177.936 1325.19 165.722C1325.19 153.509 1320.95 142.947 1312.16 134.364C1303.69 125.452 1292.93 121.161 1280.55 121.161C1267.84 121.161 1257.09 125.452 1247.97 134.364C1239.17 142.947 1234.61 153.509 1234.61 165.722C1234.61 177.936 1239.17 188.498 1247.97 197.411C1256.76 205.663 1267.52 209.954 1280.55 209.954Z"
|
||||
fill={color}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
<VisuallyHidden>thirdweb</VisuallyHidden>
|
||||
</Stack>
|
||||
|
||||
@@ -233,7 +233,7 @@ export const ApplyForOpCreditsForm: React.FC<ApplyForOpCreditsFormProps> = ({
|
||||
<FormHelperText>Minimum 150 characters recommended.</FormHelperText>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<Button
|
||||
w="full"
|
||||
type="submit"
|
||||
@@ -242,7 +242,7 @@ export const ApplyForOpCreditsForm: React.FC<ApplyForOpCreditsFormProps> = ({
|
||||
>
|
||||
{form.formState.isSubmitting ? "Applying..." : "Apply now"}
|
||||
</Button>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -152,7 +152,7 @@ export const ApplyForOpCreditsModal: React.FC = () => {
|
||||
<AlertDescription as={Text}>
|
||||
You need to add a payment method to be able to claim
|
||||
credits. This is to prevent abuse, you will not be
|
||||
charged.
|
||||
charged.{" "}
|
||||
<Text
|
||||
as="span"
|
||||
onClick={() => {
|
||||
|
||||
@@ -169,13 +169,13 @@ const OnboardingConfirmEmail: React.FC<OnboardingConfirmEmailProps> = ({
|
||||
description={
|
||||
!completed ? (
|
||||
<>
|
||||
We've sent a 6 letter confirmation code to
|
||||
We've sent a 6 letter confirmation code to{" "}
|
||||
<strong>{email}</strong>. Copy the code and paste it below.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
We've linked
|
||||
<strong>{shortenString(user?.address ?? "")}</strong> wallet to
|
||||
We've linked{" "}
|
||||
<strong>{shortenString(user?.address ?? "")}</strong> wallet to{" "}
|
||||
<strong>{email}</strong> thirdweb account.
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -68,10 +68,10 @@ const OnboardingLinkWallet: React.FC<OnboardingLinkWalletProps> = ({
|
||||
heading="Linking Wallets"
|
||||
description={
|
||||
<>
|
||||
We've noticed that there is another account associated with
|
||||
<strong>{email}</strong>. Would you like to link your wallet
|
||||
We've noticed that there is another account associated with{" "}
|
||||
<strong>{email}</strong>. Would you like to link your wallet{" "}
|
||||
<strong>{shortenString(user?.address ?? "")}</strong> to the
|
||||
existing account? Once you agree, we will email you the details.
|
||||
existing account? Once you agree, we will email you the details.{" "}
|
||||
<TrackedLink
|
||||
href="https://portal.thirdweb.com/account/billing/account-info"
|
||||
color="blue.500"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
AspectRatio,
|
||||
Flex,
|
||||
Modal,
|
||||
ModalBody,
|
||||
@@ -39,9 +38,9 @@ export const OnboardingModal: ComponentWithChildren<OnboardingModalProps> = ({
|
||||
<ModalOverlay />
|
||||
<ModalContent className="!bg-background rounded-lg border border-border">
|
||||
<ModalBody p={8} as={Flex} gap={4} flexDir="column">
|
||||
<AspectRatio ratio={1} w="40px">
|
||||
<div className="aspect-square w-[40px]">
|
||||
<IconLogo />
|
||||
</AspectRatio>
|
||||
</div>
|
||||
|
||||
<Flex flexDir="column" gap={8}>
|
||||
{children}
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
Alert,
|
||||
AlertDescription,
|
||||
AlertIcon,
|
||||
Center,
|
||||
Flex,
|
||||
Spinner,
|
||||
} from "@chakra-ui/react";
|
||||
@@ -109,9 +108,9 @@ export const OnboardingPaymentForm: React.FC<OnboardingPaymentForm> = ({
|
||||
/>
|
||||
|
||||
{loading ? (
|
||||
<Center pb={16}>
|
||||
<div className="flex items-center justify-center pb-16">
|
||||
<Spinner size="sm" />
|
||||
</Center>
|
||||
</div>
|
||||
) : (
|
||||
<Flex flexDir="column" gap={4}>
|
||||
{paymentFailureCode ? (
|
||||
@@ -128,7 +127,7 @@ export const OnboardingPaymentForm: React.FC<OnboardingPaymentForm> = ({
|
||||
variant="left-accent"
|
||||
bg="inputBg"
|
||||
>
|
||||
<Flex>
|
||||
<div className="flex flex-row">
|
||||
<AlertIcon boxSize={4} mt={1} ml={1} />
|
||||
<Flex flexDir="column" gap={1} pl={1}>
|
||||
<AlertDescription as={Text} fontSize="body.md">
|
||||
@@ -136,7 +135,7 @@ export const OnboardingPaymentForm: React.FC<OnboardingPaymentForm> = ({
|
||||
on your payment method.
|
||||
</AlertDescription>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</div>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Flex, ListItem, UnorderedList } from "@chakra-ui/react";
|
||||
import { Flex, ListItem, UnorderedList } from "@chakra-ui/react";
|
||||
import { Badge, Card, Heading, LinkButton, Text } from "tw-components";
|
||||
import type { CreditsRecord } from "./ApplyForOpCreditsModal";
|
||||
|
||||
@@ -10,7 +10,7 @@ export const PlanCard: React.FC<PlanCardProps> = ({ creditsRecord }) => {
|
||||
return (
|
||||
<Card as={Flex} justifyContent="space-between" flexDir="column" gap={2}>
|
||||
<Flex flexDir="column" gap={2}>
|
||||
<Box>
|
||||
<div>
|
||||
<Badge
|
||||
borderRadius="full"
|
||||
size="label.sm"
|
||||
@@ -22,7 +22,7 @@ export const PlanCard: React.FC<PlanCardProps> = ({ creditsRecord }) => {
|
||||
>
|
||||
{creditsRecord.title}
|
||||
</Badge>
|
||||
</Box>
|
||||
</div>
|
||||
<Flex flexDir="column" gap={1}>
|
||||
<Text color="faded">{creditsRecord.upTo ? "Up to" : "\u00A0"}</Text>
|
||||
<Heading color="bgBlack" size="title.md" fontWeight="extrabold">
|
||||
|
||||
@@ -208,7 +208,7 @@ export const OnboardingSteps: React.FC<OnboardingStepsProps> = ({
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<Text>
|
||||
Successful applicants will receive gas grants which can be used
|
||||
across all supported
|
||||
across all supported{" "}
|
||||
<Link
|
||||
href="https://blog.thirdweb.com/accelerating-the-superchain-with-optimism"
|
||||
isExternal
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user