From 4e7773017e1c05e191fac09e34529b656bf99311 Mon Sep 17 00:00:00 2001 From: plam-ml <127577476+plam-ml@users.noreply.github.com> Date: Wed, 26 Jul 2023 13:48:03 -0700 Subject: [PATCH] [Explorer]: update TXN page header (#13105) ## Description https://mysten.atlassian.net/browse/APPS-1484 ![txn-ok](https://github.com/MystenLabs/sui/assets/127577476/2f5743dd-9c7c-4552-9dbb-048eb64c19e4) ![txn-error](https://github.com/MystenLabs/sui/assets/127577476/273f7246-c799-4c4e-852a-a5070c80fac8) ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes --- apps/core/tailwind.config.ts | 12 ++- .../src/components/Layout/PageLayout.tsx | 65 +++++++++---- apps/explorer/src/pages/home/Home.tsx | 51 +++++----- .../transaction-result/TransactionResult.tsx | 36 +++++++ .../transaction-result/TransactionView.tsx | 65 +++++-------- apps/explorer/src/ui/Banner.tsx | 2 +- apps/explorer/src/ui/Card.tsx | 2 +- apps/explorer/src/ui/CopyToClipboard.tsx | 6 +- apps/explorer/src/ui/PageHeader.tsx | 93 +++++++++---------- apps/explorer/src/ui/StatusIcon.tsx | 21 +++++ apps/icons/src/Copy24.tsx | 29 ++++++ apps/icons/src/ThumbDownFill12.tsx | 26 ++++++ apps/icons/src/ThumbUpFill12.tsx | 26 ++++++ apps/icons/src/index.ts | 3 + apps/icons/svgs/copy_24.svg | 4 + apps/icons/svgs/thumb_down_fill_12.svg | 10 ++ apps/icons/svgs/thumb_up_fill_12.svg | 10 ++ apps/ui/src/Heading.tsx | 4 +- 18 files changed, 322 insertions(+), 143 deletions(-) create mode 100644 apps/explorer/src/ui/StatusIcon.tsx create mode 100644 apps/icons/src/Copy24.tsx create mode 100644 apps/icons/src/ThumbDownFill12.tsx create mode 100644 apps/icons/src/ThumbUpFill12.tsx create mode 100644 apps/icons/svgs/copy_24.svg create mode 100644 apps/icons/svgs/thumb_down_fill_12.svg create mode 100644 apps/icons/svgs/thumb_up_fill_12.svg diff --git a/apps/core/tailwind.config.ts b/apps/core/tailwind.config.ts index 7b09a7b26dfc8..afbd7aa83c174 100644 --- a/apps/core/tailwind.config.ts +++ b/apps/core/tailwind.config.ts @@ -85,7 +85,8 @@ export default { colors: { 'gradient-blue-start': '#589AEA', 'gradient-blue-end': '#4C75A6', - 'gradient-graph-bg-01-start': '#D2EBFA', + 'gradients-graph-cards-start': '#D2EBFA', + 'gradients-failure-start': '#FBF0FF', }, // Line-heights that are found in the design: lineHeight: { @@ -105,6 +106,7 @@ export default { drop: '0px 0px 10px rgba(111, 188, 240, 0.2)', mistyEdge: '0px 0px 0px 1px rgba(160, 182, 195, 0.08), 0px 5px 30px 0px rgba(86, 104, 115, 0.20)', + cardSoft: '1px 2px 8px 2px rgba(21, 82, 123, 0.05)', }, fontSize: { // Text sizes: @@ -152,6 +154,9 @@ export default { 3.75: '0.9375rem', 4.5: '1.125rem', 7.5: '1.875rem', + 17: '4.25rem', + 18: '4.5rem', + 19: '4.75rem', 50: '12.5rem', verticalListShort: '13.0625rem', verticalListLong: '35.6875rem', @@ -166,6 +171,8 @@ export default { walletLogo: '4.813rem', }, minWidth: { + 10: '2.5rem', + 18: '4.5rem', transactionColumn: '31.875rem', }, transitionTimingFunction: { @@ -179,7 +186,8 @@ export default { placeholderGradient01: 'linear-gradient(165.96deg, #e6f5ff 10%, #ebecff 95%)', placeholderShimmer: 'linear-gradient(90deg, #ecf1f4 -24.18%, rgba(237 242 245 / 40%) 73.61%, #f3f7f9 114.81%, #ecf1f4 114.82%)', - main: 'linear-gradient(176deg, #D2EBFA 51.68%, #D5F7EE 100%)', + 'gradients-graph-cards': 'linear-gradient(176deg, #D2EBFA 51.68%, #D5F7EE 100%)', + 'gradients-failure': 'linear-gradient(166deg, #FBF0FF 0%, #FFF0F0 100%)', }, rotate: { 135: '135deg', diff --git a/apps/explorer/src/components/Layout/PageLayout.tsx b/apps/explorer/src/components/Layout/PageLayout.tsx index 5033a9475e08a..0f9c450101058 100644 --- a/apps/explorer/src/components/Layout/PageLayout.tsx +++ b/apps/explorer/src/components/Layout/PageLayout.tsx @@ -13,11 +13,16 @@ import { Banner } from '~/ui/Banner'; import { Network } from '~/utils/api/DefaultRpcClient'; export type PageLayoutProps = { - gradientContent?: ReactNode; + gradient?: { + content: ReactNode; + size: 'lg' | 'md'; + type?: 'success' | 'error'; + }; content: ReactNode; + error?: string; }; -export function PageLayout({ gradientContent, content }: PageLayoutProps) { +export function PageLayout({ gradient, content }: PageLayoutProps) { const [network] = useNetworkContext(); const { request } = useAppsBackend(); const { data } = useQuery({ @@ -31,33 +36,53 @@ export function PageLayout({ gradientContent, content }: PageLayoutProps) { retry: false, enabled: network === Network.MAINNET, }); - const isGradientVisible = !!gradientContent; + const isGradientVisible = !!gradient; + const isError = gradient?.type === 'error'; + return ( -
+
- {network === Network.MAINNET && data?.degraded && ( -
-
- - We’re sorry that the explorer is running slower than usual. We’re - working to fix the issue and appreciate your patience. - -
-
- )} {isGradientVisible ? ( -
-
- {gradientContent} +
+ {network === Network.MAINNET && data?.degraded && ( +
+
+ + We’re sorry that the explorer is running slower than usual. We’re + working to fix the issue and appreciate your patience. + +
+
+ )} +
+ {gradient.content}
) : null} -
- {content} -
+
{content}
); } + +//mx-auto max-w-[1440px] px-5 py-8 md:p-10 diff --git a/apps/explorer/src/pages/home/Home.tsx b/apps/explorer/src/pages/home/Home.tsx index 73ccb26ae010d..5491a7a00bdcb 100644 --- a/apps/explorer/src/pages/home/Home.tsx +++ b/apps/explorer/src/pages/home/Home.tsx @@ -4,15 +4,15 @@ import clsx from 'clsx'; import { lazy, Suspense } from 'react'; -import { ErrorBoundary } from '../../components/error-boundary/ErrorBoundary'; -import { TopValidatorsCard } from '../../components/top-validators-card/TopValidatorsCard'; import { AccountsCardGraph } from '~/components/AccountCardGraph'; import { Activity } from '~/components/Activity'; import { CurrentEpoch, OnTheNetwork } from '~/components/HomeMetrics'; import { PageLayout } from '~/components/Layout/PageLayout'; import { SuiTokenCard } from '~/components/SuiTokenCard'; import { TransactionsCardGraph } from '~/components/TransactionsCardGraph'; +import { ErrorBoundary } from '~/components/error-boundary/ErrorBoundary'; import { TopPackagesCard } from '~/components/top-packages/TopPackagesCard'; +import { TopValidatorsCard } from '~/components/top-validators-card/TopValidatorsCard'; import { useNetwork } from '~/context'; import { Card } from '~/ui/Card'; import { TabHeader } from '~/ui/Tabs'; @@ -27,30 +27,33 @@ function Home() { const isSuiTokenCardEnabled = network === Network.MAINNET; return ( -
- -
-
- -
- {isSuiTokenCardEnabled ? ( -
- + gradient={{ + content: ( +
+
+ +
+
+ +
+ {isSuiTokenCardEnabled ? ( +
+ +
+ ) : null} +
+ +
+
+
- ) : null} -
- -
-
-
-
- } + ), + size: 'lg', + }} content={
diff --git a/apps/explorer/src/pages/transaction-result/TransactionResult.tsx b/apps/explorer/src/pages/transaction-result/TransactionResult.tsx index dc09a8683f79c..56703c4b5d7bc 100644 --- a/apps/explorer/src/pages/transaction-result/TransactionResult.tsx +++ b/apps/explorer/src/pages/transaction-result/TransactionResult.tsx @@ -1,6 +1,7 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +import { getExecutionStatusError, type SuiTransactionBlockResponse } from '@mysten/sui.js'; import { LoadingIndicator } from '@mysten/ui'; import { useParams } from 'react-router-dom'; @@ -8,12 +9,47 @@ import { TransactionView } from './TransactionView'; import { PageLayout } from '~/components/Layout/PageLayout'; import { useGetTransaction } from '~/hooks/useGetTransaction'; import { Banner } from '~/ui/Banner'; +import { PageHeader } from '~/ui/PageHeader'; +import { StatusIcon } from '~/ui/StatusIcon'; + +function TransactionResultPageHeader({ + transaction, + error, +}: { + transaction: SuiTransactionBlockResponse; + error?: string; +}) { + const txnKindName = transaction.transaction?.data.transaction?.kind; + const txnDigest = transaction.digest; + const txnStatus = transaction.effects?.status.status; + + const isProgrammableTransaction = txnKindName === 'ProgrammableTransaction'; + + return ( + } + /> + ); +} export default function TransactionResult() { const { id } = useParams(); const { isLoading, isError, data } = useGetTransaction(id as string); + const txError = data ? getExecutionStatusError(data) : undefined; + return ( , + size: 'md', + type: txError ? 'error' : 'success', + } + } content={ isLoading ? ( diff --git a/apps/explorer/src/pages/transaction-result/TransactionView.tsx b/apps/explorer/src/pages/transaction-result/TransactionView.tsx index ecbeaa6d09242..942009d057ebf 100644 --- a/apps/explorer/src/pages/transaction-result/TransactionView.tsx +++ b/apps/explorer/src/pages/transaction-result/TransactionView.tsx @@ -1,15 +1,9 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -import { - getExecutionStatusError, - getExecutionStatusType, - getTransactionDigest, - getTransactionKind, - getTransactionKindName, - type SuiTransactionBlockResponse, -} from '@mysten/sui.js'; +import { type SuiTransactionBlockResponse } from '@mysten/sui.js'; import clsx from 'clsx'; +import { type ReactNode } from 'react'; import { Signatures } from './Signatures'; import { ErrorBoundary } from '~/components/error-boundary/ErrorBoundary'; @@ -17,21 +11,25 @@ import { useBreakpoint } from '~/hooks/useBreakpoint'; import { Events } from '~/pages/transaction-result/Events'; import { TransactionData } from '~/pages/transaction-result/TransactionData'; import { TransactionSummary } from '~/pages/transaction-result/transaction-summary'; -import { Banner } from '~/ui/Banner'; -import { PageHeader } from '~/ui/PageHeader'; import { SplitPanes } from '~/ui/SplitPanes'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '~/ui/Tabs'; import styles from './TransactionResult.module.css'; +function TabsContentContainer({ value, children }: { value: string; children: ReactNode }) { + return ( + +
{children}
+
+ ); +} + export function TransactionView({ transaction }: { transaction: SuiTransactionBlockResponse }) { const isMediumOrAbove = useBreakpoint('md'); const hasEvents = !!transaction.events?.length; - const txError = getExecutionStatusError(transaction); - - const transactionKindName = getTransactionKindName(getTransactionKind(transaction)!); + const transactionKindName = transaction.transaction?.data.transaction?.kind; const isProgrammableTransaction = transactionKindName === 'ProgrammableTransaction'; @@ -44,25 +42,19 @@ export function TransactionView({ transaction }: { transaction: SuiTransactionBl {hasEvents && Events} {isProgrammableTransaction && Signatures} - -
- -
-
+ + + {hasEvents && ( - -
- -
-
+ + + )} - -
- - - -
-
+ + + + +
), @@ -84,19 +76,6 @@ export function TransactionView({ transaction }: { transaction: SuiTransactionBl return (
-
- - {txError && ( -
- {txError} -
- )} -
> = { Transaction: 'Transaction Block', }; -const TYPE_TO_ICON: Record = { - Transaction: CallIcon, +const TYPE_TO_ICON: Record = { + Transaction: null, Checkpoint: Flag16, Object: Nft16, Package: CallIcon, - Address: () => ( - - ), + Address: null, }; -const STATUS_TO_TEXT = { - success: 'Success', - failure: 'Failure', -}; - -export function PageHeader({ title, subtitle, type, status }: PageHeaderProps) { +export function PageHeader({ title, subtitle, type, before, error }: PageHeaderProps) { const Icon = TYPE_TO_ICON[type]; return ( -
-
- {Icon && } - - {type in TYPE_TO_COPY ? TYPE_TO_COPY[type] : type} - -
-
-
-
- - {title} - +
+
+ {before &&
{before}
} +
+
+
+
+ {Icon && } + + {type in TYPE_TO_COPY ? TYPE_TO_COPY[type] : type} + +
+
+ + {title} + +
+ {subtitle && ( +
+ + {subtitle} + +
+ )} +
+
+ +
- + {error && ( +
+ }> + + {error} + + +
+ )}
- - {status && ( -
- {STATUS_TO_TEXT[status]} -
- )}
- {subtitle && ( -
- - {subtitle} - -
- )}
); } diff --git a/apps/explorer/src/ui/StatusIcon.tsx b/apps/explorer/src/ui/StatusIcon.tsx new file mode 100644 index 0000000000000..8474186a67e78 --- /dev/null +++ b/apps/explorer/src/ui/StatusIcon.tsx @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +import { ThumbUpFill24, ThumbDownFill24 } from '@mysten/icons'; +import clsx from 'clsx'; + +export function StatusIcon({ success }: { success: boolean }) { + const Icon = success ? ThumbUpFill24 : ThumbDownFill24; + + return ( +
+
+ +
+
+ ); +} diff --git a/apps/icons/src/Copy24.tsx b/apps/icons/src/Copy24.tsx new file mode 100644 index 0000000000000..fd30ed86a0a2b --- /dev/null +++ b/apps/icons/src/Copy24.tsx @@ -0,0 +1,29 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgCopy24 = (props: SVGProps) => ( + + + + +); +export default SvgCopy24; diff --git a/apps/icons/src/ThumbDownFill12.tsx b/apps/icons/src/ThumbDownFill12.tsx new file mode 100644 index 0000000000000..de748a865c4b4 --- /dev/null +++ b/apps/icons/src/ThumbDownFill12.tsx @@ -0,0 +1,26 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgThumbDownFill12 = (props: SVGProps) => ( + + + + + + + + + + +); +export default SvgThumbDownFill12; diff --git a/apps/icons/src/ThumbUpFill12.tsx b/apps/icons/src/ThumbUpFill12.tsx new file mode 100644 index 0000000000000..e9fa6b761877b --- /dev/null +++ b/apps/icons/src/ThumbUpFill12.tsx @@ -0,0 +1,26 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgThumbUpFill12 = (props: SVGProps) => ( + + + + + + + + + + +); +export default SvgThumbUpFill12; diff --git a/apps/icons/src/index.ts b/apps/icons/src/index.ts index ce731f06de312..477c2a3f974c8 100644 --- a/apps/icons/src/index.ts +++ b/apps/icons/src/index.ts @@ -57,6 +57,7 @@ export { default as Coins24 } from './Coins24'; export { default as Copy12 } from './Copy12'; export { default as Copy16 } from './Copy16'; export { default as Copy18 } from './Copy18'; +export { default as Copy24 } from './Copy24'; export { default as CopyArchiveDoNotUse16 } from './CopyArchiveDoNotUse16'; export { default as CopyArchiveDoNotUse24 } from './CopyArchiveDoNotUse24'; export { default as CopyNew24 } from './CopyNew24'; @@ -139,10 +140,12 @@ export { default as SuiTestnet } from './SuiTestnet'; export { default as Support24 } from './Support24'; export { default as Swap16 } from './Swap16'; export { default as Tag16 } from './Tag16'; +export { default as ThumbDownFill12 } from './ThumbDownFill12'; export { default as ThumbDownFill24 } from './ThumbDownFill24'; export { default as ThumbDownFill32 } from './ThumbDownFill32'; export { default as ThumbDownStroke24 } from './ThumbDownStroke24'; export { default as ThumbDownStroke32 } from './ThumbDownStroke32'; +export { default as ThumbUpFill12 } from './ThumbUpFill12'; export { default as ThumbUpFill24 } from './ThumbUpFill24'; export { default as ThumbUpFill32 } from './ThumbUpFill32'; export { default as ThumbUpStroke24 } from './ThumbUpStroke24'; diff --git a/apps/icons/svgs/copy_24.svg b/apps/icons/svgs/copy_24.svg new file mode 100644 index 0000000000000..3f39e4e178026 --- /dev/null +++ b/apps/icons/svgs/copy_24.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/icons/svgs/thumb_down_fill_12.svg b/apps/icons/svgs/thumb_down_fill_12.svg new file mode 100644 index 0000000000000..212cdf422bff9 --- /dev/null +++ b/apps/icons/svgs/thumb_down_fill_12.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/icons/svgs/thumb_up_fill_12.svg b/apps/icons/svgs/thumb_up_fill_12.svg new file mode 100644 index 0000000000000..26fc9a1c66991 --- /dev/null +++ b/apps/icons/svgs/thumb_up_fill_12.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/ui/src/Heading.tsx b/apps/ui/src/Heading.tsx index 673aa2c077c86..790f209d51e0a 100644 --- a/apps/ui/src/Heading.tsx +++ b/apps/ui/src/Heading.tsx @@ -16,10 +16,10 @@ const headingStyles = cva([], { size: { heading1: 'text-heading1', heading2: 'md:text-heading2 text-heading4', - heading3: 'text-heading3', + heading3: 'md:text-heading3 text-heading6', heading4: 'md:text-heading4 text-heading6', heading5: 'text-heading5', - heading6: 'text-heading6', + heading6: 'md:text-heading6 text-body', }, color: { issue: 'text-issue',