Skip to content

Commit

Permalink
fix(tangle-dapp): Enhance Animation and Add Loading Pages (#2676)
Browse files Browse the repository at this point in the history
  • Loading branch information
AtelyPham authored Nov 29, 2024
1 parent f44e4c1 commit 1fd76bd
Show file tree
Hide file tree
Showing 30 changed files with 794 additions and 312 deletions.
24 changes: 24 additions & 0 deletions apps/tangle-dapp/app/blueprints/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import TopBanner from '@webb-tools/tangle-shared-ui/components/blueprints/TopBanner';
import SkeletonLoader from '@webb-tools/webb-ui-components/components/SkeletonLoader';
import type { FC } from 'react';
import { twMerge } from 'tailwind-merge';

const LoadingPage: FC = () => {
return (
<div className="space-y-5">
<TopBanner />

<div
className={twMerge(
'grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3',
)}
>
{Array.from({ length: 6 }).map((_, idx) => (
<SkeletonLoader key={idx} className="h-80" />
))}
</div>
</div>
);
};

export default LoadingPage;
64 changes: 64 additions & 0 deletions apps/tangle-dapp/app/bridge/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ArrowRight } from '@webb-tools/icons/ArrowRight';
import Button from '@webb-tools/webb-ui-components/components/buttons/Button';
import { Label } from '@webb-tools/webb-ui-components/components/Label';
import SkeletonLoader from '@webb-tools/webb-ui-components/components/SkeletonLoader';
import { type FC } from 'react';
import { twMerge } from 'tailwind-merge';

const Loading: FC = () => {
// TODO: Using the container style when PR https://github.com/tangle-network/dapp/pull/2664 is merged
return (
<div
className={twMerge(
'max-w-[640px] min-h-[580px] bg-mono-0 dark:bg-mono-190 p-5 md:p-8 rounded-xl',
'shadow-webb-lg dark:shadow-webb-lg-dark',
'flex flex-col justify-between w-full mx-auto',
)}
>
<div className="flex flex-col gap-10">
<div className="flex flex-col items-center justify-center md:flex-row md:justify-between md:items-end md:gap-3">
{/* Source Chain Selector */}
<div className="w-full space-y-2 md:flex-1">
<Label
className="font-bold text-mono-120 dark:text-mono-120"
htmlFor="bridge-source-chain-selector"
>
From
</Label>

<SkeletonLoader className="w-full h-16" />
</div>

<ArrowRight
size="lg"
className="mt-5 rotate-90 md:rotate-0 md:mt-0 md:mb-5"
/>

{/* Destination Chain Selector */}
<div className="w-full space-y-2 md:flex-1">
<Label
className="font-bold text-mono-120 dark:text-mono-120"
htmlFor="bridge-destination-chain-selector"
>
To
</Label>

<SkeletonLoader className="w-full h-16" />
</div>
</div>

<div className="space-y-2">
<SkeletonLoader className="w-full h-[72px]" />

<SkeletonLoader className="w-full h-4 ml-auto max-w-24" />
</div>

<SkeletonLoader className="w-full h-[72px]" />
</div>

<Button isFullWidth isLoading loadingText="Loading..." />
</div>
);
};

export default Loading;
14 changes: 14 additions & 0 deletions apps/tangle-dapp/app/liquid-staking/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import SkeletonLoader from '@webb-tools/webb-ui-components/components/SkeletonLoader';
import type { FC } from 'react';

const LoadingPage: FC = () => {
return (
<div className="w-full max-w-lg mx-auto space-y-4">
<SkeletonLoader className="w-full h-11 rounded-2xl" />

<SkeletonLoader className="w-full h-[448px] rounded-2xl" />
</div>
);
};

export default LoadingPage;
29 changes: 29 additions & 0 deletions apps/tangle-dapp/app/restake/AnimatedPageWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use client';

import { HTMLMotionProps, motion } from 'framer-motion';
import { forwardRef, PropsWithChildren } from 'react';

export type AnimatedPageWrapperProps = HTMLMotionProps<'div'>;

