Finish rebrand implementation

pull/47/head
J M Rossy 1 year ago
parent 342fb1efb0
commit b19c1ff78e
  1. BIN
      public/hyperlane-banner.png
  2. 4
      public/images/lines-bg-mid.svg
  3. 4
      public/images/lines-bg-top.svg
  4. 0
      public/images/logo-blue.png
  5. 0
      public/images/logo-with-text.png
  6. 0
      public/images/logo.png
  7. 0
      public/images/logo.svg
  8. 10
      src/components/buttons/SolidButton.tsx
  9. 6
      src/components/icons/Chevron.tsx
  10. 38
      src/components/icons/HyperlaneLogo.tsx
  11. 2
      src/components/input/Checkbox.module.css
  12. 2
      src/components/input/SelectField.tsx
  13. 11
      src/components/layout/AppLayout.tsx
  14. 11
      src/components/layout/Card.tsx
  15. 2
      src/components/layout/Modal.tsx
  16. 13
      src/components/nav/Footer.tsx
  17. 8
      src/components/nav/Header.tsx
  18. 4
      src/components/search/MiniSearchBar.tsx
  19. 4
      src/components/search/SearchBar.tsx
  20. 71
      src/components/search/SearchFilterBar.tsx
  21. 4
      src/components/search/SearchStates.tsx
  22. 36
      src/features/chains/ConfigureChains.tsx
  23. 29
      src/features/messages/MessageDetails.tsx
  24. 9
      src/features/messages/MessageSearch.tsx
  25. 18
      src/features/messages/MessageTable.tsx
  26. 4
      src/features/messages/cards/ContentDetailsCard.tsx
  27. 6
      src/features/messages/cards/GasDetailsCard.tsx
  28. 4
      src/features/messages/cards/IcaDetailsCard.tsx
  29. 4
      src/features/messages/cards/IsmDetailsCard.tsx
  30. 2
      src/features/messages/cards/KeyValueRow.tsx
  31. 4
      src/features/messages/cards/TimelineCard.tsx
  32. 4
      src/features/messages/cards/TransactionCard.tsx
  33. 2
      src/features/messages/queries/useMessageQuery.ts
  34. 0
      src/images/backgrounds/footer-bg.svg
  35. 0
      src/images/backgrounds/footer-line-desktop.svg
  36. 0
      src/images/backgrounds/footer-line-mobile.svg
  37. 0
      src/images/backgrounds/footer-top-border.svg
  38. 4
      src/images/backgrounds/main-bg.svg
  39. 5
      src/images/footer/footer-logo.svg
  40. 2
      src/images/icons/checkmark-circle.svg
  41. 2
      src/pages/_document.tsx
  42. 20
      src/pages/api-docs.tsx
  43. 21
      src/styles/Color.ts
  44. 20
      tailwind.config.js

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

@ -0,0 +1,4 @@
<svg width="1440" height="1422" viewBox="0 0 1440 1422" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M-31.5 462.274C2081.5 638.912 -628.5 757.774 1473.5 932.774" stroke="white" stroke-width="8"/>
<path d="M-34 484.774C1976.5 621.774 -688.5 763.274 1470.5 960.774" stroke="white" stroke-width="4"/>
</svg>

After

Width:  |  Height:  |  Size: 317 B

@ -0,0 +1,4 @@
<svg width="886" height="114" viewBox="0 0 886 114" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M783.5 -3.5C621.953 133.053 158.722 87.2984 8 -3.5" stroke="white" stroke-width="2"/>
<path d="M884.5 -5.5C586 201.5 152.904 88.164 2 -5.5" stroke="white" stroke-width="4"/>
</svg>

After

