Skip to content

Commit 8b945dd

Browse files
committed
[MNY-189] SDK: SwapWidget UI improvements
1 parent fddb791 commit 8b945dd

File tree

18 files changed

+1001
-557
lines changed

18 files changed

+1001
-557
lines changed

.changeset/nine-otters-pay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
SwapWidget UI improvements

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,13 @@ export function BuyAndSwapEmbed(props: {
107107
theme={themeObj}
108108
className="!rounded-2xl !border-none !w-full"
109109
prefill={{
110-
sellToken: {
110+
// buy this token by default
111+
buyToken: {
111112
chainId: props.chain.id,
112113
tokenAddress: props.tokenAddress,
113114
},
114-
// only set `buyToken` as "Native token" if `sellToken` is not a "native token" already
115-
buyToken: props.tokenAddress
115+
// sell the native token by default (but if buytoken is a native token, don't set)
116+
sellToken: props.tokenAddress
116117
? {
117118
chainId: props.chain.id,
118119
}

apps/dashboard/src/@/utils/sdk-component-theme.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ export function getSDKTheme(theme: "light" | "dark"): Theme {
3131
selectedTextBg: "hsl(var(--inverted))",
3232
selectedTextColor: "hsl(var(--inverted-foreground))",
3333
separatorLine: "hsl(var(--border))",
34-
skeletonBg: "hsl(var(--muted))",
34+
skeletonBg: "hsl(var(--secondary-foreground)/15%)",
3535
success: "hsl(var(--success-text))",
36-
tertiaryBg: "hsl(var(--muted)/50%)",
36+
tertiaryBg: "hsl(var(--muted)/30%)",
3737
tooltipBg: "hsl(var(--popover))",
3838
tooltipText: "hsl(var(--popover-foreground))",
3939
},

packages/thirdweb/src/react/core/design-system/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ export const iconSize = {
200200
"4xl": "128",
201201
lg: "32",
202202
md: "24",
203+
"sm+": "20",
203204
sm: "16",
204205
xl: "48",
205206
xs: "12",

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export function SearchInput(props: {
3636
variant="outline"
3737
placeholder={props.placeholder}
3838
value={props.value}
39+
sm
3940
style={{
4041
paddingLeft: "44px",
4142
}}

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx

Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ export type SwapWidgetProps = {
162162
* @default true
163163
*/
164164
persistTokenSelections?: boolean;
165+
/**
166+
* Called when the user disconnects the active wallet
167+
*/
168+
onDisconnect?: () => void;
165169
};
166170

167171
/**
@@ -324,46 +328,11 @@ function SwapWidgetContent(props: SwapWidgetProps) {
324328
});
325329

326330
const [buyToken, setBuyToken] = useState<TokenSelection | undefined>(() => {
327-
if (props.prefill?.buyToken) {
328-
return {
329-
tokenAddress:
330-
props.prefill.buyToken.tokenAddress ||
331-
getAddress(NATIVE_TOKEN_ADDRESS),
332-
chainId: props.prefill.buyToken.chainId,
333-
};
334-
}
335-
336-
if (!isPersistEnabled) {
337-
return undefined;
338-
}
339-
340-
const lastUsedBuyToken = getLastUsedTokens()?.buyToken;
341-
342-
// the token that will be set as initial value of sell token
343-
const sellToken = getInitialSellToken(
344-
props.prefill,
345-
getLastUsedTokens()?.sellToken,
346-
);
347-
348-
// if both tokens are same, ignore "buyToken", keep "sellToken"
349-
if (
350-
lastUsedBuyToken &&
351-
sellToken &&
352-
lastUsedBuyToken.tokenAddress.toLowerCase() ===
353-
sellToken.tokenAddress.toLowerCase() &&
354-
lastUsedBuyToken.chainId === sellToken.chainId
355-
) {
356-
return undefined;
357-
}
358-
359-
return lastUsedBuyToken;
331+
return getInitialTokens(props.prefill).buyToken;
360332
});
361333

362334
const [sellToken, setSellToken] = useState<TokenSelection | undefined>(() => {
363-
return getInitialSellToken(
364-
props.prefill,
365-
isPersistEnabled ? getLastUsedTokens()?.sellToken : undefined,
366-
);
335+
return getInitialTokens(props.prefill).sellToken;
367336
});
368337

369338
// persist selections to localStorage whenever they change
@@ -393,6 +362,7 @@ function SwapWidgetContent(props: SwapWidgetProps) {
393362
if (screen.id === "1:swap-ui" || !activeWalletInfo) {
394363
return (
395364
<SwapUI
365+
onDisconnect={props.onDisconnect}
396366
showThirdwebBranding={
397367
props.showThirdwebBranding === undefined
398368
? true
@@ -532,17 +502,60 @@ function SwapWidgetContent(props: SwapWidgetProps) {
532502
return null;
533503
}
534504

535-
function getInitialSellToken(
536-
prefill: SwapWidgetProps["prefill"],
537-
lastUsedSellToken: TokenSelection | undefined,
538-
) {
539-
if (prefill?.sellToken) {
505+
function getInitialTokens(prefill: SwapWidgetProps["prefill"]): {
506+
buyToken: TokenSelection | undefined;
507+
sellToken: TokenSelection | undefined;
508+
} {
509+
const lastUsedTokens = getLastUsedTokens();
510+
const buyToken = prefill?.buyToken
511+
? {
512+
tokenAddress:
513+
prefill.buyToken.tokenAddress || getAddress(NATIVE_TOKEN_ADDRESS),
514+
chainId: prefill.buyToken.chainId,
515+
}
516+
: lastUsedTokens?.buyToken;
517+
518+
const sellToken = prefill?.sellToken
519+
? {
520+
tokenAddress:
521+
prefill.sellToken.tokenAddress || getAddress(NATIVE_TOKEN_ADDRESS),
522+
chainId: prefill.sellToken.chainId,
523+
}
524+
: lastUsedTokens?.sellToken;
525+
526+
// if both tokens are same
527+
if (
528+
buyToken &&
529+
sellToken &&
530+
buyToken.tokenAddress?.toLowerCase() ===
531+
sellToken.tokenAddress?.toLowerCase() &&
532+
buyToken.chainId === sellToken.chainId
533+
) {
534+
// if sell token prefill is specified, ignore buy token
535+
if (prefill?.sellToken) {
536+
return {
537+
buyToken: undefined,
538+
sellToken: sellToken,
539+
};
540+
}
541+
542+
// if buy token prefill is specified, ignore sell token
543+
if (prefill?.buyToken) {
544+
return {
545+
buyToken: buyToken,
546+
sellToken: undefined,
547+
};
548+
}
549+
550+
// if none of the two are specified via prefill, keep buy token
540551
return {
541-
tokenAddress:
542-
prefill.sellToken.tokenAddress || getAddress(NATIVE_TOKEN_ADDRESS),
543-
chainId: prefill.sellToken.chainId,
552+
buyToken: buyToken,
553+
sellToken: undefined,
544554
};
545555
}
546556

547-
return lastUsedSellToken;
557+
return {
558+
buyToken: buyToken,
559+
sellToken: sellToken,
560+
};
548561
}

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/common.tsx

Lines changed: 0 additions & 35 deletions
This file was deleted.

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { ThirdwebClient } from "../../../../../client/client.js";
44
import {
55
fontSize,
66
iconSize,
7+
radius,
78
spacing,
89
} from "../../../../core/design-system/index.js";
910
import { Container, Line, ModalHeader } from "../../components/basic.js";
@@ -21,6 +22,7 @@ type SelectBuyTokenProps = {
2122
client: ThirdwebClient;
2223
onSelectChain: (chain: BridgeChain) => void;
2324
selectedChain: BridgeChain | undefined;
25+
isMobile: boolean;
2426
};
2527

2628
/**
@@ -56,11 +58,15 @@ export function SelectBridgeChainUI(
5658
});
5759

5860
return (
59-
<div>
60-
<Container px="md" py="md+">
61-
<ModalHeader onBack={props.onBack} title="Select Chain" />
62-
</Container>
63-
<Line />
61+
<Container fullHeight flex="column">
62+
{props.isMobile && (
63+
<>
64+
<Container px="md" py="md+">
65+
<ModalHeader onBack={props.onBack} title="Select Chain" />
66+
</Container>
67+
<Line />
68+
</>
69+
)}
6470

6571
<Spacer y="md" />
6672

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

8187
<Container
88+
expand
8289
px="md"
90+
gap={props.isMobile ? undefined : "xxs"}
8391
flex="column"
8492
style={{
85-
height: "400px",
93+
maxHeight: props.isMobile ? "400px" : "none",
8694
overflowY: "auto",
8795
scrollbarWidth: "none",
8896
paddingBottom: spacing.md,
@@ -95,6 +103,7 @@ export function SelectBridgeChainUI(
95103
client={props.client}
96104
onClick={() => props.onSelectChain(chain)}
97105
isSelected={chain.chainId === props.selectedChain?.chainId}
106+
isMobile={props.isMobile}
98107
/>
99108
))}
100109

@@ -119,7 +128,7 @@ export function SelectBridgeChainUI(
119128
</div>
120129
)}
121130
</Container>
122-
</div>
131+
</Container>
123132
);
124133
}
125134

@@ -144,6 +153,7 @@ function ChainButton(props: {
144153
client: ThirdwebClient;
145154
onClick: () => void;
146155
isSelected: boolean;
156+
isMobile: boolean;
147157
}) {
148158
return (
149159
<Button
@@ -152,18 +162,21 @@ function ChainButton(props: {
152162
style={{
153163
justifyContent: "flex-start",
154164
fontWeight: 500,
155-
fontSize: fontSize.md,
165+
fontSize: props.isMobile ? fontSize.md : fontSize.sm,
156166
border: "1px solid transparent",
157-
padding: `${spacing.sm} ${spacing.sm}`,
167+
padding: !props.isMobile ? `${spacing.xs} ${spacing.xs}` : undefined,
158168
}}
159-
gap="sm"
160169
onClick={props.onClick}
170+
gap="sm"
161171
>
162172
<Img
163173
src={props.chain.icon}
164174
client={props.client}
165-
width={iconSize.lg}
166-
height={iconSize.lg}
175+
width={props.isMobile ? iconSize.lg : iconSize.md}
176+
height={props.isMobile ? iconSize.lg : iconSize.md}
177+
style={{
178+
borderRadius: radius.full,
179+
}}
167180
/>
168181
{cleanedChainName(props.chain.name)}
169182
</Button>

0 commit comments

Comments
 (0)