const AnimatedPageWrapper = forwardRef<
HTMLDivElement,
PropsWithChildren<AnimatedPageWrapperProps>
>(({ children, ...props }, ref) => {
return (
<motion.div
ref={ref}
style={{ transformOrigin: 'left' }}
initial={{ opacity: 0, flex: 'none', width: '0%' }}
animate={{ opacity: 1, flex: '1 1 0%', width: '100%' }}
transition={{ duration: 0.3, delay: 0.3 }}
exit={{ opacity: 0, flex: 'none', width: '0%' }}
{...props}
>
{children}
</motion.div>
);
});

AnimatedPageWrapper.displayName = 'AnimatedPageWrapper';

export default AnimatedPageWrapper;
34 changes: 34 additions & 0 deletions apps/tangle-dapp/app/restake/AnimatedTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import cx from 'classnames';
import { AnimatePresence, motion } from 'framer-motion';
import type { PropsWithChildren } from 'react';

export type AnimatedTableProps = PropsWithChildren & {
isTableOpen?: boolean;
isMediumScreen?: boolean;
};

export function AnimatedTable({
children,
isMediumScreen,
isTableOpen,
}: AnimatedTableProps) {
return (
<AnimatePresence>
{(!isMediumScreen || isTableOpen) && (
<motion.div
key="unstake-request-table"
className={cx(
'w-full max-w-lg origin-[0_0_0]',
isTableOpen && isMediumScreen ? 'mr-auto ml-0' : 'mx-auto',
)}
transition={{ duration: 0.15 }}
initial={{ opacity: 0, scale: 0 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0 }}
>
{children}
</motion.div>
)}
</AnimatePresence>
);
}
70 changes: 70 additions & 0 deletions apps/tangle-dapp/app/restake/ExpandTableButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { DoubleArrowRightIcon } from '@radix-ui/react-icons';
import { TooltipTrigger } from '@radix-ui/react-tooltip';
import IconButton from '@webb-tools/webb-ui-components/components/buttons/IconButton';
import {
Tooltip,
TooltipBody,
} from '@webb-tools/webb-ui-components/components/Tooltip';
import type { ComponentProps, ReactNode } from 'react';
import { twMerge } from 'tailwind-merge';

export enum NotificationVariant {
PENDING = 'pending',
SUCCESS = 'success',
}

export type ExpandTableButtonProps = ComponentProps<'button'> & {
notificationVariant?: NotificationVariant;
tooltipContent?: ReactNode;
};

const colorClasses = {
[NotificationVariant.PENDING]: {
back: twMerge('bg-amber-400'),
front: twMerge('bg-amber-500'),
},
[NotificationVariant.SUCCESS]: {
back: twMerge('bg-green-400'),
front: twMerge('bg-green-500'),
},
} as const satisfies Record<
NotificationVariant,
{ back: string; front: string }
>;

export function ExpandTableButton({
notificationVariant,
tooltipContent,
...props
}: ExpandTableButtonProps) {
return (
<Tooltip>
<TooltipTrigger asChild>
<IconButton {...props}>
<DoubleArrowRightIcon />

{notificationVariant && (
<>
<span className="absolute top-0 right-0 flex w-2 h-2 -mt-0.5 -mr-0.5">
<span
className={twMerge(
'absolute inline-flex w-full h-full rounded-full opacity-75 animate-ping',
colorClasses[notificationVariant].back,
)}
/>
<span
className={twMerge(
'relative inline-flex w-2 h-2 rounded-full',
colorClasses[notificationVariant].front,
)}
/>
</span>
</>
)}
</IconButton>
</TooltipTrigger>

<TooltipBody>{tooltipContent}</TooltipBody>
</Tooltip>
);
}
39 changes: 39 additions & 0 deletions apps/tangle-dapp/app/restake/LoadingPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Button from '@webb-tools/webb-ui-components/components/buttons/Button';
import { Card } from '@webb-tools/webb-ui-components/components/Card';
import SkeletonLoader from '@webb-tools/webb-ui-components/components/SkeletonLoader';
import { FC } from 'react';

import RestakeTabs from './RestakeTabs';
import StyleContainer from './StyleContainer';

