Redesign and expose styling and theming (#25)

This commit is contained in:
philippe-ftx 2021-05-26 18:47:53 +02:00 committed by GitHub
parent 99a49ab334
commit 004938274b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 342 additions and 177 deletions

View File

@ -6,6 +6,7 @@
"homepage": "https://github.com/project-serum/swap-ui", "homepage": "https://github.com/project-serum/swap-ui",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@fontsource/roboto": "^4.3.0",
"@project-serum/serum": "^0.13.34", "@project-serum/serum": "^0.13.34",
"@project-serum/swap": "^0.1.0-alpha.14", "@project-serum/swap": "^0.1.0-alpha.14",
"@solana/spl-token": "^0.1.4" "@solana/spl-token": "^0.1.4"

View File

@ -13,24 +13,18 @@ import { useSwapContext, useSwapFair } from "../context/Swap";
import { useMint } from "../context/Token"; import { useMint } from "../context/Token";
import { useRoute, useMarketName, useBbo } from "../context/Dex"; import { useRoute, useMarketName, useBbo } from "../context/Dex";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles(() => ({
infoLabel: { infoLabel: {
marginTop: "10px", marginTop: "20px",
marginBottom: "10px", marginBottom: "20px",
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "flex-end",
marginLeft: "5px", alignItems: "center",
marginRight: "5px",
},
fairPriceLabel: {
marginRight: "10px",
display: "flex",
justifyContent: "center",
flexDirection: "column",
color: theme.palette.text.secondary,
}, },
infoButton: { infoButton: {
marginLeft: "5px",
padding: 0, padding: 0,
fontSize: "14px",
}, },
})); }));
@ -47,17 +41,14 @@ export function InfoLabel() {
return ( return (
<div className={styles.infoLabel}> <div className={styles.infoLabel}>
<Typography color="textSecondary"></Typography> <Typography color="textSecondary" style={{ fontSize: "14px" }}>
<div style={{ display: "flex" }}> {fair !== undefined && toTokenInfo && fromTokenInfo
<div className={styles.fairPriceLabel}> ? `1 ${toTokenInfo.symbol} = ${fair.toFixed(
{fair !== undefined && toTokenInfo && fromTokenInfo fromMintInfo?.decimals
? `1 ${toTokenInfo.symbol} = ${fair.toFixed( )} ${fromTokenInfo.symbol}`
fromMintInfo?.decimals : `-`}
)} ${fromTokenInfo.symbol}` </Typography>
: `-`} <InfoButton />
</div>
<InfoButton />
</div>
</div> </div>
); );
} }
@ -74,7 +65,7 @@ function InfoButton() {
{...bindTrigger(popupState)} {...bindTrigger(popupState)}
className={styles.infoButton} className={styles.infoButton}
> >
<Info /> <Info fontSize="small" />
</IconButton> </IconButton>
<Popover <Popover
{...bindPopover(popupState)} {...bindPopover(popupState)}

View File

@ -28,8 +28,8 @@ import { useMint, useOwnedTokenAccount } from "../context/Token";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
table: {}, table: {},
closeAccountSwitchLabel: { closeAccount: {
color: theme.palette.text.secondary, color: theme.palette.error.main,
}, },
})); }));
@ -40,6 +40,8 @@ export default function OpenOrdersDialog({
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
}) { }) {
const styles = useStyles();
return ( return (
<Dialog <Dialog
maxWidth="lg" maxWidth="lg"
@ -51,30 +53,24 @@ export default function OpenOrdersDialog({
}, },
}} }}
> >
<div> <div
<div style={{
display: "flex",
justifyContent: "flex-end",
}}
>
<IconButton
onClick={onClose}
style={{ style={{
height: "24px", padding: 10,
display: "flex",
justifyContent: "space-between",
}} }}
> >
<IconButton <Close />
onClick={onClose} </IconButton>
style={{
padding: 0,
position: "absolute",
right: "8px",
top: "8px",
}}
>
<Close />
</IconButton>
</div>
<DialogContent style={{ paddingTop: 0 }}>
<OpenOrdersAccounts />
</DialogContent>
</div> </div>
<DialogContent style={{ paddingTop: 0 }}>
<OpenOrdersAccounts />
</DialogContent>
</Dialog> </Dialog>
); );
} }
@ -126,6 +122,8 @@ function OpenOrdersRow({
market: PublicKey; market: PublicKey;
openOrders: Array<OpenOrders>; openOrders: Array<OpenOrders>;
}) { }) {
const styles = useStyles();
const [ooAccount, setOoAccount] = useState(openOrders[0]); const [ooAccount, setOoAccount] = useState(openOrders[0]);
const { swapClient } = useDexContext(); const { swapClient } = useDexContext();
const marketClient = useMarket(market); const marketClient = useMarket(market);
@ -235,9 +233,9 @@ function OpenOrdersRow({
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="center">
<Button <Button
color="secondary"
disabled={closeDisabled} disabled={closeDisabled}
onClick={closeOpenOrders} onClick={closeOpenOrders}
className={styles.closeAccount}
> >
Close Close
</Button> </Button>

View File

@ -11,7 +11,6 @@ import {
FormControlLabel, FormControlLabel,
FormGroup, FormGroup,
} from "@material-ui/core"; } from "@material-ui/core";
import { ToggleButton } from "@material-ui/lab";
import { SettingsOutlined as Settings } from "@material-ui/icons"; import { SettingsOutlined as Settings } from "@material-ui/icons";
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state"; import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
import { useSwapContext, useSwapFair } from "../context/Swap"; import { useSwapContext, useSwapFair } from "../context/Swap";
@ -25,10 +24,27 @@ const useStyles = makeStyles((theme) => ({
table: {}, table: {},
settingsButton: { settingsButton: {
padding: 0, padding: 0,
color: theme.palette.primary.main,
}, },
closeAccountSwitchLabel: { closeAccountSwitchLabel: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
}, },
fairAutoSelected: {
backgroundColor: theme.palette.primary.main,
padding: "3px 5px",
borderRadius: "10px",
color: theme.palette.primary.contrastText,
fontWeight: 700,
},
fairAuto: {
backgroundColor:
theme.palette.type === "dark"
? theme.palette.secondary.light
: theme.palette.secondary.main,
padding: "3px 5px",
borderRadius: "10px",
boxShadow: "none",
},
})); }));
export function SettingsButton() { export function SettingsButton() {
@ -56,7 +72,12 @@ export function SettingsButton() {
vertical: "top", vertical: "top",
horizontal: "right", horizontal: "right",
}} }}
PaperProps={{ style: { borderRadius: "10px" } }} PaperProps={{
style: {
borderRadius: "10px",
boxShadow: "0px 0px 30px 5px rgba(0,0,0,0.075)",
},
}}
> >
<SettingsDetails /> <SettingsDetails />
</Popover> </Popover>
@ -68,6 +89,8 @@ export function SettingsButton() {
} }
function SettingsDetails() { function SettingsDetails() {
const styles = useStyles();
const { slippage, setSlippage, fairOverride, setFairOverride } = const { slippage, setSlippage, fairOverride, setFairOverride } =
useSwapContext(); useSwapContext();
const [showSettingsDialog, setShowSettingsDialog] = useState(false); const [showSettingsDialog, setShowSettingsDialog] = useState(false);
@ -80,12 +103,12 @@ function SettingsDetails() {
return ( return (
<div style={{ padding: "15px", width: "305px" }}> <div style={{ padding: "15px", width: "305px" }}>
<Typography color="textSecondary" style={{ fontWeight: "bold" }}> <Typography style={{ fontWeight: "bold" }}>Settings</Typography>
Settings <div>
</Typography> <div style={{ marginTop: "10px" }}>
<div style={{ marginTop: "10px" }}> <Typography color="textSecondary" style={{ fontSize: "12px" }}>
<div> Slippage tolerance
<Typography color="textSecondary">Slippage tolerance</Typography> </Typography>
<TextField <TextField
type="number" type="number"
placeholder="Error tolerance percentage" placeholder="Error tolerance percentage"
@ -101,8 +124,10 @@ function SettingsDetails() {
}} }}
/> />
</div> </div>
<div style={{ marginTop: "5px" }}> <div style={{ marginTop: "10px" }}>
<Typography color="textSecondary">Fair price</Typography> <Typography color="textSecondary" style={{ fontSize: "12px" }}>
Fair price
</Typography>
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<TextField <TextField
type="number" type="number"
@ -118,9 +143,9 @@ function SettingsDetails() {
}} }}
disabled={fairOverride === null} disabled={fairOverride === null}
/> />
<ToggleButton <Button
value="bold" component="div"
selected={fairOverride === null} variant="contained"
onClick={() => { onClick={() => {
if (fair === undefined) { if (fair === undefined) {
console.error("Fair is undefined"); console.error("Fair is undefined");
@ -132,27 +157,22 @@ function SettingsDetails() {
setFairOverride(null); setFairOverride(null);
} }
}} }}
style={{ className={
paddingTop: "3px", fairOverride === null
paddingBottom: "3px", ? styles.fairAutoSelected
paddingLeft: "5px", : styles.fairAuto
paddingRight: "5px", }
borderRadius: "20px",
}}
> >
Auto Auto
</ToggleButton> </Button>
</div> </div>
</div> </div>
<div style={{ marginTop: "5px" }}> <div style={{ margin: "10px 0px" }}>
<CloseNewAccountsSwitch /> <CloseNewAccountsSwitch />
</div> </div>
<Button <Button
style={{ variant="contained"
width: "100%", fullWidth
marginTop: "10px",
background: "#e0e0e0",
}}
disabled={swapClient.program.provider.wallet.publicKey === null} disabled={swapClient.program.provider.wallet.publicKey === null}
onClick={() => setShowSettingsDialog(true)} onClick={() => setShowSettingsDialog(true)}
> >

View File

@ -5,11 +5,11 @@ import {
makeStyles, makeStyles,
Card, Card,
Button, Button,
Paper,
Typography, Typography,
TextField, TextField,
useTheme,
} from "@material-ui/core"; } from "@material-ui/core";
import { ExpandMore } from "@material-ui/icons"; import { ExpandMore, ImportExportRounded } from "@material-ui/icons";
import { useSwapContext, useSwapFair } from "../context/Swap"; import { useSwapContext, useSwapFair } from "../context/Swap";
import { import {
useDexContext, useDexContext,
@ -25,16 +25,12 @@ import TokenDialog from "./TokenDialog";
import { SettingsButton } from "./Settings"; import { SettingsButton } from "./Settings";
import { InfoLabel } from "./Info"; import { InfoLabel } from "./Info";
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme) => ({
card: { card: {
width: "450px", width: "450px",
borderRadius: "10px", borderRadius: "16px",
border: "solid 1pt #e0e0e0", boxShadow: "0px 0px 30px 5px rgba(0,0,0,0.075)",
}, padding: "16px",
cardContent: {
marginLeft: "6px",
marginRight: "6px",
marginBottom: "6px",
}, },
tab: { tab: {
width: "50%", width: "50%",
@ -44,30 +40,78 @@ const useStyles = makeStyles(() => ({
}, },
swapButton: { swapButton: {
width: "100%", width: "100%",
borderRadius: "15px", borderRadius: "10px",
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
fontSize: 16,
fontWeight: 700,
padding: "10px",
}, },
swapToFromButton: { swapToFromButton: {
display: "block", display: "block",
marginLeft: "auto", margin: "10px auto 10px auto",
marginRight: "auto", cursor: "pointer",
},
amountInput: {
fontSize: 22,
fontWeight: 600,
},
input: {
textAlign: "right",
},
swapTokenFormContainer: {
borderRadius: "10px",
boxShadow: "0px 0px 15px 2px rgba(33,150,243,0.1)",
display: "flex",
justifyContent: "space-between",
padding: "10px",
},
swapTokenSelectorContainer: {
marginLeft: "5px",
display: "flex",
flexDirection: "column",
},
balanceContainer: {
display: "flex",
alignItems: "center",
fontSize: "14px",
},
maxButton: {
marginLeft: 10,
color: theme.palette.primary.main,
fontWeight: 700,
fontSize: "12px",
cursor: "pointer",
},
tokenButton: {
display: "flex",
alignItems: "center",
cursor: "pointer",
marginBottom: "10px",
}, },
})); }));
export default function SwapCard({ style }: { style?: any }) { export default function SwapCard({
containerStyle,
contentStyle,
swapTokenContainerStyle,
}: {
containerStyle?: any;
contentStyle?: any;
swapTokenContainerStyle?: any;
}) {
const styles = useStyles(); const styles = useStyles();
return ( return (
<div style={style}> <Card className={styles.card} style={containerStyle}>
<Card className={styles.card}> <SwapHeader />
<SwapHeader /> <div style={contentStyle}>
<div className={styles.cardContent}> <SwapFromForm style={swapTokenContainerStyle} />
<SwapFromForm /> <ArrowButton />
<ArrowButton /> <SwapToForm style={swapTokenContainerStyle} />
<SwapToForm /> <InfoLabel />
<InfoLabel /> <SwapButton />
<SwapButton /> </div>
</div> </Card>
</Card>
</div>
); );
} }
@ -77,18 +121,17 @@ function SwapHeader() {
style={{ style={{
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
margin: "8px", marginBottom: "20px",
}} }}
> >
<Typography <Typography
style={{ style={{
fontWeight: "bold", fontSize: 18,
display: "flex", fontWeight: 700,
justifyContent: "center", fontFamily: "Roboto Condensed",
flexDirection: "column",
}} }}
> >
Swap SWAP
</Typography> </Typography>
<SettingsButton /> <SettingsButton />
</div> </div>
@ -97,18 +140,24 @@ function SwapHeader() {
export function ArrowButton() { export function ArrowButton() {
const styles = useStyles(); const styles = useStyles();
const theme = useTheme();
const { swapToFromMints } = useSwapContext(); const { swapToFromMints } = useSwapContext();
return ( return (
<Button className={styles.swapToFromButton} onClick={swapToFromMints}> <ImportExportRounded
className={styles.swapToFromButton}
</Button> fontSize="large"
htmlColor={theme.palette.primary.main}
onClick={swapToFromMints}
/>
); );
} }
function SwapFromForm() { function SwapFromForm({ style }: { style?: any }) {
const { fromMint, setFromMint, fromAmount, setFromAmount } = useSwapContext(); const { fromMint, setFromMint, fromAmount, setFromAmount } = useSwapContext();
return ( return (
<SwapTokenForm <SwapTokenForm
from
style={style}
mint={fromMint} mint={fromMint}
setMint={setFromMint} setMint={setFromMint}
amount={fromAmount} amount={fromAmount}
@ -117,10 +166,12 @@ function SwapFromForm() {
); );
} }
function SwapToForm() { function SwapToForm({ style }: { style?: any }) {
const { toMint, setToMint, toAmount, setToAmount } = useSwapContext(); const { toMint, setToMint, toAmount, setToAmount } = useSwapContext();
return ( return (
<SwapTokenForm <SwapTokenForm
from={false}
style={style}
mint={toMint} mint={toMint}
setMint={setToMint} setMint={setToMint}
amount={toAmount} amount={toAmount}
@ -130,57 +181,75 @@ function SwapToForm() {
} }
function SwapTokenForm({ function SwapTokenForm({
from,
style,
mint, mint,
setMint, setMint,
amount, amount,
setAmount, setAmount,
}: { }: {
from: boolean;
style?: any;
mint: PublicKey; mint: PublicKey;
setMint: (m: PublicKey) => void; setMint: (m: PublicKey) => void;
amount: number; amount: number;
setAmount: (a: number) => void; setAmount: (a: number) => void;
}) { }) {
const styles = useStyles();
const [showTokenDialog, setShowTokenDialog] = useState(false); const [showTokenDialog, setShowTokenDialog] = useState(false);
const tokenAccount = useOwnedTokenAccount(mint); const tokenAccount = useOwnedTokenAccount(mint);
const mintAccount = useMint(mint); const mintAccount = useMint(mint);
const balance =
tokenAccount &&
mintAccount &&
tokenAccount.account.amount.toNumber() / 10 ** mintAccount.decimals;
const formattedAmount =
mintAccount && amount
? amount.toLocaleString("fullwide", {
maximumFractionDigits: mintAccount.decimals,
useGrouping: false,
})
: amount;
return ( return (
<Paper elevation={0} variant="outlined" style={{ borderRadius: "10px" }}> <div className={styles.swapTokenFormContainer} style={style}>
<div <div className={styles.swapTokenSelectorContainer}>
style={{
height: "50px",
display: "flex",
justifyContent: "space-between",
}}
>
<TokenButton mint={mint} onClick={() => setShowTokenDialog(true)} /> <TokenButton mint={mint} onClick={() => setShowTokenDialog(true)} />
<TextField <Typography color="textSecondary" className={styles.balanceContainer}>
type="number"
value={amount}
onChange={(e) => setAmount(parseFloat(e.target.value))}
style={{
display: "flex",
justifyContent: "center",
flexDirection: "column",
}}
/>
</div>
<div style={{ marginLeft: "10px", height: "30px" }}>
<Typography color="textSecondary" style={{ fontSize: "14px" }}>
{tokenAccount && mintAccount {tokenAccount && mintAccount
? `Balance: ${( ? `Balance: ${balance?.toFixed(mintAccount.decimals)}`
tokenAccount.account.amount.toNumber() /
10 ** mintAccount.decimals
).toFixed(mintAccount.decimals)}`
: `-`} : `-`}
{from && !!balance ? (
<span
className={styles.maxButton}
onClick={() => setAmount(balance)}
>
MAX
</span>
) : null}
</Typography> </Typography>
</div> </div>
<TextField
type="number"
value={formattedAmount}
onChange={(e) => setAmount(parseFloat(e.target.value))}
InputProps={{
disableUnderline: true,
classes: {
root: styles.amountInput,
input: styles.input,
},
}}
/>
<TokenDialog <TokenDialog
setMint={setMint} setMint={setMint}
open={showTokenDialog} open={showTokenDialog}
onClose={() => setShowTokenDialog(false)} onClose={() => setShowTokenDialog(false)}
/> />
</Paper> </div>
); );
} }
@ -191,12 +260,14 @@ function TokenButton({
mint: PublicKey; mint: PublicKey;
onClick: () => void; onClick: () => void;
}) { }) {
const styles = useStyles();
return ( return (
<Button onClick={onClick} style={{ minWidth: "116px" }}> <div onClick={onClick} className={styles.tokenButton}>
<TokenIcon mint={mint} style={{ width: "25px", borderRadius: "13px" }} /> <TokenIcon mint={mint} style={{ width: "30px" }} />
<TokenName mint={mint} /> <TokenName mint={mint} style={{ fontSize: 14, fontWeight: 700 }} />
<ExpandMore /> <ExpandMore />
</Button> </div>
); );
} }
@ -220,11 +291,13 @@ export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
); );
} }
function TokenName({ mint }: { mint: PublicKey }) { function TokenName({ mint, style }: { mint: PublicKey; style: any }) {
const tokenMap = useTokenMap(); const tokenMap = useTokenMap();
let tokenInfo = tokenMap.get(mint.toString()); let tokenInfo = tokenMap.get(mint.toString());
return ( return (
<Typography style={{ marginLeft: "5px" }}>{tokenInfo?.symbol}</Typography> <Typography style={{ marginLeft: "10px", marginRight: "5px", ...style }}>
{tokenInfo?.symbol}
</Typography>
); );
} }

