Skip to content

Commit

Permalink
feat(bridge-ui-v2): NFT bridge stepper (#14811)
Browse files Browse the repository at this point in the history
  • Loading branch information
KorbinianK committed Sep 28, 2023
1 parent e8e2f05 commit 90e19fc
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 31 deletions.
85 changes: 66 additions & 19 deletions packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import { chainConfig } from '$chainConfig';
import { FlatAlert } from '$components/Alert';
import ChainSelectorWrapper from '$components/Bridge/ChainSelectorWrapper.svelte';
import { Button } from '$components/Button';
import { Card } from '$components/Card';
import { successToast, warningToast } from '$components/NotificationToast';
import { errorToast, infoToast } from '$components/NotificationToast/NotificationToast.svelte';
import { OnAccount } from '$components/OnAccount';
import { OnNetwork } from '$components/OnNetwork';
import { Step, Stepper } from '$components/Stepper';
import { TokenDropdown } from '$components/TokenDropdown';
import {
type BridgeArgs,
Expand Down Expand Up @@ -41,8 +43,18 @@
import Amount from './Amount.svelte';
import { ProcessingFee } from './ProcessingFee';
import Recipient from './Recipient.svelte';
import { bridgeService, destNetwork, enteredAmount, processingFee, recipientAddress, selectedToken } from './state';
import {
activeBridge,
bridgeService,
destNetwork,
enteredAmount,
processingFee,
recipientAddress,
selectedToken,
} from './state';
import { BridgeTypes, NFTSteps } from './types';
let activeStep: NFTSteps = NFTSteps.IMPORT;
let amountComponent: Amount;
let recipientComponent: Recipient;
let processingFeeComponent: ProcessingFee;
Expand Down Expand Up @@ -296,33 +308,68 @@
}
}
}
const nextStep = () => (activeStep = Math.min(activeStep + 1, NFTSteps.CONFIRM));
const back = () => (activeStep = Math.max(activeStep - 1, NFTSteps.IMPORT));
let nftStepTitle: string;
let nftStepDescription: string;
$: {
const stepKey = NFTSteps[activeStep].toLowerCase(); // Convert enum to string and to lowercase
nftStepTitle = $t(`bridge.title.nft.${stepKey}`);
nftStepDescription = $t(`bridge.description.nft.${stepKey}`);
}
$: if ($selectedToken && amountComponent) {
amountComponent.validateAmount();
}
</script>