Width:  |  Height:  |  Size: 290 B

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -1,7 +1,7 @@
import { PropsWithChildren, ReactElement } from 'react';
interface ButtonProps {
color?: 'white' | 'blue' | 'green' | 'red'; // defaults to blue
color?: 'white' | 'blue' | 'green' | 'red' | 'pink'; // defaults to blue
type?: 'submit' | 'reset' | 'button';
onClick?: () => void;
classes?: string;
@ -18,7 +18,7 @@ export function SolidButton(props: PropsWithChildren<ButtonProps>) {
onClick,
color: _color,
classes,
bold,
bold = true,
icon,
disabled,
title,
@ -26,12 +26,16 @@ export function SolidButton(props: PropsWithChildren<ButtonProps>) {
} = props;
const color = _color ?? 'blue';
const base = 'flex items-center justify-center rounded transition-all duration-500';
const base = 'flex items-center justify-center rounded-full transition-all duration-500';
let baseColors, onHover, onActive;
if (color === 'blue') {
baseColors = 'bg-blue-500 text-white';
onHover = 'hover:bg-blue-600';
onActive = 'active:bg-blue-700';
} else if (color === 'pink') {
baseColors = 'bg-pink-500 text-white';
onHover = 'hover:bg-pink-600';
onActive = 'active:bg-pink-700';
} else if (color === 'green') {
baseColors = 'bg-green-500 text-white';
onHover = 'hover:bg-green-600';

@ -40,7 +40,7 @@ function _ChevronIcon({ width, height, direction, color, classes }: Props) {
<path
d="M1 1l6 6 6-6"
strokeWidth="2"
stroke={color || Color.primaryBlack}
stroke={color || Color.Black}
fill="none"
fillRule="evenodd"
strokeLinecap="round"
@ -90,7 +90,7 @@ function _HyperlaneChevron({ width, height, direction, color, classes }: Props)
>
<path
d="M6.3 1h61.3a20 20 0 0 1 18.7 13L140 158.3a5 5 0 0 1 0 3.4l-.3.9-53.5 147.2A20 20 0 0 1 67.4 323H6.2a5 5 0 0 1-4.7-6.6l55.2-158.1L1.7 7.7A5 5 0 0 1 6.2 1Z"
fill={color || Color.primaryBlue}
fill={color || Color.Blue}
></path>
</svg>
);
@ -124,7 +124,7 @@ function _HyperlaneWideChevron({ width, height, direction, color, classes }: Pro
width={width}
height={height}
className={`${directionClass} ${classes}`}
fill={color || Color.primaryBlue}
fill={color || Color.Blue}
>
<path d="M4.4 0h53c7.2 0 13.7 3 16.2 7.7l46.5 85.1a2 2 0 0 1 0 2l-.2.5-46.3 87c-2.5 4.6-9 7.7-16.3 7.7h-53c-3 0-5-2-4-4L48 92.9.4 4c-1-2 1-4 4-4Z" />
</svg>

@ -0,0 +1,38 @@
import { memo } from 'react';
function _HyperlaneLogo({
width,
height,
fill,
className = '',
}: {
width?: number | string;
height?: number | string;
fill?: string;
className?: string;
}) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width}
height={height}
className={className}
viewBox="0 0 117 118"
>
<path
d="M64.4787 0H88.4134C91.6788 0 94.6004 1.89614 95.7403 4.7553L116.749 57.4498C116.911 57.8563 116.913 58.3035 116.754 58.7112L116.637 59.014L116.635 59.017L95.7152 112.81C94.5921 115.698 91.6551 117.62 88.3666 117.62H64.4355C63.0897 117.62 62.1465 116.379 62.59 115.192L84.1615 57.4498L62.6428 2.45353C62.1766 1.26188 63.1208 0 64.4787 0Z"
fill={fill}
/>
<path
d="M1.99945 0H25.9342C29.1996 0 32.1211 1.89614 33.261 4.7553L54.2696 57.4498C54.4316 57.8563 54.4336 58.3035 54.275 58.7112L54.1573 59.014L54.1561 59.017L33.236 112.81C32.1129 115.698 29.1759 117.62 25.8874 117.62H1.95626C0.610483 117.62 -0.332722 116.379 0.110804 115.192L21.6823 57.4498L0.163626 2.45353C-0.302638 1.26188 0.641544 0 1.99945 0Z"
fill={fill}
/>
<path
d="M80.7202 46.2178H46.9324V71.7089H80.7202L86.2411 58.5992L80.7202 46.2178Z"
fill={fill}
/>
</svg>
);
}
export const HyperlaneLogo = memo(_HyperlaneLogo);

@ -20,7 +20,7 @@
border-radius: 0.2rem;
transform: scale(0);
transition: 200ms all ease-in-out;
background-color: #2362c1;
background-color: #2362C0;
}
.checkbox:checked::before {

@ -19,7 +19,7 @@ export function SelectField(props: Props) {
return (
<select
className={`px-2 py-1 text-sm border border-gray-400 rounded bg-transparent invalid:text-gray-400 ${
className={`px-2 py-1 text-sm font-light border border-gray-400 rounded bg-transparent invalid:text-gray-400 ${
classes || ''
}`}
{...passThruProps}

@ -18,13 +18,14 @@ export function AppLayout({ pathName, children }: PropsWithChildren<Props>) {
<title>{`Hyperlane Explorer | ${getHeadTitle(pathName)}`}</title>
</Head>
<div
style={styles.container}
id="app-content"
className="w-full min-w-screen h-full min-h-screen flex flex-col justify-between bg-blue-500"
className="relative w-full min-w-screen h-full min-h-screen flex flex-col justify-between bg-blue-500"
>
{/* <InfoBanner /> */}
<Header pathName={pathName} />
<div className="max-w-5xl mx-auto grow">
<main style={styles.container} className="min-h-full pt-2 ">
<main style={styles.main} className="relative min-h-full pt-3 z-20">
{children}
</main>
</div>
@ -42,6 +43,12 @@ function getHeadTitle(pathName: string) {
const styles = {
container: {
backgroundImage: 'url(/images/lines-bg-top.svg)',
backgroundSize: '94vw',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center 80px',
},
main: {
width: 'min(900px,96vw)',
},
};

@ -1,11 +1,16 @@
import { PropsWithChildren } from 'react';
interface Props {
classes?: string;
className?: string;
padding?: string;
}
export function Card({ classes, children }: PropsWithChildren<Props>) {
export function Card({ className, padding = 'p-4 sm:p-5', children }: PropsWithChildren<Props>) {
return (
<div className={`p-4 bg-white shadow border rounded overflow-auto ${classes}`}>{children}</div>
<div
className={`bg-white ring ring-blue-300 rounded-3xl overflow-auto ${padding} ${className}`}
>
{children}
</div>
);
}

@ -42,7 +42,7 @@ export function Modal({
maxWidth || 'max-w-xs'
} max-h-[90vh] transform overflow-auto rounded-md bg-white px-4 py-4 text-left shadow-lg transition-all`}
>
<Dialog.Title as="h3" className="text text-gray-700">
<Dialog.Title as="h3" className="font-medium text-blue-500">
{title}
</Dialog.Title>
{children}

@ -3,13 +3,14 @@ import Image from 'next/image';
import Link from 'next/link';
import { links } from '../../consts/links';
// import FooterLine from '../../images/footer/footer-line-desktop.svg';
// import FooterLineMobile from '../../images/footer/footer-line-mobile.svg';
import FooterBg from '../../images/footer/footer-bg.svg';
import FooterLogo from '../../images/footer/footer-logo.svg';
import FooterTopBorder from '../../images/footer/footer-top-border.svg';
// import FooterLine from '../../images/backgrounds/footer-line-desktop.svg';
// import FooterLineMobile from '../../images/backgrounds/footer-line-mobile.svg';
import FooterBg from '../../images/backgrounds/footer-bg.svg';
import FooterTopBorder from '../../images/backgrounds/footer-top-border.svg';
import { Color } from '../../styles/Color';
import { Discord } from '../icons/Discord';
import { Github } from '../icons/Github';
import { HyperlaneLogo } from '../icons/HyperlaneLogo';
import { Medium } from '../icons/Medium';
import { Twitter } from '../icons/Twitter';
@ -47,7 +48,7 @@ export function Footer() {
<div className="flex items-center justify-between">
<div className="flex items-center justify-center">
<div className="ml-2 h-20 w-20">
<Image src={FooterLogo} alt="footer-logo" />
<HyperlaneLogo fill={Color.White} />
</div>
<div className="text-2xl font-medium ml-6 space-y-1 ">
<div>Go Interchain</div>

@ -36,7 +36,7 @@ export function Header({ pathName }: { pathName: string }) {
return (
<header
className={`z-30 sticky top-0 px-2 sm:px-6 lg:px-12 w-full bg-blue-500 transition-all ease-in-out duration-500 ${
animateHeader ? 'py-1 border-b border-blue-400' : 'py-4 sm:py-5'
animateHeader ? 'py-1 border-b border-white' : 'py-4 sm:py-5'
}`}
>
<div className="flex items-center justify-between">
@ -122,21 +122,21 @@ function DropdownButton({ isOpen }: { isOpen: boolean }) {
width={10}
height={14}
direction={isOpen ? 'n' : 's'}
color={Color.primaryWhite}
color={Color.White}
classes="transition-all"
/>
<HyperlaneWideChevron
width={10}
height={14}
direction={isOpen ? 'n' : 's'}
color={Color.primaryWhite}
color={Color.White}
classes="-mt-1 transition-all"
/>
<HyperlaneWideChevron
width={10}
height={14}
direction={isOpen ? 'n' : 's'}
color={Color.primaryWhite}
color={Color.White}
classes="-mt-1 transition-all"
/>
</div>

@ -22,13 +22,13 @@ export function MiniSearchBar() {
return (
<Formik<FormValues> initialValues={initialValues} onSubmit={onSubmit}>
<Form>
<div className="p-1 flex items-center bg-white ring-4 ring-blue-400 hover:ring-blue-200 rounded-full transition-all">
<div className="p-1 flex items-center bg-white ring ring-blue-400 hover:ring-blue-200 rounded-full transition-all">
<Field
id="search"
name="search"
type="search"
placeholder="Hash or address"
className="w-32 focus:w-64 py-2 px-2.5 h-8 text-sm rounded-full placeholder:text-gray-500 focus:outline-none transition-[width] ease-in-out duration-500"
className="w-32 focus:w-64 py-2 px-2.5 h-8 text-sm font-light placeholder:text-gray-600 rounded-full focus:outline-none transition-[width] ease-in-out duration-500"
/>
<div className="h-8 w-8 flex items-center justify-center rounded-full bg-pink-500">
<IconButton

@ -20,13 +20,13 @@ export function SearchBar({ value, placeholder, onChangeValue, isFetching }: Pro
};
return (
<div className="p-1 flex items-center bg-white w-full rounded-full ring-4 ring-blue-400 hover:ring-blue-200 transition-all duration-500">
<div className="p-1 flex items-center bg-white w-full rounded-full ring ring-blue-400 hover:ring-blue-200 transition-all duration-500">
<input
value={value}
onChange={onChange}
type="search"
placeholder={placeholder}
className="p-1 sm:px-4 md:px-5 flex-1 h-10 sm:h-12 rounded-full placeholder:text-gray-500 focus:outline-none"
className="p-1 sm:px-4 md:px-5 flex-1 h-10 sm:h-12 font-light rounded-full placeholder:text-gray-600 focus:outline-none"
/>
<div className="h-10 sm:h-12 w-10 sm:w-12 flex items-center justify-center rounded-full bg-pink-500">
{isFetching && <Spinner classes="scale-[30%] mr-2.5 invert" />}

@ -7,8 +7,9 @@ import { ChainMetadata, mainnetChainsMetadata, testnetChainsMetadata } from '@hy
import { getChainDisplayName } from '../../features/chains/utils';
import { useMultiProvider } from '../../features/providers/multiProvider';
import GearIcon from '../../images/icons/gear.svg';
import { Color } from '../../styles/Color';
import { arrayToObject } from '../../utils/objects';
import { BorderedButton } from '../buttons/BorderedButton';
import { SolidButton } from '../buttons/SolidButton';
import { TextButton } from '../buttons/TextButton';
import { ChainLogo } from '../icons/ChainLogo';
import { ChevronIcon } from '../icons/Chevron';
@ -61,15 +62,10 @@ export function SearchFilterBar({
endValue={endTimestamp}
onChangeEndValue={onChangeEndTimestamp}
/>
<div className="w-px h-8 bg-gray-200"></div>
<Link href="/settings" title="View explorer settings">
<Image
src={GearIcon}
width={24}
height={24}
className="opacity-40 hover:opacity-30 active:opacity-20 hover:rotate-90 transition-all"
alt=""
/>
<div className="p-1.5 bg-pink-500 rounded-full active:opacity-90 hover:rotate-90 transition-all">
<Image src={GearIcon} width={16} height={16} className="invert" alt="Settings" />
</div>
</Link>
</div>
);
@ -151,23 +147,26 @@ function ChainMultiSelector({
<DropdownModal
buttonContent={
<>
<span className="text-gray-700 py-px">{text}</span>
<ChevronIcon direction="s" width={9} height={5} classes="ml-2 opacity-80" />
<span className="text-white font-medium py-px">{text}</span>
<ChevronIcon
direction="s"
width={9}
height={5}
classes="ml-2 opacity-80"
color={Color.White}
/>
</>
}
buttonClasses="text-sm sm:min-w-[5.8rem] px-1 sm:px-2.5 py-0.5 flex items-center justify-center rounded border border-gray-500 hover:opacity-70 active:opacity-60 transition-all"
buttonClasses="text-sm sm:min-w-[5.8rem] px-1 sm:px-2.5 py-0.5 flex items-center justify-center rounded-full bg-pink-500 hover:opacity-80 active:opacity-70 transition-all"
modalContent={(closeDropdown) => (
<div className="p-4">
<div className="flex items-center justify-between">
<h3 className="text-gray-700 text-lg">{header}</h3>
<h3 className="font-medium text-blue-500">{header}</h3>
<div className="flex mr-4">
<TextButton classes="text-sm underline underline-offset-2" onClick={onToggleAll}>
<TextButton classes="text-sm font-medium text-pink-500" onClick={onToggleAll}>
All
</TextButton>
<TextButton
classes="ml-3.5 text-sm underline underline-offset-2"
onClick={onToggleNone}
>
<TextButton classes="ml-3.5 text-sm font-medium text-pink-500" onClick={onToggleNone}>
None
</TextButton>
</div>
@ -180,7 +179,7 @@ function ChainMultiSelector({
onToggle={onToggleSection(mainnetChainsMetadata)}
name="mainnet-chains"
>
<h4 className="ml-2 text-gray-700">Mainnet Chains</h4>
<h4 className="ml-2 text-gray-800">Mainnet Chains</h4>
</CheckBox>
</div>
{mainnetChainsMetadata.map((c) => (
@ -191,7 +190,7 @@ function ChainMultiSelector({
name={c.name}
>
<div className="py-0.5 ml-2 text-sm flex items-center">
<span className="mr-2">
<span className="mr-2 font-light">
{getChainDisplayName(multiProvider, c.chainId, true)}
</span>
<ChainLogo chainId={c.chainId} size={12} color={false} background={false} />
@ -207,7 +206,7 @@ function ChainMultiSelector({
onToggle={onToggleSection(testnetChainsMetadata)}
name="testnet-chains"
>
<h4 className="ml-2 text-gray-700">Testnet Chains</h4>
<h4 className="ml-2 text-gray-800">Testnet Chains</h4>
</CheckBox>
</div>
{testnetChainsMetadata.map((c) => (
@ -218,7 +217,7 @@ function ChainMultiSelector({
name={c.name}
>
<div className="py-0.5 ml-2 text-sm flex items-center">
<span className="mr-2">
<span className="mr-2 font-light">
{getChainDisplayName(multiProvider, c.chainId, true)}
</span>
<ChainLogo chainId={c.chainId} size={12} color={false} background={false} />
@ -227,12 +226,12 @@ function ChainMultiSelector({
))}
</div>
</div>
<BorderedButton
<SolidButton
classes="mt-2.5 text-sm px-2 py-1 w-full"
onClick={() => onClickApply(closeDropdown)}
>
Apply
</BorderedButton>
</SolidButton>
</div>
)}
modalClasses={`w-88 ${position || 'right-0'}`}
@ -270,33 +269,39 @@ function DatetimeSelector({
<DropdownModal
buttonContent={
<>
<span className="text-gray-700 py-px px-2">Time</span>
<ChevronIcon direction="s" width={9} height={5} classes="ml-2 opacity-80" />
<span className="text-white font-medium py-px px-2">Time</span>
<ChevronIcon
direction="s"
width={9}
height={5}
classes="ml-2 opacity-80"
color={Color.White}
/>
</>
}
buttonClasses="text-sm px-1 sm:px-2.5 py-0.5 flex items-center justify-center rounded border border-gray-500 hover:opacity-70 active:opacity-60 transition-all"
buttonClasses="text-sm px-1 sm:px-2.5 py-0.5 flex items-center justify-center rounded-full bg-pink-500 hover:opacity-80 active:opacity-70 transition-all"
modalContent={(closeDropdown) => (
<div className="p-4" key="date-time-selector">
<div className="flex items-center justify-between">
<h3 className="text-gray-700 text-lg">Time Range</h3>
<h3 className="text-blue-500 font-medium">Time Range</h3>
<div className="flex pt-1">
<TextButton classes="text-sm underline underline-offset-2" onClick={onClickClear}>
<TextButton classes="text-sm font-medium text-pink-500" onClick={onClickClear}>
Clear
</TextButton>
</div>
</div>
<div className="flex flex-col">
<h4 className="mt-3 mb-1 text-gray-700">Start Time</h4>
<h4 className="mt-3 mb-1 text-gray-500 text-sm font-medium">Start Time</h4>
<DatetimeField timestamp={startTime} onChange={setStartTime} />
<h4 className="mt-3 mb-1 text-gray-700">End Time</h4>
<h4 className="mt-3 mb-1 text-gray-500 text-sm font-medium">End Time</h4>
<DatetimeField timestamp={endTime} onChange={setEndTime} />
</div>
<BorderedButton
<SolidButton
classes="mt-4 text-sm px-2 py-1 w-full"
onClick={() => onClickApply(closeDropdown)}
>
Apply
</BorderedButton>
</SolidButton>
</div>
)}
modalClasses="w-60 -right-8"

@ -17,7 +17,7 @@ export function SearchFetching({ show, isPiFetching }: { show: boolean; isPiFetc
<div className="flex items-center justify-center scale-90">
<Spinner />
</div>
<div className="mt-4 text-center leading-loose text-gray-700">
<div className="mt-4 text-center font-light leading-loose text-gray-700">
{isPiFetching ? 'Searching custom chains for messages' : 'Searching for messages'}
</div>
</div>
@ -45,7 +45,7 @@ export function SearchError({
<div className="flex justify-center my-10">
<div className="flex flex-col items-center justify-center max-w-md px-3 py-5">
<Image src={imgSrc} width={imgWidth} className="opacity-80" alt="" />
<div className="mt-4 text-center leading-loose text-gray-700">{text}</div>
<div className="mt-4 text-center font-light leading-loose text-gray-700">{text}</div>
</div>
</div>
</Fade>

@ -57,8 +57,8 @@ export function ConfigureChains() {
return (
<Card>
<h2 className="mt-1 text-xl text-blue-500">Chain Settings</h2>
<p className="mt-3">
<h2 className="mt-1 text-lg text-blue-500 font-medium">Chain Settings</h2>
<p className="mt-3 font-light">
Hyperlane can be deployed to any chain using{' '}
<a
href={`${links.docs}/docs/deploy/permissionless-interoperability`}
@ -70,31 +70,35 @@ export function ConfigureChains() {
</a>
. This explorer can be configured to search for messages on any PI chain.
</p>
<h3 className="mt-4 text-lg text-blue-500">Default Chains</h3>
<h3 className="mt-6 text-lg text-blue-500 font-medium">Default Chains</h3>
<div className="mt-4 flex">
<h4 className="text-gray-600">Mainnets:</h4>
<h4 className="text-gray-600 font-medium text-sm">Mainnets:</h4>
<div className="ml-3 flex gap-3.5 flex-wrap">
{mainnetChainsMetadata.map((c) => (
<div className="shrink-0 text-sm flex items-center" key={c.name}>
<ChainLogo chainId={c.chainId} size={15} color={true} background={false} />
<span className="ml-1.5">{getChainDisplayName(multiProvider, c.chainId, true)}</span>
<span className="ml-1.5 font-light">
{getChainDisplayName(multiProvider, c.chainId, true)}
</span>
</div>
))}
</div>
</div>
<div className="mt-4 flex">
<h4 className="text-gray-600">Testnets:</h4>
<div className="mt-5 flex">
<h4 className="text-gray-600 font-medium text-sm">Testnets:</h4>
<div className="ml-3 flex gap-3.5 flex-wrap">
{testnetChainsMetadata.map((c) => (
<div className="shrink-0 text-sm flex items-center" key={c.name}>
<ChainLogo chainId={c.chainId} size={15} color={true} background={false} />
<div className="ml-1.5">{getChainDisplayName(multiProvider, c.chainId, true)}</div>
<div className="ml-1.5 font-light">
{getChainDisplayName(multiProvider, c.chainId, true)}
</div>
</div>
))}
</div>
</div>
<h3 className="mt-4 text-lg text-blue-500">Custom Chains</h3>
<table className="mt-4 w-full">
<h3 className="mt-6 text-lg text-blue-500 font-medium">Custom Chains</h3>
<table className="mt-2 w-full">
<thead>
<tr>
<th className={styles.header}>Chain</th>
@ -141,7 +145,7 @@ export function ConfigureChains() {
title="Add Custom Chain"
maxWidth="max-w-xl"
>
<p className="mt-2">
<p className="mt-2 font-light">
Input a chain metadata config including core contract addresses to enable exploration of
that chain. See{' '}
<a
@ -156,7 +160,7 @@ export function ConfigureChains() {
</p>
<div className="relative mt-4">
<textarea
className="w-full min-h-[20rem] p-2 border border-gray-400 rounded text-sm focus:outline-none"
className="w-full min-h-[20rem] p-2 border border-gray-400 rounded-xl text-sm font-light focus:outline-none"
placeholder={customChainTextareaPlaceholder}
value={customChainInput}
onChange={onCustomChainInputChange}
@ -165,7 +169,7 @@ export function ConfigureChains() {
copyValue={customChainInput || customChainTextareaPlaceholder}
width={16}
height={16}
classes="absolute top-2 right-2"
classes="absolute top-3 right-3"
/>
</div>
{chainInputErr && <div className="mt-2 text-red-600 text-sm">{chainInputErr}</div>}
@ -197,7 +201,7 @@ const customChainTextareaPlaceholder = `{
`;
const styles = {
header: 'text-sm text-gray-700 font-normal pt-2 pb-1 text-left',
value: 'py-4 text-sm px-1',
valueTruncated: 'py-4 text-sm truncate',
header: 'pt-2 pb-1 text-sm text-gray-700 font-normal text-left',
value: 'py-4 px-1 text-sm font-light',
valueTruncated: 'py-4 text-sm font-light truncate',
};

@ -3,11 +3,12 @@ import { useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import { Spinner } from '../../components/animations/Spinner';
import { Card } from '../../components/layout/Card';
import CheckmarkIcon from '../../images/icons/checkmark-circle.svg';
import { useStore } from '../../store';
import { Message, MessageStatus } from '../../types';
import { logger } from '../../utils/logger';
import { toTitleCase } from '../../utils/string';
import { toTitleCase, trimToLength } from '../../utils/string';
import { getChainDisplayName } from '../chains/utils';
import { useMessageDeliveryStatus } from '../deliveryStatus/useMessageDeliveryStatus';
import { useMultiProvider } from '../providers/multiProvider';
@ -75,7 +76,14 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
pause: !isMessageFound,
});
const { status, originChainId, destinationChainId: destChainId, origin, destination } = message;
const {
msgId,
status,
originChainId,
destinationChainId: destChainId,
origin,
destination,
} = message;
// Mark delivery found to prevent pause queries
useEffect(() => {
@ -87,18 +95,21 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
return (
<>
<div className="flex items-center justify-between px-1">
<h2 className="text-white text-lg">{`${
<Card className="flex items-center justify-between px-1 rounded-full">
<h2 className="text-blue-500 font-medium">{`${
isIcaMsg ? 'ICA ' : ''
} Message to ${getChainDisplayName(multiProvider, destChainId)}`}</h2>
} Message ${trimToLength(msgId, 6)} to ${getChainDisplayName(
multiProvider,
destChainId,
)}`}</h2>
<StatusHeader
messageStatus={status}
isMessageFound={isMessageFound}
isFetching={isFetching}
isError={isError}
/>
</div>
<div className="flex flex-wrap items-stretch justify-between mt-5 gap-3">
</Card>
<div className="flex flex-wrap items-stretch justify-between mt-3 md:mt-4 gap-3 md:gap-4">
<OriginTransactionCard chainId={originChainId} transaction={origin} blur={blur} />
<DestinationTransactionCard
chainId={destChainId}
@ -150,7 +161,7 @@ function StatusHeader({
icon = (
<div className="w-7 h-7 overflow-hidden flex items-center justify-center">
<div className="scale-[35%]">
<Spinner white={true} />
<Spinner />
</div>
</div>
);
@ -163,7 +174,7 @@ function StatusHeader({
return (
<div className="flex items-center">
<h3 className="text-white text-lg mr-3">{text}</h3>
<h3 className="text-blue-500 font-medium lg mr-3">{text}</h3>
{icon}
</div>
);

@ -1,6 +1,7 @@
import { useState } from 'react';
import { Fade } from '../../components/animations/Fade';
import { Card } from '../../components/layout/Card';
import { SearchBar } from '../../components/search/SearchBar';
import { SearchFilterBar } from '../../components/search/SearchFilterBar';
import {
@ -75,9 +76,9 @@ export function MessageSearch() {
isFetching={isAnyFetching}
placeholder="Search by address, hash, or message id"
/>
<div className="relative w-full min-h-[38rem] mt-5 bg-white ring-4 ring-blue-300 rounded-3xl overflow-auto">
<div className="px-2 py-3 sm:px-4 md:px-5 flex items-center justify-between">
<h2 className="w-min sm:w-fit pl-0.5 text-gray-700">
<Card className="relative w-full min-h-[38rem] mt-4" padding="">
<div className="px-2 pt-3.5 pb-3 sm:px-4 md:px-5 flex items-center justify-between">
<h2 className="w-min sm:w-fit pl-0.5 text-blue-500 font-medium">
{!hasInput ? 'Latest Messages' : 'Search Results'}
</h2>
<SearchFilterBar
@ -105,7 +106,7 @@ export function MessageSearch() {
/>
<SearchUnknownError show={isAnyError && isValidInput} />
<SearchInvalidError show={!isValidInput} allowAddress={true} />
</div>
</Card>
</>
);
}

@ -38,7 +38,7 @@ export function MessageTable({
{messageList.map((m) => (
<tr
key={`message-${m.id}`}
className={`cursor-pointer hover:bg-gray-100 active:bg-gray-200 border-b border-gray-100 last:border-0 ${
className={`cursor-pointer hover:bg-pink-50 active:bg-pink-100 border-b border-blue-50 last:border-0 ${
isFetching && 'blur-xs'
} transition-all duration-500`}
>
@ -62,10 +62,10 @@ export function MessageSummaryRow({ message, mp }: { message: MessageStub; mp: M
destination,
} = message;
let statusColor = 'bg-beige-500';
let statusColor = 'bg-blue-50 text-gray-700';
let statusText = 'Pending';
if (status === MessageStatus.Delivered) {
statusColor = 'bg-green-400 text-white';
statusColor = 'bg-[#14825d] text-white';
statusText = 'Delivered';
} else if (status === MessageStatus.Failing) {
statusColor = 'bg-red-500 text-white';
@ -107,7 +107,9 @@ export function MessageSummaryRow({ message, mp }: { message: MessageStub; mp: M
: '-'}
</LinkCell>
<LinkCell id={msgId} base64={base64} aClasses="flex items-center justify-center">
<div className={`text-center w-20 md:w-[5.25rem] py-1.5 text-sm rounded ${statusColor}`}>
<div
className={`text-center w-20 md:w-[5.25rem] py-1.5 text-sm rounded-full ${statusColor}`}
>
{statusText}
</div>
</LinkCell>
@ -134,8 +136,8 @@ function LinkCell({
}
const styles = {
header: 'text-sm text-gray-700 font-normal pt-2 pb-3 text-center',
value: 'py-3.5 flex items-center justify-center text-sm text-center px-1',
valueTruncated: 'py-3.5 flex items-center justify-center text-sm text-center truncate',
chainName: 'text-sm ml-2',
header: 'text-sm text-blue-500 font-medium pt-2 pb-3 text-center',
value: 'py-3.5 flex items-center justify-center text-sm text-center font-light px-1',
valueTruncated: 'py-3.5 flex items-center justify-center text-sm text-center font-light truncate',
chainName: 'text-sm font-light ml-2',
};

@ -67,11 +67,11 @@ export function ContentDetailsCard({
}, [nonce, originDomainId, sender, destinationDomainId, recipient, body]);
return (
<Card classes="w-full space-y-4">
<Card className="w-full space-y-4">
<div className="flex items-center justify-between">
<Image src={EnvelopeInfo} width={28} height={28} alt="" className="opacity-80" />
<div className="flex items-center pb-1">
<h3 className="text-gray-500 font-medium text-md mr-2">Message Details</h3>
<h3 className="text-blue-500 font-medium text-md mr-2">Message Details</h3>
<HelpIcon
size={16}
text="Immutable information about the message itself such as its contents."

@ -69,18 +69,18 @@ export function GasDetailsCard({ message, blur, igpPayments = {} }: Props) {
}, [unit, message, igpPayments]);
return (
<Card classes="w-full space-y-4 relative">
<Card className="w-full space-y-4 relative">
<div className="flex items-center justify-between">
<Image src={FuelPump} width={24} height={24} alt="" className="opacity-80" />
<div className="flex items-center pb-1">
<h3 className="text-gray-500 font-medium text-md mr-2">Interchain Gas Payments</h3>
<h3 className="text-blue-500 font-medium text-md mr-2">Interchain Gas Payments</h3>
<HelpIcon
size={16}
text="Amounts paid to the Interchain Gas Paymaster for message delivery."
/>
</div>
</div>
<p className="text-sm">
<p className="text-sm font-light">
Interchain gas payments are required to fund message delivery on the destination chain.{' '}
<a
href={`${links.docs}/docs/protocol/interchain-gas-payments`}

@ -24,13 +24,13 @@ export function IcaDetailsCard({ message: { originDomainId, body }, blur }: Prop
} = useIcaAddress(originDomainId, decodeResult?.sender);
return (
<Card classes="w-full space-y-4">
<Card className="w-full space-y-4">
<div className="flex items-center justify-between">
<div className="relative -top-px -left-0.5">
<Image src={AccountStar} width={28} height={28} alt="" className="opacity-80" />
</div>
<div className="flex items-center pb-1">
<h3 className="text-gray-500 font-medium text-md mr-2">ICA Details</h3>
<h3 className="text-blue-500 font-medium text-md mr-2">ICA Details</h3>
<HelpIcon size={16} text="Extra information for messages from/to Interchain Accounts." />
</div>
</div>

@ -16,11 +16,11 @@ interface Props {
export function IsmDetailsCard({ ismDetails, blur }: Props) {
return (
<Card classes="w-full space-y-4 relative">
<Card className="w-full space-y-4 relative">
<div className="flex items-center justify-between">
<Image src={ShieldLock} width={24} height={24} alt="" className="opacity-80" />
<div className="flex items-center pb-1">
<h3 className="text-gray-500 font-medium text-md mr-2">Interchain Security Modules</h3>
<h3 className="text-blue-500 font-medium text-md mr-2">Interchain Security Modules</h3>
<HelpIcon
size={16}
text="Details about the Interchain Security Modules (ISM) that must verify this message."

@ -26,7 +26,7 @@ export function KeyValueRow({
}: Props) {
const useFallbackVal = isZeroish(display) && !allowZeroish;
return (
<div className={`flex items-center pl-px ${classes}`}>
<div className={`flex items-center pl-px font-light ${classes}`}>
<label className={`text-sm text-gray-500 ${labelWidth}`}>{label}</label>
<div className={`text-sm ml-1 truncate ${displayWidth || ''} ${blurValue && 'blur-xs'}`}>
<span>{!useFallbackVal ? display : 'Unknown'}</span>

@ -12,12 +12,12 @@ export function TimelineCard({ message, blur }: Props) {
const { stage, timings } = useMessageStage({ message });
return (
<Card classes="w-full">
<Card className="w-full">
{/* <div className="flex items-center justify-end">
<h3 className="text-gray-500 font-medium text-md mr-2">Delivery Timeline</h3>
<HelpIcon size={16} text="A breakdown of the stages for delivering a message" />
</div> */}
<div className={`-mx-2 sm:mx-0 -my-2 ${blur && 'blur-xs'}`}>
<div className={`-mx-2 sm:mx-0 -my-2 font-light ${blur && 'blur-xs'}`}>
<MessageTimeline status={message.status} stage={stage} timings={timings} />
</div>
</Card>

@ -118,13 +118,13 @@ function TransactionCard({
children,
}: PropsWithChildren<{ chainId: ChainId; title: string; helpText: string }>) {
return (
<Card classes="flex flex-col flex-1 min-w-fit space-y-3">
<Card className="flex flex-col flex-1 min-w-fit space-y-3">
<div className="flex items-center justify-between">
<div className="relative -top-px -left-0.5">
<ChainLogo chainId={chainId} />
</div>
<div className="flex items-center pb-1">
<h3 className="text-gray-500 font-medium text-md mr-2">{title}</h3>
<h3 className="text-blue-500 font-medium text-md mr-2">{title}</h3>
<HelpIcon size={16} text={helpText} />
</div>
</div>

@ -15,7 +15,7 @@ import { parseMessageQueryResult, parseMessageStubResult } from '../queries/pars
const SEARCH_AUTO_REFRESH_DELAY = 15000;
const MSG_AUTO_REFRESH_DELAY = 10000;
const LATEST_QUERY_LIMIT = 30;
const LATEST_QUERY_LIMIT = 20;
const SEARCH_QUERY_LIMIT = 50;
export function isValidSearchQuery(input: string, allowAddress?: boolean) {

Before

Width:  |  Height:  |  Size: 245 B

After

Width:  |  Height:  |  Size: 245 B

Before

Width:  |  Height:  |  Size: 194 B

After

Width:  |  Height:  |  Size: 194 B

Before

Width:  |  Height:  |  Size: 199 B

After

Width:  |  Height:  |  Size: 199 B

Before

Width:  |  Height:  |  Size: 454 B

After

Width:  |  Height:  |  Size: 454 B

@ -0,0 +1,4 @@
<svg width="886" height="114" viewBox="0 0 886 114" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M783.5 -3.5C621.953 133.053 158.722 87.2984 8 -3.5" stroke="white" stroke-width="2"/>
<path d="M884.5 -5.5C586 201.5 152.904 88.164 2 -5.5" stroke="white" stroke-width="4"/>
</svg>

After

Width:  |  Height:  |  Size: 290 B

@ -1,5 +0,0 @@
<svg width="117" height="118" viewBox="0 0 117 118" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M64.4787 0H88.4134C91.6788 0 94.6004 1.89614 95.7403 4.7553L116.749 57.4498C116.911 57.8563 116.913 58.3035 116.754 58.7112L116.637 59.014L116.635 59.017L95.7152 112.81C94.5921 115.698 91.6551 117.62 88.3666 117.62H64.4355C63.0897 117.62 62.1465 116.379 62.59 115.192L84.1615 57.4498L62.6428 2.45353C62.1766 1.26188 63.1208 0 64.4787 0Z" fill="white"/>
<path d="M1.99945 0H25.9342C29.1996 0 32.1211 1.89614 33.261 4.7553L54.2696 57.4498C54.4316 57.8563 54.4336 58.3035 54.275 58.7112L54.1573 59.014L54.1561 59.017L33.236 112.81C32.1129 115.698 29.1759 117.62 25.8874 117.62H1.95626C0.610483 117.62 -0.332722 116.379 0.110804 115.192L21.6823 57.4498L0.163626 2.45353C-0.302638 1.26188 0.641544 0 1.99945 0Z" fill="white"/>
<path d="M80.7202 46.2178H46.9324V71.7089H80.7202L86.2411 58.5992L80.7202 46.2178Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 937 B

@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#FFFFFF" class="bi bi-check2-circle" viewBox="0 0 16 16">
<svg xmlns="http://www.w3.org/2000/svg" fill="#2362C1" class="bi bi-check2-circle" viewBox="0 0 16 16">
<path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0z"/>
<path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l7-7z"/>
</svg>

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 346 B

@ -34,7 +34,7 @@ export default function Document() {
<meta property="og:url" content={links.baseUrl} />
<meta property="og:title" content="Hyperlane Explorer" />
<meta property="og:type" content="website" />
<meta property="og:image" content={links.baseUrl + '/logo.png'} />
<meta property="og:image" content={links.baseUrl + '/images/logo.png'} />
<meta
property="og:description"
content="The official interchain explorer for the Hyperlane protocol and network."

@ -6,28 +6,30 @@ const ApiDocs: NextPage = () => {
return (
<div className="mt-4 mb-2 px-2 sm:px-6 lg:pr-14 w-full">
<Card>
<h2 className="mt-1 text-xl text-blue-500">Explorer APIs - Overview and documentation</h2>
<p className="mt-3">
<h2 className="mt-1 text-lg text-blue-500 font-medium">
Explorer APIs - Overview and documentation
</h2>
<p className="mt-3 font-light">
The Explorer REST API provides endpoints to retrieve data about messages.
</p>
<p className="mt-1">
<p className="mt-1 font-light">
The APIs are currently available free of charge and without authentication required.
</p>
<h3 className="mt-4 text-lg text-blue-500">Example Request</h3>
<div className="mt-2 bg-gray-50 rounded p-2.5 text-sm overflow-auto">
<h3 className="mt-5 text-blue-500 font-medium">Example Request</h3>
<div className="mt-2 bg-gray-50 rounded-xl p-2.5 text-sm overflow-auto">
<pre>
<code>{exampleRequest}</code>
</pre>
</div>
<h3 className="mt-4 text-lg text-blue-500">Example Response</h3>
<div className="mt-2 bg-gray-50 rounded p-2.5 text-sm overflow-auto">
<h3 className="mt-5 text-blue-500 font-medium">Example Response</h3>
<div className="mt-2 bg-gray-50 rounded-xl p-2.5 text-sm overflow-auto">
<pre>
<code>{exampleResponse}</code>
</pre>
</div>
<h3 className="mt-4 text-lg text-blue-500">API Reference</h3>
<h3 className="mt-4 font-medium text-blue-500">API Reference</h3>
<h4 className="mt-2 text-gray-600">
Module:<code className="ml-2">message</code>
</h4>
@ -76,7 +78,7 @@ function ParamItem({ name, desc }: { name: string; desc: string }) {
return (
<li>
<code className="mr-2">{name + ':'}</code>
{desc}
<span className="font-light">{desc}</span>
</li>
);
}

@ -1,11 +1,12 @@
// Should match tailwind.config.js
export enum Color {
primaryBlack = '#010101',
primaryWhite = '#FFFFFF',
primaryGray = '#6B7280',
primaryBlue = '#2362C1',
primaryBeige = '#F1EDE9',
primaryRed = '#BF1B15',
Black = '#010101',
White = '#FFFFFF',
Gray = '#6B7280',
Blue = '#2362C1',
Pink = '#D631B9',
Beige = '#F1EDE9',
Red = '#BF1B15',
}
// Useful for cases when using class names isn't convenient
@ -13,11 +14,13 @@ export enum Color {
export function classNameToColor(className) {
switch (className) {
case 'bg-blue-500':
return Color.primaryBlue;
return Color.Blue;
case 'bg-pink-500':
return Color.Pink;
case 'bg-red-500':
return Color.primaryRed;
return Color.Red;
case 'bg-gray-500':
return Color.primaryGray;
return Color.Gray;
default:
throw new Error('Missing color for className: ' + className);
}

@ -43,16 +43,16 @@ module.exports = {
900: '#908E8B',
},
pink: {
50: '#FAEAF7',
100: '#F0C0E8',
200: '#EBABE0',
300: '#E282D1',
400: '#D858C2',
500: '#CF2FB3',
600: '#BA2AA1',
700: '#A5258F',
800: '#90207D',
900: '#7C1C6B',
50: '#FCF2FA',
100: '#F2C1EA',
200: '#EA98DC',
300: '#E26ECE',
400: '#DA45C0',
500: '#D631B9',
600: '#C02CA6',
700: '#952281',
800: '#6B185C',
900: '#400E37',
},
red: {
100: '#EBBAB8',

Loading…
Cancel
Save