View File

@ -17,20 +17,25 @@ import {
import { TokenIcon } from "./Swap"; import { TokenIcon } from "./Swap";
import { useSwappableTokens } from "../context/TokenList"; import { useSwappableTokens } from "../context/TokenList";
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme) => ({
dialogContent: { dialogContent: {
paddingTop: 0, padding: 0,
paddingBottom: 0,
}, },
textField: { textField: {
width: "100%",
border: "solid 1pt #ccc",
borderRadius: "10px",
marginBottom: "8px", marginBottom: "8px",
}, },
tab: { tab: {
minWidth: "134px", minWidth: "134px",
}, },
tabSelected: {
color: theme.palette.primary.contrastText,
fontWeight: 700,
backgroundColor: theme.palette.primary.main,
borderRadius: "10px",
},
tabIndicator: {
opacity: 0,
},
})); }));
export default function TokenDialog({ export default function TokenDialog({
@ -83,11 +88,9 @@ export default function TokenDialog({
className={styles.textField} className={styles.textField}
placeholder={"Search name"} placeholder={"Search name"}
value={tokenFilter} value={tokenFilter}
fullWidth
variant="outlined"
onChange={(e) => setTokenFilter(e.target.value)} onChange={(e) => setTokenFilter(e.target.value)}
InputProps={{
disableUnderline: true,
style: { padding: "10px" },
}}
/> />
</DialogTitle> </DialogTitle>
<DialogContent className={styles.dialogContent} dividers={true}> <DialogContent className={styles.dialogContent} dividers={true}>
@ -105,10 +108,31 @@ export default function TokenDialog({
</List> </List>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Tabs value={tabSelection} onChange={(e, v) => setTabSelection(v)}> <Tabs
<Tab value={0} className={styles.tab} label="Main" /> value={tabSelection}
<Tab value={1} className={styles.tab} label="Wormhole" /> onChange={(e, v) => setTabSelection(v)}
<Tab value={2} className={styles.tab} label="Sollet" /> classes={{
indicator: styles.tabIndicator,
}}
>
<Tab
value={0}
className={styles.tab}
classes={{ selected: styles.tabSelected }}
label="Main"
/>
<Tab
value={1}
className={styles.tab}
classes={{ selected: styles.tabSelected }}
label="Wormhole"
/>
<Tab
value={2}
className={styles.tab}
classes={{ selected: styles.tabSelected }}
label="Sollet"
/>
</Tabs> </Tabs>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
@ -124,7 +148,11 @@ function TokenListItem({
}) { }) {
const mint = new PublicKey(tokenInfo.address); const mint = new PublicKey(tokenInfo.address);
return ( return (
<ListItem button onClick={() => onClick(mint)}> <ListItem
button
onClick={() => onClick(mint)}
style={{ padding: "10px 20px" }}
>
<TokenIcon mint={mint} style={{ width: "30px", borderRadius: "15px" }} /> <TokenIcon mint={mint} style={{ width: "30px", borderRadius: "15px" }} />
<TokenName tokenInfo={tokenInfo} /> <TokenName tokenInfo={tokenInfo} />
</ListItem> </ListItem>

1
src/index.css Normal file
View File

@ -0,0 +1 @@
@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;700&display=swap");

View File

@ -1,3 +1,5 @@
import "@fontsource/roboto";
import "./index.css";
import { ReactElement } from "react"; import { ReactElement } from "react";
import { PublicKey } from "@solana/web3.js"; import { PublicKey } from "@solana/web3.js";
import { TokenListContainer } from "@solana/spl-token-registry"; import { TokenListContainer } from "@solana/spl-token-registry";
@ -8,6 +10,11 @@ import { DexContextProvider } from "./context/Dex";
import { TokenListContextProvider } from "./context/TokenList"; import { TokenListContextProvider } from "./context/TokenList";
import { TokenContextProvider } from "./context/Token"; import { TokenContextProvider } from "./context/Token";
import SwapCard from "./components/Swap"; import SwapCard from "./components/Swap";
import {
createMuiTheme,
ThemeOptions,
ThemeProvider,
} from "@material-ui/core/styles";
/** /**
* A`Swap` component that can be embedded into applications. To use, * A`Swap` component that can be embedded into applications. To use,
@ -26,7 +33,10 @@ import SwapCard from "./components/Swap";
*/ */
export function Swap(props: SwapProps): ReactElement { export function Swap(props: SwapProps): ReactElement {
const { const {
style, containerStyle,
contentStyle,
swapTokenContainerStyle,
materialTheme,
provider, provider,
tokenList, tokenList,
fromMint, fromMint,
@ -36,22 +46,45 @@ export function Swap(props: SwapProps): ReactElement {
referral, referral,
} = props; } = props;
const swapClient = new SwapClient(provider, tokenList); const swapClient = new SwapClient(provider, tokenList);
const theme = createMuiTheme(
materialTheme || {
palette: {
primary: {
main: "#2196F3",
contrastText: "#FFFFFF",
},
secondary: {
main: "#E0E0E0",
light: "#595959",
},
error: {
main: "#ff6b6b",
},
},
}
);
return ( return (
<TokenListContextProvider tokenList={tokenList}> <ThemeProvider theme={theme}>
<TokenContextProvider provider={provider}> <TokenListContextProvider tokenList={tokenList}>
<DexContextProvider swapClient={swapClient}> <TokenContextProvider provider={provider}>
<SwapContextProvider <DexContextProvider swapClient={swapClient}>
fromMint={fromMint} <SwapContextProvider
toMint={toMint} fromMint={fromMint}
fromAmount={fromAmount} toMint={toMint}
toAmount={toAmount} fromAmount={fromAmount}
referral={referral} toAmount={toAmount}
> referral={referral}
<SwapCard style={style} /> >
</SwapContextProvider> <SwapCard
</DexContextProvider> containerStyle={containerStyle}
</TokenContextProvider> contentStyle={contentStyle}
</TokenListContextProvider> swapTokenContainerStyle={swapTokenContainerStyle}
/>
</SwapContextProvider>
</DexContextProvider>
</TokenContextProvider>
</TokenListContextProvider>
</ThemeProvider>
); );
} }
@ -101,9 +134,24 @@ export type SwapProps = {
toAmount?: number; toAmount?: number;
/** /**
* Style properties to pass through to the component. * Provide custom material-ui theme.
*/ */
style?: any; materialTheme?: ThemeOptions;
/**
* Styling properties for the main container.
*/
containerStyle?: any;
/**
* Styling properties for the content container.
*/
contentStyle?: any;
/**
* Styling properties for the from and to token containers.
*/
swapTokenContainerStyle?: any;
}; };
export default Swap; export default Swap;

View File

@ -1255,6 +1255,11 @@
minimatch "^3.0.4" minimatch "^3.0.4"
strip-json-comments "^3.1.1" strip-json-comments "^3.1.1"
"@fontsource/roboto@^4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@fontsource/roboto/-/roboto-4.3.0.tgz#00f1cceca43eff85bb0e1d424311751ee41f6aa6"
integrity sha512-WeFWCWYutLWyEtRmBhn+bLbW4/km0l+HhTpR8wWDxJLiGiMOhVLO/Z0q5w6l20ZOkWnf6Z1rN3o3W2HjvYN6Rg==
"@hapi/address@2.x.x": "@hapi/address@2.x.x":
version "2.1.4" version "2.1.4"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"