Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nine-otters-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---

SwapWidget UI improvements
7 changes: 4 additions & 3 deletions apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,13 @@ export function BuyAndSwapEmbed(props: {
theme={themeObj}
className="!rounded-2xl !border-none !w-full"
prefill={{
sellToken: {
// buy this token by default
buyToken: {
chainId: props.chain.id,
tokenAddress: props.tokenAddress,
},
// only set `buyToken` as "Native token" if `sellToken` is not a "native token" already
buyToken: props.tokenAddress
// sell the native token by default (but if buytoken is a native token, don't set)
sellToken: props.tokenAddress
? {
chainId: props.chain.id,
}
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/src/@/utils/sdk-component-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export function getSDKTheme(theme: "light" | "dark"): Theme {
selectedTextBg: "hsl(var(--inverted))",
selectedTextColor: "hsl(var(--inverted-foreground))",
separatorLine: "hsl(var(--border))",
skeletonBg: "hsl(var(--muted))",
skeletonBg: "hsl(var(--secondary-foreground)/15%)",
success: "hsl(var(--success-text))",
tertiaryBg: "hsl(var(--muted)/50%)",
tertiaryBg: "hsl(var(--muted)/30%)",
tooltipBg: "hsl(var(--popover))",
tooltipText: "hsl(var(--popover-foreground))",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export function RightSection(props: { options: SwapWidgetPlaygroundOptions }) {
prefill={props.options.prefill}
currency={props.options.currency}
showThirdwebBranding={props.options.showThirdwebBranding}
key={JSON.stringify(props.options)}
key={JSON.stringify({
prefill: props.options.prefill,
})}
persistTokenSelections={false}
/>
)}
Expand Down
6 changes: 6 additions & 0 deletions apps/portal/src/app/bridge/swap/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
TypeScriptIcon,
} from "@/icons";
import SwapWidgetImage from "./swap-dark.png";
import SwapWidgetImageLight from "./swap-light.png";

export const metadata = createMetadata({
image: {
Expand Down Expand Up @@ -55,7 +56,12 @@ function Example() {
}
```

<div className='dark-only'>
<DocImage src={SwapWidgetImage} />
</div>
<div className='light-only'>
<DocImage src={SwapWidgetImageLight} />
</div>

## Live Playground

Expand Down
Binary file modified apps/portal/src/app/bridge/swap/swap-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/thirdweb/src/react/core/design-system/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export const iconSize = {
"4xl": "128",
lg: "32",
md: "24",
"sm+": "20",
sm: "16",
xl: "48",
xs: "12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export function SearchInput(props: {
variant="outline"
placeholder={props.placeholder}
value={props.value}
sm
style={{
paddingLeft: "44px",
}}
Expand Down
106 changes: 61 additions & 45 deletions packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ export type SwapWidgetProps = {
* @default true
*/
persistTokenSelections?: boolean;
/**
* Called when the user disconnects the active wallet
*/
onDisconnect?: () => void;
};

/**
Expand Down Expand Up @@ -325,46 +329,11 @@ function SwapWidgetContent(props: SwapWidgetProps) {
});

const [buyToken, setBuyToken] = useState<TokenSelection | undefined>(() => {
if (props.prefill?.buyToken) {
return {
tokenAddress:
props.prefill.buyToken.tokenAddress ||
getAddress(NATIVE_TOKEN_ADDRESS),
chainId: props.prefill.buyToken.chainId,
};
}

if (!isPersistEnabled) {
return undefined;
}

const lastUsedBuyToken = getLastUsedTokens()?.buyToken;

// the token that will be set as initial value of sell token
const sellToken = getInitialSellToken(
props.prefill,
getLastUsedTokens()?.sellToken,
);

// if both tokens are same, ignore "buyToken", keep "sellToken"
if (
lastUsedBuyToken &&
sellToken &&
lastUsedBuyToken.tokenAddress.toLowerCase() ===
sellToken.tokenAddress.toLowerCase() &&
lastUsedBuyToken.chainId === sellToken.chainId
) {
return undefined;
}

return lastUsedBuyToken;
return getInitialTokens(props.prefill, isPersistEnabled).buyToken;
});

const [sellToken, setSellToken] = useState<TokenSelection | undefined>(() => {
return getInitialSellToken(
props.prefill,
isPersistEnabled ? getLastUsedTokens()?.sellToken : undefined,
);
return getInitialTokens(props.prefill, isPersistEnabled).sellToken;
});

// persist selections to localStorage whenever they change
Expand Down Expand Up @@ -394,6 +363,7 @@ function SwapWidgetContent(props: SwapWidgetProps) {
if (screen.id === "1:swap-ui" || !activeWalletInfo) {
return (
<SwapUI
onDisconnect={props.onDisconnect}
showThirdwebBranding={
props.showThirdwebBranding === undefined
? true
Expand Down Expand Up @@ -533,17 +503,63 @@ function SwapWidgetContent(props: SwapWidgetProps) {
return null;
}

function getInitialSellToken(
function getInitialTokens(
prefill: SwapWidgetProps["prefill"],
lastUsedSellToken: TokenSelection | undefined,
) {
if (prefill?.sellToken) {
isPersistEnabled: boolean,
): {
buyToken: TokenSelection | undefined;
sellToken: TokenSelection | undefined;
} {
const lastUsedTokens = isPersistEnabled ? getLastUsedTokens() : undefined;
const buyToken = prefill?.buyToken
? {
tokenAddress:
prefill.buyToken.tokenAddress || getAddress(NATIVE_TOKEN_ADDRESS),
chainId: prefill.buyToken.chainId,
}
: lastUsedTokens?.buyToken;

const sellToken = prefill?.sellToken
? {
tokenAddress:
prefill.sellToken.tokenAddress || getAddress(NATIVE_TOKEN_ADDRESS),
chainId: prefill.sellToken.chainId,
}
: lastUsedTokens?.sellToken;

// if both tokens are same
if (
buyToken &&
sellToken &&
buyToken.tokenAddress?.toLowerCase() ===
sellToken.tokenAddress?.toLowerCase() &&
buyToken.chainId === sellToken.chainId
) {
// if sell token prefill is specified, ignore buy token
if (prefill?.sellToken) {
return {
buyToken: undefined,
sellToken: sellToken,
};
}

// if buy token prefill is specified, ignore sell token
if (prefill?.buyToken) {
return {
buyToken: buyToken,
sellToken: undefined,
};
}

// if none of the two are specified via prefill, keep buy token
return {
tokenAddress:
prefill.sellToken.tokenAddress || getAddress(NATIVE_TOKEN_ADDRESS),
chainId: prefill.sellToken.chainId,
buyToken: buyToken,
sellToken: undefined,
};
}

return lastUsedSellToken;
return {
buyToken: buyToken,
sellToken: sellToken,
};
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ThirdwebClient } from "../../../../../client/client.js";
import {
fontSize,
iconSize,
radius,
spacing,
} from "../../../../core/design-system/index.js";
import { Container, Line, ModalHeader } from "../../components/basic.js";
Expand All @@ -21,6 +22,7 @@ type SelectBuyTokenProps = {
client: ThirdwebClient;
onSelectChain: (chain: BridgeChain) => void;
selectedChain: BridgeChain | undefined;
isMobile: boolean;
};

/**
Expand Down Expand Up @@ -56,11 +58,15 @@ export function SelectBridgeChainUI(
});

return (
<div>
<Container px="md" py="md+">
<ModalHeader onBack={props.onBack} title="Select Chain" />
</Container>
<Line />
<Container fullHeight flex="column">
{props.isMobile && (
<>
<Container px="md" py="md+">
<ModalHeader onBack={props.onBack} title="Select Chain" />
</Container>
<Line />
</>
)}

<Spacer y="md" />

Expand All @@ -79,10 +85,12 @@ export function SelectBridgeChainUI(
<Spacer y="sm" />

<Container
expand
px="md"
gap={props.isMobile ? undefined : "xxs"}
flex="column"
style={{
height: "400px",
maxHeight: props.isMobile ? "400px" : "none",
overflowY: "auto",
scrollbarWidth: "none",
paddingBottom: spacing.md,
Expand All @@ -95,6 +103,7 @@ export function SelectBridgeChainUI(
client={props.client}
onClick={() => props.onSelectChain(chain)}
isSelected={chain.chainId === props.selectedChain?.chainId}
isMobile={props.isMobile}
/>
))}

Expand All @@ -119,7 +128,7 @@ export function SelectBridgeChainUI(
</div>
)}
</Container>
</div>
</Container>
);
}

Expand All @@ -144,6 +153,7 @@ function ChainButton(props: {
client: ThirdwebClient;
onClick: () => void;
isSelected: boolean;
isMobile: boolean;
}) {
return (
<Button
Expand All @@ -152,18 +162,21 @@ function ChainButton(props: {
style={{
justifyContent: "flex-start",
fontWeight: 500,
fontSize: fontSize.md,
fontSize: props.isMobile ? fontSize.md : fontSize.sm,
border: "1px solid transparent",
padding: `${spacing.sm} ${spacing.sm}`,
padding: !props.isMobile ? `${spacing.xs} ${spacing.xs}` : undefined,
}}
gap="sm"
onClick={props.onClick}
gap="sm"
>
<Img
src={props.chain.icon}
client={props.client}
width={iconSize.lg}
height={iconSize.lg}
width={props.isMobile ? iconSize.lg : iconSize.md}
height={props.isMobile ? iconSize.lg : iconSize.md}
style={{
borderRadius: radius.full,
}}
/>
{cleanedChainName(props.chain.name)}
</Button>
Expand Down
Loading
Loading