const LoadingPage: FC = () => {
return (
<StyleContainer>
<RestakeTabs />

<Card withShadow className="space-y-4">
<SkeletonLoader className="w-full h-36 rounded-xl" />

<div className="p-3 space-y-2">
<div className="flex items-center justify-between">
<SkeletonLoader className="flex-none w-20 h-6 rounded-xl" />

<SkeletonLoader className="flex-none w-12 h-6 rounded-xl" />
</div>

<div className="flex items-center justify-between">
<SkeletonLoader className="flex-none w-20 h-6 rounded-xl" />

<SkeletonLoader className="flex-none w-12 h-6 rounded-xl" />
</div>
</div>

<Button isFullWidth isLoading loadingText="Loading...">
Loading...
</Button>
</Card>
</StyleContainer>
);
};

export default LoadingPage;
21 changes: 21 additions & 0 deletions apps/tangle-dapp/app/restake/StyleContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentProps, forwardRef, PropsWithChildren } from 'react';
import { twMerge } from 'tailwind-merge';

const StyleContainer = forwardRef<
HTMLDivElement,
PropsWithChildren<ComponentProps<'div'>>
>(({ children, className, ...props }, ref) => {
return (
<div
{...props}
ref={ref}
className={twMerge('w-full max-w-lg mx-auto', className)}
>
{children}
</div>
);
});

StyleContainer.displayName = 'StyleContainer';

export default StyleContainer;
17 changes: 0 additions & 17 deletions apps/tangle-dapp/app/restake/deposit/layout.tsx

This file was deleted.

7 changes: 7 additions & 0 deletions apps/tangle-dapp/app/restake/deposit/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import LoadingPage from '../LoadingPage';

const Page = () => {
return <LoadingPage />;
};

export default Page;
9 changes: 8 additions & 1 deletion apps/tangle-dapp/app/restake/deposit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import RestakeTabs from '../RestakeTabs';
import StyleContainer from '../StyleContainer';
import DepositForm from './DepositForm';

export const dynamic = 'force-static';

export default function DepositPage() {
return <DepositForm />;
return (
<StyleContainer>
<RestakeTabs />
<DepositForm />
</StyleContainer>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import type { OperatorMap } from '@webb-tools/tangle-shared-ui/types/restake';
import { Input } from '@webb-tools/webb-ui-components/components/Input';
import { type ComponentProps, type FC, useMemo, useState } from 'react';

import OperatorsTableUI from '../../components/tables/Operators';
import { useRestakeContext } from '../../context/RestakeContext';
import useIdentities from '../../data/useIdentities';
import { delegationsToVaultTokens } from './utils';
import OperatorsTableUI from '../../../components/tables/Operators';
import { useRestakeContext } from '../../../context/RestakeContext';
import useIdentities from '../../../data/useIdentities';
import { delegationsToVaultTokens } from '../utils';

type OperatorUI = NonNullable<
ComponentProps<typeof OperatorsTableUI>['data']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { TableAndChartTabs } from '@webb-tools/webb-ui-components/components/Tab
import { TabContent } from '@webb-tools/webb-ui-components/components/Tabs/TabContent';
import { type ComponentProps, type FC, useMemo } from 'react';

import VaultAssetsTable from '../../components/tables/VaultAssets';
import VaultsTable from '../../components/tables/Vaults';
import { useRestakeContext } from '../../context/RestakeContext';
import useRestakeRewardConfig from '../../data/restake/useRestakeRewardConfig';
import type { DelegatorInfo } from '../../types/restake';
import VaultAssetsTable from '../../../components/tables/VaultAssets';
import VaultsTable from '../../../components/tables/Vaults';
import { useRestakeContext } from '../../../context/RestakeContext';
import useRestakeRewardConfig from '../../../data/restake/useRestakeRewardConfig';
import type { DelegatorInfo } from '../../../types/restake';
import OperatorsTable from './OperatorsTable';

const RESTAKE_VAULTS_TAB = 'Restake Vaults';
Expand Down
Loading

0 comments on commit 1fd76bd

Please sign in to comment.