diff --git a/src/components/animation/Spinner.module.css b/src/components/animation/Spinner.module.css index 87df3ee..45e5181 100644 --- a/src/components/animation/Spinner.module.css +++ b/src/components/animation/Spinner.module.css @@ -20,6 +20,9 @@ border-radius: 20%; background: #010101; } +.spinner.white div:after { + background: #ffffff; +} .spinner div:nth-child(1) { transform: rotate(0deg); animation-delay: -1.1s; diff --git a/src/components/animation/Spinner.tsx b/src/components/animation/Spinner.tsx index 6df8f8d..263f617 100644 --- a/src/components/animation/Spinner.tsx +++ b/src/components/animation/Spinner.tsx @@ -3,9 +3,11 @@ import { memo } from 'react'; import styles from './Spinner.module.css'; // From https://loading.io/css/ -function _Spinner({ classes }: { classes?: string }) { +function _Spinner({ white, classes }: { white?: boolean; classes?: string }) { return ( -
+
diff --git a/src/components/layout/BackgroundBanner.tsx b/src/components/layout/BackgroundBanner.tsx new file mode 100644 index 0000000..cb48bce --- /dev/null +++ b/src/components/layout/BackgroundBanner.tsx @@ -0,0 +1,31 @@ +import { createContext, useContext, useMemo, useState } from 'react'; + +export const BannerColorContext = createContext<{ + bannerClassName: string; + setBannerClassName?: (name: string) => void; +}>({ bannerClassName: '', setBannerClassName: undefined }); + +export function useBackgroundBannerState() { + // State for managing banner class, to be used as context value + const [bannerClassName, setBannerClassName] = useState(''); + const bannerState = useMemo( + () => ({ bannerClassName, setBannerClassName }), + [bannerClassName, setBannerClassName], + ); + return bannerState; +} + +export function useBackgroundBanner() { + return useContext(BannerColorContext); +} + +export function BackgroundBanner() { + const { bannerClassName } = useBackgroundBanner(); + return ( +
+ ); +} diff --git a/src/components/layout/ContentFrame.tsx b/src/components/layout/ContentFrame.tsx new file mode 100644 index 0000000..95fa8b1 --- /dev/null +++ b/src/components/layout/ContentFrame.tsx @@ -0,0 +1,32 @@ +import { PropsWithChildren } from 'react'; + +import { + BackgroundBanner, + BannerColorContext, + useBackgroundBannerState, +} from './BackgroundBanner'; + +export function ContentFrame(props: PropsWithChildren) { + // Provide context so children can change banner color + const bannerState = useBackgroundBannerState(); + + return ( +
+
+ + +
{props.children}
+
+
+
+ ); +} + +const styles = { + container: { + width: 'min(900px,96vw)', + }, +}; diff --git a/src/components/nav/ContentFrame.tsx b/src/components/nav/ContentFrame.tsx deleted file mode 100644 index 300aa32..0000000 --- a/src/components/nav/ContentFrame.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { PropsWithChildren } from 'react'; - -export function ContentFrame(props: PropsWithChildren) { - return ( -
-
-
-
{props.children}
-
-
- ); -} diff --git a/src/features/search/MessageDetails.tsx b/src/features/search/MessageDetails.tsx index ca6e3f3..7405eb1 100644 --- a/src/features/search/MessageDetails.tsx +++ b/src/features/search/MessageDetails.tsx @@ -1,5 +1,5 @@ import Image from 'next/future/image'; -import { useCallback, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import { useQuery } from 'urql'; import { Spinner } from '../../components/animation/Spinner'; @@ -7,6 +7,7 @@ import { CopyButton } from '../../components/buttons/CopyButton'; import { ChainIcon } from '../../components/icons/ChainIcon'; import { ChainToChain } from '../../components/icons/ChainToChain'; import { HelpIcon } from '../../components/icons/HelpIcon'; +import { useBackgroundBanner } from '../../components/layout/BackgroundBanner'; import { Card } from '../../components/layout/Card'; import CheckmarkIcon from '../../images/icons/checkmark-circle.svg'; import XCircleIcon from '../../images/icons/x-circle.svg'; @@ -43,6 +44,18 @@ export function MessageDetails({ messageId }: { messageId: string }) { destinationTransaction, } = message; + const { bannerClassName, setBannerClassName } = useBackgroundBanner(); + useEffect(() => { + if (!setBannerClassName) return; + if (error || message.status === MessageStatus.Failing) { + setBannerClassName('bg-red-600'); + } else if (bannerClassName) { + setBannerClassName(''); + } + + // TODO toast on error or surface some other way + }, [error, message, bannerClassName, setBannerClassName]); + const reExecutor = useCallback(() => { if (status !== MessageStatus.Delivered) { reexecuteQuery({ requestPolicy: 'network-only' }); @@ -50,15 +63,23 @@ export function MessageDetails({ messageId }: { messageId: string }) { }, [reexecuteQuery, status]); useInterval(reExecutor, AUTO_REFRESH_DELAY); - // TODO handle message not found and error cases + // TODO handle message not found // TODO hide chain logos in circles while loading + // TODO show spinner while message is fetching, not just found and pending return ( <>

Message

{status === MessageStatus.Pending && ( -
Status: Pending
+
+
Status: Pending
+
+
+ +
+
+
)} {status === MessageStatus.Delivered && (
diff --git a/src/features/search/placeholderMessages.ts b/src/features/search/placeholderMessages.ts index 513f70b..a77c6ae 100644 --- a/src/features/search/placeholderMessages.ts +++ b/src/features/search/placeholderMessages.ts @@ -19,13 +19,16 @@ export const TX_ZERO: PartialTransactionReceipt = { blockNumber: 123456789, }; +const BODY_ZERO = + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; + export const PLACEHOLDER_MESSAGES: Message[] = [ { id: '1', status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: chain.mainnet.id, destinationChainId: chain.arbitrum.id, originTransaction: TX_ZERO, @@ -38,7 +41,7 @@ export const PLACEHOLDER_MESSAGES: Message[] = [ status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: chain.polygon.id, destinationChainId: chain.optimism.id, originTransaction: TX_ZERO, @@ -51,7 +54,7 @@ export const PLACEHOLDER_MESSAGES: Message[] = [ status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: avalancheChain.id, destinationChainId: celoMainnetChain.id, originTransaction: TX_ZERO, @@ -64,7 +67,7 @@ export const PLACEHOLDER_MESSAGES: Message[] = [ status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: bscChain.id, destinationChainId: chain.mainnet.id, originTransaction: TX_ZERO, @@ -77,7 +80,7 @@ export const PLACEHOLDER_MESSAGES: Message[] = [ status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: chain.mainnet.id, destinationChainId: chain.goerli.id, originTransaction: TX_ZERO, @@ -90,7 +93,7 @@ export const PLACEHOLDER_MESSAGES: Message[] = [ status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: chain.mainnet.id, destinationChainId: celoMainnetChain.id, originTransaction: TX_ZERO, @@ -103,7 +106,7 @@ export const PLACEHOLDER_MESSAGES: Message[] = [ status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: chain.optimism.id, destinationChainId: avalancheChain.id, originTransaction: TX_ZERO, @@ -116,7 +119,7 @@ export const PLACEHOLDER_MESSAGES: Message[] = [ status: MessageStatus.Pending, sender: constants.AddressZero, recipient: constants.AddressZero, - body: constants.AddressZero + constants.AddressZero + constants.AddressZero, + body: BODY_ZERO, originChainId: bscChain.id, destinationChainId: avalancheChain.id, originTransaction: TX_ZERO, diff --git a/src/images/icons/book.svg b/src/images/icons/book.svg index 3e22e6c..76589a5 100644 --- a/src/images/icons/book.svg +++ b/src/images/icons/book.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/images/icons/briefcase.svg b/src/images/icons/briefcase.svg index cc81432..bc6150d 100644 --- a/src/images/icons/briefcase.svg +++ b/src/images/icons/briefcase.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + \ No newline at end of file diff --git a/src/images/icons/info-circle.svg b/src/images/icons/info-circle.svg index aa986c2..79f08a9 100644 --- a/src/images/icons/info-circle.svg +++ b/src/images/icons/info-circle.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 736b87f..c5c1716 100755 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,6 +1,6 @@ import type { NextPage } from 'next'; -import { ContentFrame } from '../components/nav/ContentFrame'; +import { ContentFrame } from '../components/layout/ContentFrame'; import { MessageSearch } from '../features/search/MessageSearch'; const Home: NextPage = () => { diff --git a/src/pages/message/[messageId].tsx b/src/pages/message/[messageId].tsx index 8e26361..0998d18 100644 --- a/src/pages/message/[messageId].tsx +++ b/src/pages/message/[messageId].tsx @@ -2,7 +2,7 @@ import type { NextPage } from 'next'; import { useRouter } from 'next/router'; import { useEffect } from 'react'; -import { ContentFrame } from '../../components/nav/ContentFrame'; +import { ContentFrame } from '../../components/layout/ContentFrame'; import { MessageDetails } from '../../features/search/MessageDetails'; import { logger } from '../../utils/logger';