<Card class="w-full md:w-[524px]" title={$t('bridge.title.default')} text={$t('bridge.description')}>
<div class="space-y-[30px]">
<div class="f-between-center gap-4">
<ChainSelectorWrapper />
</div>
{#if $activeBridge === BridgeTypes.FUNGIBLE}
<Card class="w-full md:w-[524px]" title={$t('bridge.title.default')} text={$t('bridge.description')}>
<div class="space-y-[30px]">
<div class="f-between-center gap-4">
<ChainSelectorWrapper />
</div>

<TokenDropdown {tokens} bind:value={$selectedToken} />
{#if $selectedToken?.symbol === 'BLL' && !$selectedToken?.imported}
<FlatAlert class="!mt-2" message={$t('bridge.errors.bll_token')} type="warning" />
{/if}
<Amount bind:this={amountComponent} />
<TokenDropdown {tokens} bind:value={$selectedToken} />
{#if $selectedToken?.symbol === 'BLL' && !$selectedToken?.imported}
<FlatAlert class="!mt-2" message={$t('bridge.errors.bll_token')} type="warning" />
{/if}
<Amount bind:this={amountComponent} />

<div class="space-y-[16px]">
<Recipient bind:this={recipientComponent} />
<ProcessingFee bind:this={processingFeeComponent} />
</div>
<div class="space-y-[16px]">
<Recipient bind:this={recipientComponent} />
<ProcessingFee bind:this={processingFeeComponent} />
</div>

<div class="h-sep" />
<div class="h-sep" />

<Actions {approve} {bridge} />
<Actions {approve} {bridge} />
</div>
</Card>
{:else if $activeBridge === BridgeTypes.NFT}
<div class="f-col">
<Stepper {activeStep}>
<Step stepIndex={NFTSteps.IMPORT} currentStepIndex={activeStep} isActive={activeStep === NFTSteps.IMPORT}
>{$t('bridge.title.nft.import')}</Step>
<Step stepIndex={NFTSteps.REVIEW} currentStepIndex={activeStep} isActive={activeStep === NFTSteps.REVIEW}
>{$t('bridge.title.nft.review')}</Step>
<Step stepIndex={NFTSteps.CONFIRM} currentStepIndex={activeStep} isActive={activeStep === NFTSteps.CONFIRM}
>{$t('bridge.title.nft.confirm')}</Step>
</Stepper>

<Card class="mt-[32px] w-full md:w-[524px]" title={nftStepTitle} text={nftStepDescription}>
<div class="f-between-center w-full gap-4">
<Button type="primary" class="px-[28px] py-[14px] rounded-full flex-1 text-white" on:click={back}
>Previous Step</Button>
<Button type="primary" class="px-[28px] py-[14px] rounded-full flex-1 text-white" on:click={nextStep}
>Next Step</Button>
</div>
</Card>
</div>
</Card>
{/if}

<OnNetwork change={onNetworkChange} />

Expand Down
25 changes: 17 additions & 8 deletions packages/bridge-ui-v2/src/components/Bridge/BridgeTabs.svelte
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
<script lang="ts">
import { t } from 'svelte-i18n';
import { page } from '$app/stores';
import { LinkButton } from '$components/LinkButton';
import { PUBLIC_NFT_BRIDGE_ENABLED } from '$env/static/public';
import { classNames } from '$libs/util/classNames';
import { activeBridge } from './state';
import { BridgeTypes } from './types';
let classes = classNames('space-x-2', $$props.class);
$: isERC20Bridge = $page.route.id === '/';
$: isNFTBridge = $page.route.id === '/nft';
$: isERC20Bridge = $activeBridge === BridgeTypes.FUNGIBLE;
$: isNFTBridge = $activeBridge === BridgeTypes.NFT;
const onBridgeClick = (type: BridgeTypes) => {
activeBridge.set(type);
};
</script>

{#if PUBLIC_NFT_BRIDGE_ENABLED === 'true'}
<div class={classes}>
<LinkButton class="py-2 px-[20px]" href="/" active={isERC20Bridge}>
<button
class="{isERC20Bridge ? 'btn-primary' : 'btn-ghost'} px-[28px] py-[14px] rounded-full text-white"
on:click={() => onBridgeClick(BridgeTypes.FUNGIBLE)}>
<span> {$t('nav.token')}</span>
</LinkButton>
</button>

<LinkButton class="py-2 px-[20px]" href="/nft" active={isNFTBridge}>
<button
class="{isNFTBridge ? 'btn-primary' : 'btn-ghost'} h-[44px] px-[28px] py-[14px] rounded-full text-white"
on:click={() => onBridgeClick(BridgeTypes.NFT)}>
<span> {$t('nav.nft')}</span>
</LinkButton>
</button>
</div>
{/if}
3 changes: 3 additions & 0 deletions packages/bridge-ui-v2/src/components/Bridge/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { bridges } from '$libs/bridge';
import { chains } from '$libs/chain';
import type { Token } from '$libs/token';

import { type BridgeType, BridgeTypes } from './types';

// Note: we could combine this with Context API, but since we'll only
// have one Bridge component, it would be an overkill. If we wanted to
// instantiate multiple Bridge components, then we'd need to use
Expand All @@ -14,6 +16,7 @@ import type { Token } from '$libs/token';
// but once again, we don't need such level of security that we have to
// prevent other components outside the Bridge from accessing this store.

export const activeBridge = writable<BridgeType>(BridgeTypes.FUNGIBLE);
export const selectedToken = writable<Maybe<Token>>(null);
export const tokenBalance = writable<Maybe<FetchBalanceResult>>(null);
export const enteredAmount = writable<bigint>(BigInt(0));
Expand Down
12 changes: 12 additions & 0 deletions packages/bridge-ui-v2/src/components/Bridge/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export enum BridgeTypes {
FUNGIBLE = 'FUNGIBLE',
NFT = 'NFT',
}

export enum NFTSteps {
IMPORT,
REVIEW,
CONFIRM,
}

export type BridgeType = BridgeTypes;
4 changes: 3 additions & 1 deletion packages/bridge-ui-v2/src/components/Card/Card.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

<div class={classes}>
<div class="card-body body-regular p-4 md:p-[50px] gap-0">
<h2 class="card-title title-screen-bold">{title}</h2>
{#if title}
<h2 class="card-title title-screen-bold">{title}</h2>
{/if}
{#if text}
<p>{text}</p>
{/if}
Expand Down
13 changes: 13 additions & 0 deletions packages/bridge-ui-v2/src/components/Stepper/Step.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
export let isActive = false;
export let stepIndex: number;
export let currentStepIndex: number;
</script>

<li
data-content=""
class="step
{isActive ? 'step-primary' : ''}
{stepIndex < currentStepIndex && !isActive ? 'step-previous' : ''}">
<slot />
</li>
23 changes: 23 additions & 0 deletions packages/bridge-ui-v2/src/components/Stepper/Stepper.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script lang="ts">
import { classNames } from '$libs/util/classNames';
export let activeStep: number = 0;
const styles = `
w-full
md:card
md:rounded-[20px]
md:border
md:border-divider-border
dark:md:glassy-gradient-card
dark:md:glass-background-gradient`;
$: classes = classNames(styles, $$props.class);
</script>

<div class={classes}>
<div class="card-body body-regular gap-0 p-0">
<ul class="steps my-[30px]">
<slot {activeStep} />
</ul>
</div>
</div>
2 changes: 2 additions & 0 deletions packages/bridge-ui-v2/src/components/Stepper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Step } from './Step.svelte';
export { default as Stepper } from './Stepper.svelte';
18 changes: 15 additions & 3 deletions packages/bridge-ui-v2/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,20 @@
"bridge": {
"title": {
"default": "Bridge Token",
"nft": "Bridge NFT"
"nft": {
"import": "Import NFT",
"review": "Review",
"confirm": "Confirm"
}
},
"description": {
"default": "Send your assets across chains.",
"nft": {
"import": "Transfer your NFTs across chains",
"review": "Verify your NFT details.",
"confirm": "Confirm your NFT details."
}
},
"description": "Send your assets across chains.",
"actions": {
"approve": {
"tx": "Transaction sent to approve {token} tokens. Click <a href=\"{url}\" target=\"_blank\"><b>here</b></a> to see it in the explorer.",
Expand Down Expand Up @@ -48,7 +59,8 @@
"approved": "Approved",
"bridge": "Bridge",
"bridging": "Bridging",
"import": "Fetch NFT data"
"fetch": "Fetch NFT data",
"import": "Import"
}
},
"recipient": {
Expand Down
31 changes: 31 additions & 0 deletions packages/bridge-ui-v2/src/styles/override.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,34 @@ input[type='number'] {
flex-direction: column;
align-items: center;
}

.step:after {
height: 0px !important;
width: 0px !important;
}

.step-primary:after {
height: 8px !important;
width: 8px !important;
}

.step:before {
background-color: rgba(255, 198, 233, 0.2) !important;
height: 2px !important;
}

.step-primary:before {
background-color: #e81899 !important;
height: 2px !important;
}

.step-previous:before {
background-color: #e81899 !important;
height: 2px !important;
}

.step-previous:after {
@apply step-primary;
height: 0px !important;
width: 0px !important;
}

1 comment on commit 90e19fc

@vercel
Copy link

@vercel vercel bot commented on 90e19fc Sep 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

bridge-ui-v2-internal – ./packages/bridge-ui-v2

bridge-ui-v2-internal.vercel.app
bridge-ui-v2-internal-git-main-taikoxyz.vercel.app
bridge-ui-v2-internal-taikoxyz.vercel.app

Please sign in to comment.