Compare commits

...
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
98f2b56c19 Version Packages (#4782)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-26 15:29:28 +12:00
gregfromstl 500970e001 [SDK] Fix: logout on iframe (#4809)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on fixing account logout functionality and updating error messages related to transaction limits across various tests in the `thirdweb` package.

### Detailed summary
- Updated `logout` method in `iframe-auth.ts` to check for `AuthQuerier` before calling logout.
- Changed expected address in `deploy-published.test.ts`.
- Updated error messages from `TransactionError: Error - !Qty` to `DropClaimExceedLimit` in multiple test files for `erc20`, `erc721`, and `erc1155`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-26 02:14:43 +00:00
jnsdls 9c58c08945 simplify siwe auth login flow (#4808) 2024-09-26 01:23:13 +00:00
kien-ngo 587804d5a8 [Dashboard] Remove chakra useToast (#4802)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on replacing the usage of `useToast` from `@chakra-ui/react` with `toast` from `sonner` for displaying notifications across various components in the dashboard. This change aims to streamline the notification handling.

### Detailed summary
- Removed `useToast` from multiple components.
- Replaced toast notifications with `toast.info`, `toast.success`, and `toast.error` methods from `sonner`.
- Updated the `AddressCopyButton`, `PermissionsTable`, `LatestEvents`, `IpfsUploadDropzone`, and `AuthorizedWalletsTable` components to reflect these changes.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-26 00:19:57 +00:00
kumaryash90 3f83a377bc New zksolc metadata format (#4568)
## Problem solved

Handle new zksolc metadata format
ref: ipfs://QmS6ehXYWKJEJq3LBSfG2ujKPzQQJooNE7L375zyFbpxmw

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces support for a new `zksolc` metadata format in the `thirdweb` package, enhancing the handling of zkSync contracts by updating various functions and types to accommodate the new compiler type.

### Detailed summary
- Added `compilerType` option to several functions and types to support `solc` and `zksolc`.
- Updated `fetchPublishedContractMetadata` and `deployPublishedContract` to utilize `compilerType`.
- Enhanced `formatCompilerMetadata` to handle `zksolc` specific metadata.
- Modified `fetchDeployMetadata` to validate and fetch `zksolc` metadata correctly.
- Updated `CustomContractForm` to determine `compilerType` based on the active wallet chain.
- Improved error handling for missing `zksolc` metadata.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-26 00:14:07 +00:00
gregfromstl 5ab3a81f79 [Dashboard] Feature: update ecosystem wallet auth options (#4797)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces new authentication options for the ecosystem feature, updates related types, and enhances the UI components to support these options.

### Detailed summary
- Added new authentication options: `google`, `facebook`, `x`, `discord`, `farcaster`, `telegram`, `phone`, `email`, `guest`, `apple`, `coinbase`, `line`.
- Updated `Ecosystem` type to include `authOptions`.
- Modified `useUpdateEcosystem` to accept optional `authOptions`.
- Added `AuthOptionsSection` to the `EcosystemPermissionsPage`.
- Created `AuthOptionsForm` for managing authentication options.
- Implemented confirmation dialog for adding/removing auth options.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 23:47:49 +00:00
kien-ngo 931569b374 [Dashboard] Remove <Box/> easy mode (#4786)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on replacing all instances of the `Box` component with the `div` element across various files in the codebase, likely for consistency or to simplify the component structure.

### Detailed summary
- Replaced `Box` with `div` in `PermissionsTable.tsx`
- Replaced `Box` with `div` in `LatestEvents.tsx`
- Replaced `Box` with `div` in `templates.tsx`
- Replaced `Box` with `div` in `detail-page.tsx`
- Replaced `Box` with `div` in `contract-publish-form/index.tsx`
- Replaced `Box` with `div` in `custom-factory.tsx`
- Replaced `Box` with `div` in `metadata.tsx`
- Replaced `Box` with `div` in `Solutions.tsx`
- Replaced `Box` with `div` in `MiniPlayground.tsx`
- Replaced `Box` with `div` in `FormItem.tsx`
- Replaced `Box` with `div` in `DevRelEvent.tsx`
- Replaced `Box` with `div` in `shared-metadata-form.tsx`
- Replaced `Box` with `div` in `update-metadata-form.tsx`
- Replaced `Box` with `div` in `external-links-fieldset.tsx`
- Replaced `Box` with `div` in `events-feed.tsx`
- Replaced `Box` with `div` in `lazy-mint-form.tsx`
- Replaced `Box` with `div` in `mint-form.tsx`
- Replaced `Box` with `div` in `page.tsx`
- Replaced `Box` with `div` in `landing-fieldset.tsx`
- Replaced `Box` with `div` in `PlanCard.tsx`
- Replaced `Box` with `div` in `index.tsx` of `CodeBlock`
- Replaced `Box` with `div` in `SponsorshipPolicies/index.tsx`
- Replaced `Box` with `div` in `AccountAbstractionSettingsPage` across multiple instances.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 21:47:51 +00:00
kien-ngo d76618fc00 [Dashboard] Remove Flex easy mode (#4785)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on replacing instances of the `Flex` component with `div` elements that have corresponding CSS classes for layout styling. This change aims to streamline the code while maintaining the same visual structure.

### Detailed summary
- Replaced `<Flex>` with `<div className="flex flex-row">` in multiple components for horizontal alignment.
- Replaced `<Flex>` with `<div className="flex flex-col">` in several components for vertical alignment.
- Ensured all functional components maintain the same layout and behavior after changes.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 21:47:48 +00:00
kien-ngo 46acf33b5a [Dashboard] Remove more Flex (#4784)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on replacing instances of the `Flex` component with `div` elements styled with Tailwind CSS classes. This change aims to standardize layout styling across various components in the application.

### Detailed summary
- Replaced `Flex` with `div` and added Tailwind CSS classes for layout.
- Updated components in files like `GraphicContainer.tsx`, `contract-functions.tsx`, `engine-overview.tsx`, and others.
- Maintained existing functionality while improving styling consistency.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 21:47:45 +00:00
kien-ngo 10a84d2810 [Dashboard] Remove <Center /> (#4765)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on replacing the usage of the `Center` component from `@chakra-ui/react` with `div` elements styled with Flexbox classes for better layout control across various components in the dashboard.

### Detailed summary
- Replaced `Center` with `div` and applied Flexbox utility classes in multiple components for consistent styling.
- Updated components include `TransactionButton`, `ContractSplitPage`, `OnboardingPaymentForm`, and more.
- Maintained existing functionality while improving layout responsiveness.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 21:47:42 +00:00
MananTank 3e8c074011 Fix Publish page not prepopulated with latest published version metadata (#4806)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `PublishContractPage` by adding logic to handle cases where published contract metadata lacks a version. It fetches existing contracts associated with a publisher and merges their data with the fetched metadata.

### Detailed summary
- Imported `getPublishedContractsWithPublisherMapping` utility.
- Renamed variable `publishMetadata` to `publishMetadataFromUri`.
- Added logic to check if `publishMetadataFromUri` lacks a version.
- Fetched existing published contracts for the publisher.
- Merged existing contract data with `publishMetadataFromUri` if applicable.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 21:34:26 +00:00
MananTank 206340cc1d Add Img component with skeleton + fallback support (#4791)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces a new `Img` component that handles image loading states with customizable skeletons and fallbacks. It also adds a Storybook story to demonstrate various usages of the `Img` component.

### Detailed summary
- Added `Img` component to handle image loading states.
- Implemented state management for loading, fallback, and loaded statuses.
- Introduced customizable `skeleton` and `fallback` props.
- Created Storybook stories showcasing different scenarios for the `Img` component.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 21:23:16 +00:00
gregandGitHub 6153d57c34 [SDK] Fix: adds ERC20 transfer overrides param (#4804) 2024-09-26 08:23:46 +12:00
jnsdls 39aeb140d2 Handle 400 error in user creation check (#4805) 2024-09-25 20:18:15 +00:00
MananTank 8e9d13c95c Add position relative on all Shadcn/Chakra AspectRatio component replacement divs (#4801)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating various components to add the `relative` class to `div` elements that define aspect ratios, enhancing layout control and positioning.

### Detailed summary
- Added `relative` class to `div` elements in:
  - `GameShowcase.tsx` for aspect ratios `16/9`
  - `GuideCard.tsx` for aspect ratios `2400/1260`
  - `airdrop-upload-erc20.tsx` for aspect ratios `21/9`
  - `chain-header.tsx` for conditional aspect ratios
  - `airdrop-upload.tsx` for aspect ratios `21/9`
  - `snapshot-upload.tsx` for aspect ratios `21/9`
  - `upload-step.tsx` for aspect ratio `square`
  - `NFTCards.tsx` for aspect ratio `square`
  - `MarketplaceDetails.tsx` for aspect ratio `square`
  - `dropzone.tsx` for aspect ratio adjustments
  - `WithoutThirdwebSection.tsx` for aspect ratios `16/10`
  - `logo/index.tsx` for aspect ratio `516/321`
  - Updated `Logo` component for aspect ratio `1377/267`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 15:40:12 +00:00
kien-ngo d35f0b2cc6 [Dashboard] Remove <AspectRatio/> (#4750)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on removing the `AspectRatio` component from the project and replacing its usage with `div` elements styled with Tailwind CSS classes to maintain the aspect ratio.

### Detailed summary
- Deleted `@radix-ui/react-aspect-ratio` from `package.json`.
- Removed all instances of the `AspectRatio` component across various files.
- Replaced `AspectRatio` with `div` elements using Tailwind CSS classes for aspect ratios.
- Updated related props and imports as necessary.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 05:52:04 +00:00
Joaquim VergesandGitHub 2f010fa3fc feat(storage): add JSON object upload example and documentation (#4796) 2024-09-25 15:35:57 +12:00
joaquim-verges 944d56f6d8 ecosystem refactor part 4: react native edition (#4783)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing wallet functionalities and authentication processes in the `thirdweb` library, particularly for ecosystem wallets in React Native. It introduces new wallet interfaces, updates existing methods, and improves error handling for user authentication.

### Detailed summary
- Removed obsolete `web-wallet.ts.changeset/chilled-dancers-cheer.md` file.
- Added support for ecosystem wallets in `useAutoConnect` hook.
- Updated `createInAppWallet` to include new `createOptions` structure.
- Defined `IWebWallet` interface with methods for wallet setup and user status.
- Expanded `EcosystemWalletCreationOptions` to include authentication options.
- Modified `getUserStatus` to handle user status retrieval with better error logging.
- Updated `InAppWebConnector` to utilize the new wallet interfaces and methods.
- Implemented `ShardedWallet` class with user wallet status and account retrieval.
- Enhanced error handling in the authentication processes across various modules.
- Removed deprecated methods from `native-auth.ts`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 01:41:15 +00:00
joaquim-verges 1f1f99ddd0 ecosystem refactor part 3 (#4781)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces a new constant `IS_DEV` to streamline environment checks, updates various wallet-related functionalities to use `ClientScopedStorage`, and replaces enum usages with string literals for better type safety. It also enhances error handling and modifies authentication processes.

### Detailed summary
- Added `IS_DEV` constant for environment checks.
- Replaced `process.env.NODE_ENV` checks with `IS_DEV` in multiple files.
- Updated wallet functions to utilize `ClientScopedStorage`.
- Converted enums to string literals for `RecoveryShareManagement` and `AuthProvider`.
- Improved error handling in authentication functions.
- Standardized user status strings across wallet components.
- Enhanced documentation for `ecosystemWallet` function.
- Refactored several functions to accept an object with parameters for better clarity.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 01:41:12 +00:00
joaquim-verges de63195d43 ecosystem wallet refactor (part 2) (#4780)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `thirdweb` wallet implementation, specifically enhancing the `in-app` wallet functionality by integrating `localStorage` for authentication and modifying wallet creation methods.

### Detailed summary
- Deleted `get-auth-token.ts` and `ecosystem-core.ts`.
- Updated wallet creation to use `createInAppWallet`.
- Integrated `localStorage` for authentication in multiple files.
- Modified `EcosystemWalletCreationOptions` to include `InAppWalletCreationOptions`.
- Removed obsolete auth token fetching in various functions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-25 01:41:10 +00:00
Joaquim VergesandGitHub e2b3484764 Update pregen docs (#4795)
Signed-off-by: Joaquim Verges <[email protected]>
2024-09-25 11:14:10 +12:00
jnsdls c0d81dcaca Add optional Headers param to fetchChain (#4793)
### TL;DR

Added an optional Headers parameter to the `fetchChain` function.

### What changed?

- Introduced a new optional `headers` parameter to the `fetchChain` function in `apps/dashboard/src/utils/fetchChain.ts`.
- Updated the fetch request to include the provided headers.
- Created a new changeset file to document this patch-level change.

### How to test?

1. Call the `fetchChain` function without providing headers to ensure backward compatibility.
2. Call the `fetchChain` function with custom headers and verify they are included in the request.
3. Confirm that the function still correctly fetches chain metadata from the API.

### Why make this change?

This change allows for greater flexibility when making API requests to fetch chain metadata. By allowing custom headers, it enables use cases such as authentication, caching control, or other custom requirements when interacting with the API.
2024-09-24 21:09:41 +00:00
jnsdls 0aea48e37d fix typedoc setup (#4792)
### TL;DR

Refactored TypeDoc script and added a dedicated TypeScript configuration for documentation generation.

### What changed?

- Simplified the `typedoc.mjs` script by removing the `typedoc` function and directly executing the TypeDoc application.
- Added a new `tsconfig.typedoc.json` file specifically for TypeDoc configuration.
- Updated the TypeDoc application configuration to use the new TypeScript config file.

### How to test?

1. Run the TypeDoc script to generate documentation.
2. Verify that the `typedoc/documentation.json` file is created successfully.
3. Check that the generated documentation includes the correct files and excludes the specified ones.

### Why make this change?

This change improves the documentation generation process by:
1. Simplifying the TypeDoc script for better maintainability.
2. Providing a dedicated TypeScript configuration for documentation, ensuring more accurate type information.
3. Enhancing consistency in the documentation output by using a specific tsconfig file.
2024-09-24 21:03:38 +00:00
arcoraven f91e32f133 Add Alert docs to Portal (#4788)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces new features and updates to the `thirdweb Engine`, including alert notifications, metadata enhancements, and updated documentation for troubleshooting and alert management.

### Detailed summary
- Added new alert notifications feature in `page.mdx` with instructions.
- Introduced `metadata` for `Alert Notifications` and `Troubleshooting` pages.
- Updated asset imports for alert images in `page.mdx`.
- Enhanced troubleshooting documentation for clarity.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-24 19:52:49 +00:00
MananTank e38400195f Restore deleted whitespaces, Remove unsafe biome formatting (#4789)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the user interface by adding space between certain text elements and enhancing readability across various components in the dashboard application.

### Detailed summary
- Added space after text in various components to improve readability.
- Updated text elements in `templates.tsx`, `index.tsx`, `TransactionModeScreen.tsx`, and others.
- Ensured consistent formatting in `HeroSection.tsx`, `PricingCard.tsx`, and various settings pages.

> The following files were skipped due to too many changes: `apps/dashboard/src/components/embedded-wallets/Configure/index.tsx`, `apps/dashboard/src/contract-ui/tabs/claim-conditions/components/snapshot-upload.tsx`, `apps/dashboard/src/contract-ui/tabs/overview/components/ContractChecklist.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.tsx`, `apps/dashboard/src/core-ui/batch-upload/upload-step.tsx`, `packages/thirdweb/package.json`, `apps/dashboard/src/pages/template/[id].tsx`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-24 23:14:39 +05:30
joaquim-verges e02d87b831 Refactor linkProfile and getProfiles API + prepare for ecosystemWallet in React Native (#4755)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the wallet's profile management system, enhancing the `linkProfile` and `getProfiles` functionalities. It also updates the import paths and improves the organization of wallet-related hooks and types.

### Detailed summary
- Deleted `useAdminAccount.ts` and updated references to `useAdminWallet.ts`.
- Refactored `linkProfile` and `getProfiles` APIs for improved functionality.
- Updated import paths for `Ecosystem` type across multiple files.
- Consolidated wallet profiles logic in `useProfiles` hook.
- Enhanced error handling and type definitions in wallet connectors.
- Added `linkProfile` and `getProfiles` methods to `InAppNativeConnector` and `InAppWebConnector`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-24 04:05:00 +00:00
joaquim-verges d5312304f7 refactor: update contract implementation resolution and module info retrieval (#4779)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `InstalledModulesTable` component by incorporating `getContract` for fetching contract information and updating the bytecode retrieval process in the `usePublishedContractsFromDeploy` function.

### Detailed summary
- In `InstalledModulesTable.tsx`:
  - Updated `contractInfo` to use `getContract` with parameters `moduleAddress`, `chain`, and `client`.

- In `hooks.ts`:
  - Replaced `getBytecode` with `resolveImplementation` to fetch bytecode.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-24 02:45:39 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b80b61b0a6 Bump react-native-quick-crypto from 0.7.4 to 0.7.5 (#4775)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-24 14:41:05 +12:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d37e3fe6e3 Bump knip from 5.30.4 to 5.30.5 (#4773)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-23 14:13:22 -07:00
jnsdls 3b91dad963 Remove "push" script and task (#4762)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on modifying the `turbo.json` and `package.json` configuration files, specifically removing certain caching options and adjusting command scripts related to the build process.

### Detailed summary
- In `turbo.json`, removed the `push` configuration and its `cache` and `dependsOn` settings.
- In `package.json`, removed the `push` script that executed `turbo run push --filter=./packages/*`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-23 19:41:42 +00:00
347 changed files with 2919 additions and 2676 deletions
+4
View File
@@ -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.',
+2 -3
View File
@@ -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 };
@@ -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>
)}
@@ -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>
@@ -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>
@@ -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)}`);
@@ -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} />
)}
@@ -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>
);
}
@@ -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>
);
}
@@ -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>
@@ -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,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,
}),
},
);
@@ -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>
)}
@@ -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"
+14 -30
View File
@@ -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),
@@ -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"
@@ -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"
@@ -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:&lt;port&gt;
{"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/&lt;slug&gt;/...
{"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>
);
};
@@ -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"
@@ -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}>
@@ -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
@@ -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
@@ -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"
@@ -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>
@@ -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(", ")}
@@ -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&apos;re excited to host the
This February, we&apos;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>&nbsp;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>
+25 -37
View File
@@ -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&apos;ve sent a 6 letter confirmation code to
We&apos;ve sent a 6 letter confirmation code to{" "}
<strong>{email}</strong>. Copy the code and paste it below.
</>
) : (
<>
We&apos;ve linked
<strong>{shortenString(user?.address ?? "")}</strong> wallet to
We&apos;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&apos;ve noticed that there is another account associated with
<strong>{email}</strong>. Would you like to link your wallet
We&apos;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