From b571920892926486e9f9caa63c6b7d453240ce45 Mon Sep 17 00:00:00 2001 From: evavirseda Date: Wed, 14 Aug 2024 18:01:53 +0200 Subject: [PATCH] feat(wallet): rebrand home - update coin (#1718) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add card compoentn * feat: use constants * feat: update CoinItem component * feat: refine icon * fix build * feat: update icon and images styles * refactor: update iota-sdk name * feat: bring back pinned coins * feat: add clickableAction prop * feat: remove iconSize prop * feat: pass pinned coins to useSortedCoinsByCategories hook * feat: add svg * feat: update icons * feat: minor improvements --------- Co-authored-by: BegoƱa Alvarez --- .../src/hooks/useSortedCoinsByCategories.ts | 18 ++-- apps/ui-icons/src/Pined.tsx | 18 ++++ apps/ui-icons/src/Unpined.tsx | 21 +++++ apps/ui-icons/src/index.ts | 2 + apps/ui-icons/svgs/pined.svg | 3 + apps/ui-icons/svgs/unpined.svg | 3 + .../components/molecules/card/CardBody.tsx | 15 +++- .../components/active-coins-card/CoinItem.tsx | 85 +++++++------------ .../components/active-coins-card/index.tsx | 1 - .../src/ui/app/components/coin-icon/index.tsx | 57 +++---------- .../ui/app/components/iota-apps/IotaApp.tsx | 4 +- .../components/receipt-card/StakeTxnCard.tsx | 1 - .../receipt-card/UnstakeTxnCard.tsx | 1 - .../ui/app/pages/home/tokens/TokenLink.tsx | 8 +- .../app/pages/home/tokens/TokensDetails.tsx | 31 ++++--- .../src/ui/app/shared/image-icon/index.tsx | 38 ++------- .../cards/BalanceChanges.tsx | 2 +- .../transaction-summary/cards/CoinStack.tsx | 2 +- .../app/staking/delegation-detail/index.tsx | 1 - .../src/ui/app/staking/home/StakedCard.tsx | 1 - .../app/staking/stake/ValidatorFormDetail.tsx | 6 +- .../staking/validators/ValidatorListItem.tsx | 1 - .../app/staking/validators/ValidatorLogo.tsx | 4 - 23 files changed, 141 insertions(+), 182 deletions(-) create mode 100644 apps/ui-icons/src/Pined.tsx create mode 100644 apps/ui-icons/src/Unpined.tsx create mode 100644 apps/ui-icons/svgs/pined.svg create mode 100644 apps/ui-icons/svgs/unpined.svg diff --git a/apps/core/src/hooks/useSortedCoinsByCategories.ts b/apps/core/src/hooks/useSortedCoinsByCategories.ts index 0cc4a649f3f..3da245db1fe 100644 --- a/apps/core/src/hooks/useSortedCoinsByCategories.ts +++ b/apps/core/src/hooks/useSortedCoinsByCategories.ts @@ -17,22 +17,20 @@ function sortCoins(balances: CoinBalance[]) { }); } -export function useSortedCoinsByCategories(coinBalances: CoinBalance[]) { +export function useSortedCoinsByCategories( + coinBalances: CoinBalance[], + pinnedCoinTypes?: string[], +) { const recognizedPackages = DEFAULT_RECOGNIZED_PACKAGES; // previous: useRecognizedPackages(); - // Commented out pinnedCoinTypes until https://github.com/iotaledger/iota/issues/832 is resolved - // const [pinnedCoinTypes] = usePinnedCoinTypes(); - return useMemo(() => { const reducedCoinBalances = coinBalances?.reduce( (acc, coinBalance) => { if (recognizedPackages.includes(coinBalance.coinType.split('::')[0])) { acc.recognized.push(coinBalance); - } - // else if (pinnedCoinTypes.includes(coinBalance.coinType)) { - // acc.pinned.push(coinBalance); - // } - else { + } else if (pinnedCoinTypes?.includes(coinBalance.coinType)) { + acc.pinned.push(coinBalance); + } else { acc.unrecognized.push(coinBalance); } return acc; @@ -49,5 +47,5 @@ export function useSortedCoinsByCategories(coinBalances: CoinBalance[]) { pinned: sortCoins(reducedCoinBalances.pinned), unrecognized: sortCoins(reducedCoinBalances.unrecognized), }; - }, [coinBalances, recognizedPackages /*pinnedCoinTypes*/]); + }, [coinBalances, recognizedPackages, pinnedCoinTypes]); } diff --git a/apps/ui-icons/src/Pined.tsx b/apps/ui-icons/src/Pined.tsx new file mode 100644 index 00000000000..7a6b2808487 --- /dev/null +++ b/apps/ui-icons/src/Pined.tsx @@ -0,0 +1,18 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SVGProps } from 'react'; +export default function SvgPined(props: SVGProps) { + return ( + + + + ); +} diff --git a/apps/ui-icons/src/Unpined.tsx b/apps/ui-icons/src/Unpined.tsx new file mode 100644 index 00000000000..a8277bc37f5 --- /dev/null +++ b/apps/ui-icons/src/Unpined.tsx @@ -0,0 +1,21 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SVGProps } from 'react'; +export default function SvgUnpined(props: SVGProps) { + return ( + + + + ); +} diff --git a/apps/ui-icons/src/index.ts b/apps/ui-icons/src/index.ts index e4c60c34bad..68afd21e7ee 100644 --- a/apps/ui-icons/src/index.ts +++ b/apps/ui-icons/src/index.ts @@ -52,6 +52,7 @@ export { default as MoreHoriz } from './MoreHoriz'; export { default as MoreVert } from './MoreVert'; export { default as OutboundLink } from './OutboundLink'; export { default as Person } from './Person'; +export { default as Pined } from './Pined'; export { default as PlaceholderReplace } from './PlaceholderReplace'; export { default as QrCode } from './QrCode'; export { default as RadioOff } from './RadioOff'; @@ -68,6 +69,7 @@ export { default as SwapAccount } from './SwapAccount'; export { default as ThumbUp } from './ThumbUp'; export { default as TriangleDown } from './TriangleDown'; export { default as TriangleUp } from './TriangleUp'; +export { default as Unpined } from './Unpined'; export { default as Vest } from './Vest'; export { default as VisibilityOff } from './VisibilityOff'; export { default as VisibilityOn } from './VisibilityOn'; diff --git a/apps/ui-icons/svgs/pined.svg b/apps/ui-icons/svgs/pined.svg new file mode 100644 index 00000000000..ae03ddf1b57 --- /dev/null +++ b/apps/ui-icons/svgs/pined.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/apps/ui-icons/svgs/unpined.svg b/apps/ui-icons/svgs/unpined.svg new file mode 100644 index 00000000000..bacde0adc12 --- /dev/null +++ b/apps/ui-icons/svgs/unpined.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/apps/ui-kit/src/lib/components/molecules/card/CardBody.tsx b/apps/ui-kit/src/lib/components/molecules/card/CardBody.tsx index 28b5173e7f7..3684cbbbbf3 100644 --- a/apps/ui-kit/src/lib/components/molecules/card/CardBody.tsx +++ b/apps/ui-kit/src/lib/components/molecules/card/CardBody.tsx @@ -4,13 +4,22 @@ export type CardBodyProps = { title: string; subtitle?: string; + clickableAction?: React.ReactNode; }; -export function CardBody({ title, subtitle }: CardBodyProps) { +export function CardBody({ title, subtitle, clickableAction }: CardBodyProps) { + const handleActionCardBodyClick = (event: React.MouseEvent) => { + event?.stopPropagation(); + }; return (
-
- {title} +
+
+ {title} +
+ {clickableAction && ( +
{clickableAction}
+ )}
{subtitle && (
diff --git a/apps/wallet/src/ui/app/components/active-coins-card/CoinItem.tsx b/apps/wallet/src/ui/app/components/active-coins-card/CoinItem.tsx index 0d4b1a8983f..f2e9729b4be 100644 --- a/apps/wallet/src/ui/app/components/active-coins-card/CoinItem.tsx +++ b/apps/wallet/src/ui/app/components/active-coins-card/CoinItem.tsx @@ -2,75 +2,48 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '_app/shared/text'; import { CoinIcon } from '_components/coin-icon'; import { useFormatCoin } from '@iota/core'; import { type ReactNode } from 'react'; +import { + Card, + CardAction, + CardActionType, + CardBody, + CardImage, + CardType, + ImageType, +} from '@iota/apps-ui-kit'; +import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; interface CoinItemProps { coinType: string; balance: bigint; - isActive?: boolean; usd?: number; - centerAction?: ReactNode; - subtitle?: string; + clickableAction?: ReactNode; } -export function CoinItem({ - coinType, - balance, - isActive, - usd, - centerAction, - subtitle, -}: CoinItemProps) { +export function CoinItem({ coinType, balance, usd, clickableAction }: CoinItemProps) { const [formatted, symbol, { data: coinMeta }] = useFormatCoin(balance, coinType); + const isIota = coinType === IOTA_TYPE_ARG; return ( -
- -
-
- - {coinMeta?.name || symbol} {isActive ? 'available' : ''} - - {!isActive && !subtitle ? ( -
- - {symbol} - -
- ) : null} - {subtitle ? ( -
- - {subtitle} - -
- ) : null} + + +
+
- - {centerAction} - -
- {isActive ? ( - - {formatted} - - ) : ( -
- - {formatted} {symbol} - - {usd && ( - - ${usd.toLocaleString('en-US')} - - )} -
- )} -
-
-
+ + + + ); } diff --git a/apps/wallet/src/ui/app/components/active-coins-card/index.tsx b/apps/wallet/src/ui/app/components/active-coins-card/index.tsx index 570af3f5ddb..72bb02a9fb0 100644 --- a/apps/wallet/src/ui/app/components/active-coins-card/index.tsx +++ b/apps/wallet/src/ui/app/components/active-coins-card/index.tsx @@ -50,7 +50,6 @@ export function ActiveCoinsCard({ ) diff --git a/apps/wallet/src/ui/app/components/coin-icon/index.tsx b/apps/wallet/src/ui/app/components/coin-icon/index.tsx index e279e65a592..f3fe96fe135 100644 --- a/apps/wallet/src/ui/app/components/coin-icon/index.tsx +++ b/apps/wallet/src/ui/app/components/coin-icon/index.tsx @@ -4,34 +4,8 @@ import { ImageIcon } from '_app/shared/image-icon'; import { useCoinMetadata } from '@iota/core'; -import { Iota, Unstaked } from '@iota/icons'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; -import { cva, type VariantProps } from 'class-variance-authority'; - -const imageStyle = cva(['rounded-full flex'], { - 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 ', - }, - fill: { - iota: 'bg-iota', - iotaPrimary2023: 'bg-iota-primaryBlue2023', - }, - }, - defaultVariants: { - size: 'md', - fill: 'iotaPrimary2023', - }, -}); - -function IotaCoin() { - return ( - - ); -} +import { IotaLogoMark } from '@iota/ui-icons'; interface NonIotaCoinProps { coinType: string; @@ -40,29 +14,26 @@ interface NonIotaCoinProps { function NonIotaCoin({ coinType }: NonIotaCoinProps) { const { data: coinMeta } = useCoinMetadata(coinType); return ( -
- {coinMeta?.iconUrl ? ( - - ) : ( - - )} +
+
); } -export interface CoinIconProps extends VariantProps { +export interface CoinIconProps { coinType: string; } -export function CoinIcon({ coinType, ...styleProps }: CoinIconProps) { - return ( -
- {coinType === IOTA_TYPE_ARG ? : } +export function CoinIcon({ coinType }: CoinIconProps) { + return coinType === IOTA_TYPE_ARG ? ( +
+
+ ) : ( + ); } diff --git a/apps/wallet/src/ui/app/components/iota-apps/IotaApp.tsx b/apps/wallet/src/ui/app/components/iota-apps/IotaApp.tsx index a60148ad00e..3a050cbfba4 100644 --- a/apps/wallet/src/ui/app/components/iota-apps/IotaApp.tsx +++ b/apps/wallet/src/ui/app/components/iota-apps/IotaApp.tsx @@ -32,7 +32,7 @@ function CardView({ name, link, icon }: CardViewProps) { return (
- +
@@ -59,7 +59,7 @@ interface ListViewProps { function ListView({ name, icon, description, tags }: ListViewProps) { return (
- +
{name} diff --git a/apps/wallet/src/ui/app/components/receipt-card/StakeTxnCard.tsx b/apps/wallet/src/ui/app/components/receipt-card/StakeTxnCard.tsx index 90b6ac28f81..ec7bd92ae8d 100644 --- a/apps/wallet/src/ui/app/components/receipt-card/StakeTxnCard.tsx +++ b/apps/wallet/src/ui/app/components/receipt-card/StakeTxnCard.tsx @@ -60,7 +60,6 @@ export function StakeTxnCard({ event }: StakeTxnCardProps) { diff --git a/apps/wallet/src/ui/app/components/receipt-card/UnstakeTxnCard.tsx b/apps/wallet/src/ui/app/components/receipt-card/UnstakeTxnCard.tsx index 3edcee1ad1f..564e35b2c63 100644 --- a/apps/wallet/src/ui/app/components/receipt-card/UnstakeTxnCard.tsx +++ b/apps/wallet/src/ui/app/components/receipt-card/UnstakeTxnCard.tsx @@ -36,7 +36,6 @@ export function UnStakeTxnCard({ event }: UnStakeTxnCardProps) {
diff --git a/apps/wallet/src/ui/app/pages/home/tokens/TokenLink.tsx b/apps/wallet/src/ui/app/pages/home/tokens/TokenLink.tsx index b4a22910cf4..339cf8f13f0 100644 --- a/apps/wallet/src/ui/app/pages/home/tokens/TokenLink.tsx +++ b/apps/wallet/src/ui/app/pages/home/tokens/TokenLink.tsx @@ -11,11 +11,10 @@ import { Link } from 'react-router-dom'; type TokenLinkProps = { coinBalance: CoinBalance; - centerAction?: ReactNode; - subtitle?: string; + clickableAction?: ReactNode; }; -export function TokenLink({ coinBalance, centerAction, subtitle }: TokenLinkProps) { +export function TokenLink({ coinBalance, clickableAction }: TokenLinkProps) { return ( ); diff --git a/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx b/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx index 6e91b43fce2..3b93bdcf5a4 100644 --- a/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx +++ b/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx @@ -33,13 +33,13 @@ import { useSortedCoinsByCategories, } from '@iota/core'; import { useIotaClientQuery } from '@iota/dapp-kit'; -import { Info12, Pin16, Unpin16 } from '@iota/icons'; +import { Info12 } from '@iota/icons'; import { Network, type CoinBalance as CoinBalanceType } from '@iota/iota-sdk/client'; import { formatAddress, parseStructTag, IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { useQuery } from '@tanstack/react-query'; import clsx from 'clsx'; import { useEffect, useState, type ReactNode } from 'react'; - +import { Unpined, Pined } from '@iota/ui-icons'; import Interstitial, { type InterstitialConfig } from '../interstitial'; import { CoinBalance } from './coin-balance'; import { PortfolioName } from './PortfolioName'; @@ -52,23 +52,27 @@ interface TokenDetailsProps { } interface PinButtonProps { - unpin?: boolean; + isPinned?: boolean; onClick: () => void; } -function PinButton({ unpin, onClick }: PinButtonProps) { +function PinButton({ isPinned, onClick }: PinButtonProps) { return ( ); } @@ -118,7 +122,7 @@ export function TokenRow({ coinBalance, renderActions, onClick }: TokenRowProps) onClick={onClick} >
- +
{coinMeta?.name || symbol} @@ -190,9 +194,9 @@ export function MyTokens({ coinBalances, isLoading, isFetched }: MyTokensProps) const isDefiWalletEnabled = useIsWalletDefiEnabled(); const network = useAppSelector(({ app }) => app.network); - const [_, { pinCoinType, unpinCoinType }] = usePinnedCoinTypes(); + const [_pinned, { pinCoinType, unpinCoinType }] = usePinnedCoinTypes(); - const { recognized, pinned, unrecognized } = useSortedCoinsByCategories(coinBalances); + const { recognized, pinned, unrecognized } = useSortedCoinsByCategories(coinBalances, _pinned); // Avoid perpetual loading state when fetching and retry keeps failing; add isFetched check. const isFirstTimeLoading = isLoading && !isFetched; @@ -221,9 +225,9 @@ export function MyTokens({ coinBalances, isLoading, isFetched }: MyTokensProps) { ampli.unpinnedCoin({ coinType: coinBalance.coinType }); unpinCoinType(coinBalance.coinType); @@ -248,8 +252,7 @@ export function MyTokens({ coinBalances, isLoading, isFetched }: MyTokensProps) { ampli.pinnedCoin({ coinType: coinBalance.coinType }); diff --git a/apps/wallet/src/ui/app/shared/image-icon/index.tsx b/apps/wallet/src/ui/app/shared/image-icon/index.tsx index 6eef7d05d8d..cfb7f90eec8 100644 --- a/apps/wallet/src/ui/app/shared/image-icon/index.tsx +++ b/apps/wallet/src/ui/app/shared/image-icon/index.tsx @@ -2,36 +2,10 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { cva, type VariantProps } from 'class-variance-authority'; import { useState } from 'react'; -const imageStyle = cva( - ['text-white capitalize overflow-hidden bg-gray-40 shrink-0 bg-transparent'], - { - variants: { - size: { - sm: 'w-6 h-6 font-medium text-subtitleSmallExtra', - md: 'w-7.5 h-7.5 font-medium text-body', - lg: 'w-10 h-10 font-medium text-heading4', - xl: 'w-12.5 h-12.5 font-medium text-heading4', - xxl: 'w-15 h-15 font-medium text-heading4', - }, - rounded: { - full: 'rounded-full', - md: 'rounded-md', - lg: 'rounded-lg', - }, - }, - - defaultVariants: { - rounded: 'md', - size: 'md', - }, - }, -); - -export interface ImageIconProps extends VariantProps { - src: string | null; +export interface ImageIconProps { + src: string | null | undefined; label: string; fallback: string; alt?: string; @@ -39,23 +13,23 @@ export interface ImageIconProps extends VariantProps { function FallBackAvatar({ str }: { str: string }) { return ( -
+
{str?.slice(0, 2)}
); } -export function ImageIcon({ src, label, alt = label, fallback, ...styleProps }: ImageIconProps) { +export function ImageIcon({ src, label, alt = label, fallback }: ImageIconProps) { const [error, setError] = useState(false); return ( -
+
{error || !src ? ( ) : ( {alt} setError(true)} /> )} diff --git a/apps/wallet/src/ui/app/shared/transaction-summary/cards/BalanceChanges.tsx b/apps/wallet/src/ui/app/shared/transaction-summary/cards/BalanceChanges.tsx index e6c30fae3a9..2f04b4eafa1 100644 --- a/apps/wallet/src/ui/app/shared/transaction-summary/cards/BalanceChanges.tsx +++ b/apps/wallet/src/ui/app/shared/transaction-summary/cards/BalanceChanges.tsx @@ -32,7 +32,7 @@ function BalanceChangeEntry({ change }: { change: BalanceChange }) {
- +
diff --git a/apps/wallet/src/ui/app/shared/transaction-summary/cards/CoinStack.tsx b/apps/wallet/src/ui/app/shared/transaction-summary/cards/CoinStack.tsx index 61db485486f..d943a7fa396 100644 --- a/apps/wallet/src/ui/app/shared/transaction-summary/cards/CoinStack.tsx +++ b/apps/wallet/src/ui/app/shared/transaction-summary/cards/CoinStack.tsx @@ -22,7 +22,7 @@ export function CoinsStack({ coinTypes }: CoinsStackProps) { )} {coinTypes.slice(0, MAX_COINS_TO_DISPLAY).map((coinType, i) => (
- +
))}
diff --git a/apps/wallet/src/ui/app/staking/delegation-detail/index.tsx b/apps/wallet/src/ui/app/staking/delegation-detail/index.tsx index b9bf5f948ca..024cbd20af7 100644 --- a/apps/wallet/src/ui/app/staking/delegation-detail/index.tsx +++ b/apps/wallet/src/ui/app/staking/delegation-detail/index.tsx @@ -43,7 +43,6 @@ export function DelegationDetail() { diff --git a/apps/wallet/src/ui/app/staking/home/StakedCard.tsx b/apps/wallet/src/ui/app/staking/home/StakedCard.tsx index e07059d1539..1b2d5a4b529 100644 --- a/apps/wallet/src/ui/app/staking/home/StakedCard.tsx +++ b/apps/wallet/src/ui/app/staking/home/StakedCard.tsx @@ -176,7 +176,6 @@ export function StakeCard({ diff --git a/apps/wallet/src/ui/app/staking/stake/ValidatorFormDetail.tsx b/apps/wallet/src/ui/app/staking/stake/ValidatorFormDetail.tsx index 33b45d6adf4..c6b90cf0363 100644 --- a/apps/wallet/src/ui/app/staking/stake/ValidatorFormDetail.tsx +++ b/apps/wallet/src/ui/app/staking/stake/ValidatorFormDetail.tsx @@ -117,11 +117,7 @@ export function ValidatorFormDetail({ validatorAddress, unstake }: ValidatorForm titleDivider header={
- +
} footer={ diff --git a/apps/wallet/src/ui/app/staking/validators/ValidatorListItem.tsx b/apps/wallet/src/ui/app/staking/validators/ValidatorListItem.tsx index a682e1cb657..f1b67a32398 100644 --- a/apps/wallet/src/ui/app/staking/validators/ValidatorListItem.tsx +++ b/apps/wallet/src/ui/app/staking/validators/ValidatorListItem.tsx @@ -40,7 +40,6 @@ export function ValidatorListItem({ selected, value, validatorAddress }: Validat diff --git a/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx b/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx index 003c1b9b335..360048d0f27 100644 --- a/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx +++ b/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx @@ -16,7 +16,6 @@ interface ValidatorLogoProps { stacked?: boolean; isTitle?: boolean; size: 'body' | 'subtitle'; - iconSize: 'sm' | 'md'; showActiveStatus?: boolean; activeEpoch?: string; } @@ -24,7 +23,6 @@ interface ValidatorLogoProps { export function ValidatorLogo({ validatorAddress, showAddress, - iconSize, isTitle, size, stacked, @@ -73,8 +71,6 @@ export function ValidatorLogo({ src={validatorMeta?.imageUrl || null} label={validatorMeta?.name || ''} fallback={validatorMeta?.name || ''} - size={iconSize} - rounded="full" />