Skip to content

Commit

Permalink
fix(explorer/wallet): unify iota token logo (#3554)
Browse files Browse the repository at this point in the history
* fix: iota token logo color

* minor fixes

* fix icon styles and sizes

* fix card bgcolor

* feat: update fallback icons

* polish icon
  • Loading branch information
evavirseda authored Oct 25, 2024
1 parent 92daf53 commit 48a6251
Show file tree
Hide file tree
Showing 15 changed files with 121 additions and 131 deletions.
9 changes: 5 additions & 4 deletions apps/explorer/src/components/IotaTokenCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

import { Panel } from '@iota/apps-ui-kit';
import { COIN_GECKO_IOTA_URL, useIotaCoinData } from '@iota/core';
import { IotaLogoMark } from '@iota/ui-icons';
import { ButtonOrLink } from '~/components/ui';
import { ButtonOrLink, ImageIconSize } from '~/components/ui';
import { CoinIcon } from './owned-coins';
import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';

export function IotaTokenCard(): JSX.Element {
const { data } = useIotaCoinData();
Expand All @@ -22,8 +23,8 @@ export function IotaTokenCard(): JSX.Element {
<ButtonOrLink href={COIN_GECKO_IOTA_URL}>
<Panel>
<div className="flex items-center gap-xs p-md--rs">
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary-30">
<IotaLogoMark className="h-5 w-5 text-white" />
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-shader-neutral-light-8 text-neutral-10">
<CoinIcon coinType={IOTA_TYPE_ARG} size={ImageIconSize.Small} />
</div>
<div className="flex w-full flex-col gap-xxxs">
<span className="font-inter text-title-lg text-neutral-10 dark:text-neutral-92">
Expand Down
74 changes: 24 additions & 50 deletions apps/explorer/src/components/owned-coins/CoinIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,43 @@
// SPDX-License-Identifier: Apache-2.0

import { useCoinMetadata } from '@iota/core';
import { IotaLogoMark as Iota, Unstake } from '@iota/ui-icons';
import { IotaLogoMark } from '@iota/ui-icons';
import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
import { cva, type VariantProps } from 'class-variance-authority';
import { cx } from 'class-variance-authority';
import { ImageIcon, ImageIconSize } from '../ui';

import { ImageIcon } from '~/components/ui';

const imageStyle = cva(['flex rounded-2xl'], {
variants: {
size: {
sm: 'w-6 h-6',
md: 'w-7.5 h-7.5',
lg: 'md:w-10 md:h-10 w-8 h-8',
xl: 'md:w-31.5 md:h-31.5 w-16 h-16 ',
},
},
defaultVariants: {
size: 'md',
},
});

function IotaCoin(): JSX.Element {
return (
<Iota className="flex h-full w-full rounded-2xl p-xxxs text-neutral-0 dark:text-neutral-100" />
);
}

interface NonIotaCoinProps extends VariantProps<typeof imageStyle> {
interface NonIotaCoinProps {
coinType: string;
size?: ImageIconSize;
rounded?: boolean;
}

function NonIotaCoin({ coinType, ...styleProps }: NonIotaCoinProps): JSX.Element {
function NonIotaCoin({ coinType, size = ImageIconSize.Full, rounded }: NonIotaCoinProps) {
const { data: coinMeta } = useCoinMetadata(coinType);
return (
<div className="flex h-full w-full items-center justify-center rounded-2xl">
{coinMeta?.iconUrl ? (
<ImageIcon
size={styleProps.size}
src={coinMeta.iconUrl}
label={coinMeta.name || coinType}
fallback={coinMeta.name || coinType}
circle
/>
) : (
<div className="flex h-full w-full items-center justify-center rounded-2xl">
<Unstake className="h-2.5 w-2.5" />
</div>
)}
<div className="flex h-full w-full items-center justify-center rounded-full bg-neutral-96 dark:bg-neutral-92">
<ImageIcon
src={coinMeta?.iconUrl}
label={coinMeta?.name || coinType}
fallback={coinMeta?.name || coinType}
size={size}
rounded={rounded}
/>
</div>
);
}

interface CoinIconProps extends VariantProps<typeof imageStyle> {
export interface CoinIconProps {
coinType: string;
size?: ImageIconSize;
rounded?: boolean;
}

export function CoinIcon({ coinType, ...styleProps }: CoinIconProps): JSX.Element {
return (
<div className={imageStyle(styleProps)}>
{coinType === IOTA_TYPE_ARG ? (
<IotaCoin />
) : (
<NonIotaCoin coinType={coinType} size={styleProps.size} />
)}
export function CoinIcon({ coinType, size = ImageIconSize.Full, rounded }: CoinIconProps) {
return coinType === IOTA_TYPE_ARG ? (
<div className={cx(size)}>
<IotaLogoMark className="h-full w-full" />
</div>
) : (
<NonIotaCoin rounded={rounded} size={size} coinType={coinType} />
);
}
5 changes: 3 additions & 2 deletions apps/explorer/src/components/owned-coins/OwnedCoinView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ImageType,
} from '@iota/apps-ui-kit';
import { ArrowUp, RecognizedBadge } from '@iota/ui-icons';
import { ImageIconSize } from '../ui';

type OwnedCoinViewProps = {
coin: CoinBalanceVerified;
Expand All @@ -45,8 +46,8 @@ export default function OwnedCoinView({ coin, id }: OwnedCoinViewProps): JSX.Ele
>
<Card onClick={() => setAreCoinDetailsOpen((prev) => !prev)}>
<CardImage type={ImageType.Placeholder}>
<div className="rounded-full border border-shader-neutral-light-8 dark:border-shader-neutral-dark-8">
<CoinIcon coinType={coin.coinType} size="lg" />
<div className="flex h-10 w-10 items-center justify-center rounded-full border border-shader-neutral-light-8 text-neutral-10">
<CoinIcon coinType={coin.coinType} size={ImageIconSize.Small} />
</div>
</CardImage>
<CardBody {...CARD_BODY} isTextTruncated />
Expand Down
84 changes: 45 additions & 39 deletions apps/explorer/src/components/ui/ImageIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,71 @@
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { cva, type VariantProps } from 'class-variance-authority';
import { useState } from 'react';
import cn from 'clsx';

const imageStyle = cva(['text-white capitalize overflow-hidden bg-gray-40'], {
variants: {
size: {
sm: 'w-6 h-6 font-medium text-subtitleSmallExtra',
md: 'w-8 h-8 text-label-lg',
lg: 'md:w-10 md:h-10 w-8 h-8',
xl: 'md:w-31.5 md:h-31.5 w-16 h-16 font-medium text-heading4 md:text-iconTextLarge',
},
circle: {
true: 'rounded-full',
false: 'rounded-md',
},
},

defaultVariants: {
circle: false,
size: 'md',
},
});
export enum ImageIconSize {
Small = 'w-5 h-5',
Medium = 'w-8 h-8',
Large = 'w-10 h-10',
Full = 'w-full h-full',
}

export interface ImageIconProps extends VariantProps<typeof imageStyle> {
src?: string | null;
export interface ImageIconProps {
src: string | null | undefined;
label: string;
fallback: string;
alt?: string;
rounded?: boolean;
size?: ImageIconSize;
}

interface FallBackAvatarProps {
fallback: string;
}

function FallBackAvatar({ fallback }: FallBackAvatarProps): JSX.Element {
function FallBackAvatar({
str,
rounded,
size = ImageIconSize.Large,
}: {
str: string;
rounded?: boolean;
size?: ImageIconSize;
}) {
function generateTextSize(size: ImageIconSize) {
switch (size) {
case ImageIconSize.Small:
return 'text-label-sm';
case ImageIconSize.Medium:
return 'text-label-md';
case ImageIconSize.Large:
return 'text-title-lg';
case ImageIconSize.Full:
return 'text-display-lg';
}
}
return (
<div className="flex h-full w-full items-center justify-center bg-neutral-90 text-neutral-10">
{fallback?.slice(0, 2)}
<div
className={cn(
'flex items-center justify-center bg-neutral-96 bg-gradient-to-r capitalize text-neutral-10 dark:bg-neutral-92 dark:text-primary-100',
{ 'rounded-full': rounded, 'rounded-lg': !rounded },
size,
generateTextSize(size),
)}
>
{str?.slice(0, 2)}
</div>
);
}

export function ImageIcon({
src,
label,
alt = label,
fallback,
...styleProps
}: ImageIconProps): JSX.Element {
export function ImageIcon({ src, label, alt = label, fallback, rounded, size }: ImageIconProps) {
const [error, setError] = useState(false);
return (
<div role="img" className={imageStyle(styleProps)} aria-label={label}>
<div role="img" aria-label={label} className={size}>
{error || !src ? (
<FallBackAvatar fallback={fallback} />
<FallBackAvatar rounded={rounded} str={fallback} size={size} />
) : (
<img
src={src}
alt={alt}
className="flex h-full w-full items-center justify-center object-cover"
className="flex h-full w-full items-center justify-center rounded-full object-cover"
onError={() => setError(true)}
/>
)}
Expand Down
16 changes: 9 additions & 7 deletions apps/explorer/src/components/validator/ValidatorMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Badge, BadgeType, KeyValueInfo, Panel } from '@iota/apps-ui-kit';
import { type IotaValidatorSummary } from '@iota/iota-sdk/client';
import toast from 'react-hot-toast';
import { ArrowTopRight } from '@iota/ui-icons';
import { AddressLink, ImageIcon } from '~/components/ui';
import { AddressLink, ImageIcon, ImageIconSize } from '~/components/ui';

type ValidatorMetaProps = {
validatorData: IotaValidatorSummary;
Expand All @@ -28,12 +28,14 @@ export function ValidatorMeta({ validatorData }: ValidatorMetaProps): JSX.Elemen
<Panel>
<div className="flex flex-col gap-lg p-md--rs md:flex-row">
<div className="flex flex-row gap-lg">
<ImageIcon
src={logo}
label={validatorName}
fallback={validatorName}
size="xl"
/>
<div className="flex h-[120px] w-[120px]">
<ImageIcon
src={logo}
label={validatorName}
fallback={validatorName}
size={ImageIconSize.Full}
/>
</div>
<div className="flex flex-col gap-y-sm">
<div>
<Badge type={BadgeType.Neutral} label="Validator" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import { Badge, BadgeType, TableCellBase, TableCellText } from '@iota/apps-ui-kit';
import type { ColumnDef } from '@tanstack/react-table';
import { type ApyByValidator, formatPercentageDisplay } from '@iota/core';

import { ampli, getValidatorMoveEvent, VALIDATOR_LOW_STAKE_GRACE_PERIOD } from '~/lib';
import { StakeColumn, ValidatorLink, ImageIcon } from '~/components';
import { StakeColumn } from '~/components';
import type { IotaEvent, IotaValidatorSummary } from '@iota/iota-sdk/dist/cjs/client';
import clsx from 'clsx';
import { ImageIcon, ImageIconSize, ValidatorLink } from '~/components/ui';

interface generateValidatorsTableColumnsArgs {
atRiskValidators: [string, string][];
Expand Down Expand Up @@ -41,7 +41,7 @@ function ValidatorWithImage({
<div className="flex items-center gap-x-2.5 text-neutral-40 dark:text-neutral-60">
<ImageIcon
src={validator.imageUrl}
size="sm"
size={ImageIconSize.Medium}
label={validator.name}
fallback={validator.name}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from '@iota/core';
import { RecognizedBadge } from '@iota/ui-icons';
import { useMemo } from 'react';
import { CoinIcon } from '~/components';
import { CoinIcon, ImageIconSize } from '~/components';
import { AddressLink, CollapsibleCard } from '~/components/ui';
import { BREAK_POINT, useMediaQuery } from '~/hooks';

Expand All @@ -49,7 +49,7 @@ function BalanceChangeEntry({ change }: { change: BalanceChange }): JSX.Element
<div className="flex flex-col gap-xs">
<Card type={CardType.Filled}>
<CardImage type={ImageType.BgTransparent}>
<CoinIcon coinType={coinType} />
<CoinIcon coinType={coinType} size={ImageIconSize.Small} />
</CardImage>
<CardBody
title={coinMetaData?.name || symbol}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ export const CARD_TYPE_CLASSES: Record<CardType, string> = {
[CardType.Default]: 'border border-transparent',
[CardType.Outlined]:
'border border-shader-neutral-light-8 dark:border-shader-primary-dark-8 p-xs',
[CardType.Filled]: 'border border-transparent bg-shader-neutral-light-8 p-xs',
[CardType.Filled]: 'border border-transparent bg-neutral-96 dark:bg-neutral-10 p-xs',
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
ImageType,
} from '@iota/apps-ui-kit';
import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
import { ImageIconSize } from '../../shared/image-icon';

interface CoinItemProps {
coinType: string;
Expand All @@ -32,7 +33,7 @@ export function CoinItem({ coinType, balance, usd, clickableAction, icon }: Coin
<Card type={CardType.Default}>
<CardImage type={ImageType.BgTransparent}>
<div className="flex h-10 w-10 items-center justify-center rounded-full border border-shader-neutral-light-8 text-neutral-10">
<CoinIcon coinType={coinType} rounded />
<CoinIcon coinType={coinType} rounded size={ImageIconSize.Small} />
</div>
</CardImage>
<CardBody
Expand Down
2 changes: 1 addition & 1 deletion apps/wallet/src/ui/app/components/coin-icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface NonIotaCoinProps {
function NonIotaCoin({ coinType, size = ImageIconSize.Full, rounded }: NonIotaCoinProps) {
const { data: coinMeta } = useCoinMetadata(coinType);
return (
<div className="flex h-full w-full items-center justify-center rounded-full">
<div className="flex h-full w-full items-center justify-center rounded-full bg-neutral-96 dark:bg-neutral-92">
<ImageIcon
src={coinMeta?.iconUrl}
label={coinMeta?.name || coinType}
Expand Down
7 changes: 1 addition & 6 deletions apps/wallet/src/ui/app/components/receipt-card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
LoadingIndicator,
} from '@iota/apps-ui-kit';
import { ArrowTopRight, CheckmarkFilled } from '@iota/ui-icons';
import cl from 'clsx';
import { GasFees } from '../../pages/approval-request/transaction-request/GasFees';
import ExplorerLink, { ExplorerLinkType } from '../explorer-link';

Expand All @@ -40,11 +39,7 @@ function TransactionStatus({ success, timestamp }: TransactionStatusProps) {
style={InfoBoxStyle.Elevated}
title={success ? 'Successfully sent' : 'Transaction Failed'}
supportingText={timestamp ? txnDate : ''}
icon={
<CheckmarkFilled
className={cl('h-5 w-5', success ? 'text-primary-30' : 'text-neutral-10')}
/>
}
icon={<CheckmarkFilled />}
></InfoBox>
);
}
Expand Down
Loading

0 comments on commit 48a6251

Please sign in to comment.