From 2db23bf9adf992ab8a63ec7ac6c5b05d96d4dfeb Mon Sep 17 00:00:00 2001 From: Renan Valentin Date: Mon, 25 Mar 2024 10:38:09 -0300 Subject: [PATCH] feat(extension): LW-9178 collateral output in tx activity details (#844) * feat(ui): create info bar component * fix(ui): add zIndex property to tooltip * feat(core): add collateral tooltip and info bar * feat(extension): display collateral info on activity details * refactor(extension): use wallet state * refactor(extension): reduce argument scope * refactor(extension): move ternary operation to variable declaration * refactor(core): rename tooltip function * refactor(ui): remove unused variable * refactor(core): ignore spendable activity status * feat(extension): display collateral balance * refactor(extension): move phase 2 validation func to utils --- .../src/lib/translations/en.json | 10 +- .../stores/slices/activity-detail-slice.ts | 39 +++++++- .../src/types/activity-detail.ts | 1 + .../src/utils/own-input-resolver.ts | 4 +- .../src/utils/phase2-validation.ts | 5 + .../src/utils/tx-inspection.ts | 6 +- .../components/TransactionDetailsProxy.tsx | 4 +- .../activity/helpers/common-tx-transformer.ts | 83 +++++++++++++--- .../components/ActivityDetail/Collateral.tsx | 50 ++++++++-- .../ActivityDetail/TransactionDetails.tsx | 33 ++++++- packages/core/src/ui/lib/translations/en.json | 8 ++ packages/ui/src/design-system/index.ts | 1 + .../ui/src/design-system/info-bar/index.ts | 1 + .../info-bar/info-bar.component.tsx | 44 +++++++++ .../design-system/info-bar/info-bar.css.ts | 30 ++++++ .../info-bar/info-bar.stories.tsx | 95 +++++++++++++++++++ .../tooltip/tooltip-root.component.tsx | 8 +- .../design-system/tooltip/tooltip-root.css.ts | 7 ++ packages/ui/src/design-tokens/colors.data.ts | 4 + .../src/design-tokens/theme/dark-theme.css.ts | 4 + .../design-tokens/theme/light-theme.css.ts | 4 + 21 files changed, 407 insertions(+), 34 deletions(-) create mode 100644 apps/browser-extension-wallet/src/utils/phase2-validation.ts create mode 100644 packages/ui/src/design-system/info-bar/index.ts create mode 100644 packages/ui/src/design-system/info-bar/info-bar.component.tsx create mode 100644 packages/ui/src/design-system/info-bar/info-bar.css.ts create mode 100644 packages/ui/src/design-system/info-bar/info-bar.stories.tsx create mode 100644 packages/ui/src/design-system/tooltip/tooltip-root.css.ts diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index c211959a8..18624c8d8 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -88,8 +88,14 @@ "multipleAddresses": "Multiple addresses", "pools": "Pool(s)", "epoch": "Epoch", - "collateral": "Collateral", - "collateralInfo": "Amount set as collateral to cover contract execution failure. In case of no failure collateral remains unspent." + "collateral": { + "label": "Collateral", + "tooltip": { + "info": "Amount set as collateral to cover contract execution failure. In case of no failure collateral remains unspent.", + "success": "Amount set as collateral. Since this Tx was successful collateral was not used" + }, + "error": "Since the transaction was unsuccessful, collateral has been used to cover the costs incurred from the contract execution failure." + } }, "walletNameAndPasswordSetupStep": { "title": "Let's set up your new wallet", diff --git a/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts b/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts index 386dd7210..f23a0dc73 100644 --- a/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts +++ b/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts @@ -24,6 +24,9 @@ import { governanceProposalsTransformer, votingProceduresTransformer } from '@src/views/browser-view/features/activity/helpers/common-tx-transformer'; +import { createHistoricalOwnInputResolver, HistoricalOwnInputResolverArgs } from '@src/utils/own-input-resolver'; +import { getCollateral } from '@cardano-sdk/core'; +import { hasPhase2ValidationFailed } from '@src/utils/phase2-validation'; /** * validates if the transaction is confirmed @@ -60,16 +63,22 @@ const transactionMetadataTransformer = ( [...metadata.entries()].map(([key, value]) => ({ key: key.toString(), value: Wallet.cardanoMetadatumToObj(value) })); const shouldIncludeFee = ( + tx: Wallet.Cardano.HydratedTx | Wallet.Cardano.Tx, type: ActivityType, delegationInfo: Wallet.Cardano.StakeDelegationCertificate[] | undefined -) => - !( +) => { + if (hasPhase2ValidationFailed(tx)) { + return false; + } + + return !( type === DelegationActivityType.delegationRegistration || // Existence of any (new) delegationInfo means that this "de-registration" // activity is accompanied by a "delegation" activity, which carries the fees. // However, fees should be shown if de-registration activity is standalone. (type === DelegationActivityType.delegationDeregistration && !!delegationInfo?.length) ); +}; const getPoolInfos = async (poolIds: Wallet.Cardano.PoolId[], stakePoolProvider: Wallet.StakePoolProvider) => { const filters: Wallet.QueryStakePoolsArgs = { @@ -89,6 +98,22 @@ const getPoolInfos = async (poolIds: Wallet.Cardano.PoolId[], stakePoolProvider: return pools; }; +const computeCollateral = async ( + { addresses, transactions }: HistoricalOwnInputResolverArgs, + tx?: Wallet.Cardano.Tx +): Promise => { + const inputResolver = createHistoricalOwnInputResolver({ + addresses, + transactions + }); + + return await getCollateral( + tx, + inputResolver, + addresses.map((addr) => addr.address) + ); +}; + /** * fetches asset information */ @@ -106,7 +131,8 @@ const buildGetActivityDetail = inMemoryWallet: wallet, walletUI: { cardanoCoin }, activityDetail, - walletInfo + walletInfo, + walletState } = get(); set({ fetchingActivityInfo: true }); @@ -204,6 +230,8 @@ const buildGetActivityDetail = ? Wallet.util.lovelacesToAdaString(depositReclaimValue.toString()) : undefined; const feeInAda = Wallet.util.lovelacesToAdaString(tx.body.fee.toString()); + const collateral = await computeCollateral(walletState, tx); + const collateralInAda = collateral > 0 ? Wallet.util.lovelacesToAdaString(collateral.toString()) : undefined; // Delegation tx additional data (LW-3324) @@ -214,7 +242,7 @@ const buildGetActivityDetail = let transaction: ActivityDetail['activity'] = { hash: tx.id.toString(), totalOutput: totalOutputInAda, - fee: shouldIncludeFee(type, delegationInfo) ? feeInAda : undefined, + fee: shouldIncludeFee(tx, type, delegationInfo) ? feeInAda : undefined, deposit, depositReclaim, addrInputs: inputs, @@ -230,7 +258,8 @@ const buildGetActivityDetail = fiatCurrency, proposalProcedures: tx.body.proposalProcedures }), - certificates: certificateTransformer(cardanoCoin, coinPrices, fiatCurrency, tx.body.certificates) + certificates: certificateTransformer(cardanoCoin, coinPrices, fiatCurrency, tx.body.certificates), + collateral: collateralInAda }; if (type === DelegationActivityType.delegation && delegationInfo) { diff --git a/apps/browser-extension-wallet/src/types/activity-detail.ts b/apps/browser-extension-wallet/src/types/activity-detail.ts index eb0339f6a..6927a1011 100644 --- a/apps/browser-extension-wallet/src/types/activity-detail.ts +++ b/apps/browser-extension-wallet/src/types/activity-detail.ts @@ -31,6 +31,7 @@ type TransactionActivity = { includedUtcTime?: string; totalOutput?: string; fee?: string; + collateral?: string; depositReclaim?: string; deposit?: string; addrInputs?: TxOutputInput[]; diff --git a/apps/browser-extension-wallet/src/utils/own-input-resolver.ts b/apps/browser-extension-wallet/src/utils/own-input-resolver.ts index d8b54fd46..0cf2b6e10 100644 --- a/apps/browser-extension-wallet/src/utils/own-input-resolver.ts +++ b/apps/browser-extension-wallet/src/utils/own-input-resolver.ts @@ -2,14 +2,14 @@ import { ObservableWalletState } from '@hooks/useWalletState'; import { Wallet } from '@lace/cardano'; -type Args = Pick & { +export type HistoricalOwnInputResolverArgs = Pick & { transactions: Pick; }; export const createHistoricalOwnInputResolver = ({ transactions: { history: txs }, addresses -}: Args): Wallet.Cardano.InputResolver => ({ +}: HistoricalOwnInputResolverArgs): Wallet.Cardano.InputResolver => ({ async resolveInput({ txId, index }: Wallet.Cardano.TxIn) { for (const tx of txs) { if (txId !== tx.id) { diff --git a/apps/browser-extension-wallet/src/utils/phase2-validation.ts b/apps/browser-extension-wallet/src/utils/phase2-validation.ts new file mode 100644 index 000000000..eb1d3639f --- /dev/null +++ b/apps/browser-extension-wallet/src/utils/phase2-validation.ts @@ -0,0 +1,5 @@ +import { Wallet } from '@lace/cardano'; + +export const hasPhase2ValidationFailed = ( + tx: Wallet.TxInFlight | Wallet.Cardano.HydratedTx | Wallet.Cardano.Tx +): boolean => 'inputSource' in tx && tx.inputSource === Wallet.Cardano.InputSource.collaterals; diff --git a/apps/browser-extension-wallet/src/utils/tx-inspection.ts b/apps/browser-extension-wallet/src/utils/tx-inspection.ts index 3cdcfec00..f36a72a0b 100644 --- a/apps/browser-extension-wallet/src/utils/tx-inspection.ts +++ b/apps/browser-extension-wallet/src/utils/tx-inspection.ts @@ -19,7 +19,7 @@ import { } from '@lace/core'; import { TxDirection, TxDirections } from '@src/types'; -const { CertificateType, GovernanceActionType, Vote, VoterType } = Wallet.Cardano; +const { CertificateType, GovernanceActionType, Vote, VoterType, InputSource } = Wallet.Cardano; const hasWalletStakeAddress = ( withdrawals: Wallet.Cardano.HydratedTx['body']['withdrawals'], @@ -142,6 +142,10 @@ export const inspectTxType = async ({ tx: Wallet.Cardano.HydratedTx; inputResolver: Wallet.Cardano.InputResolver; }): Promise> => { + if (tx.inputSource === InputSource.collaterals) { + return TransactionActivityType.outgoing; + } + const { paymentAddresses, rewardAccounts } = getWalletAccounts(walletAddresses); const inspectionProperties = await createTxInspector({ diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx index fb8919949..412cb9a52 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx @@ -52,7 +52,8 @@ export const TransactionDetailsProxy = withAddressBookContext( metadata, proposalProcedures, votingProcedures, - certificates + certificates, + collateral } = activityInfo.activity; const txSummary = useMemo( () => @@ -104,6 +105,7 @@ export const TransactionDetailsProxy = withAddressBookContext( certificates={certificates} handleOpenExternalHashLink={handleOpenExternalHashLink} openExternalLink={openExternalLink} + collateral={collateral} /> ); } diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/activity/helpers/common-tx-transformer.ts b/apps/browser-extension-wallet/src/views/browser-view/features/activity/helpers/common-tx-transformer.ts index 43dfc9c37..d75bbe69a 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/activity/helpers/common-tx-transformer.ts +++ b/apps/browser-extension-wallet/src/views/browser-view/features/activity/helpers/common-tx-transformer.ts @@ -24,6 +24,7 @@ import isEmpty from 'lodash/isEmpty'; import { PriceResult } from '@hooks'; import { formatPercentages } from '@lace/common'; import { depositPaidWithSymbol } from '@src/features/dapp/components/confirm-transaction/utils'; +import { hasPhase2ValidationFailed } from '@src/utils/phase2-validation'; const { util, GovernanceActionType, PlutusLanguageVersion, CertificateType } = Wallet.Cardano; @@ -98,7 +99,14 @@ const splitDelegationTx = (tx: TransformedActivity): TransformedTransactionActiv ]; }; -const transformTransactionStatus = (status: Wallet.TransactionStatus): ActivityStatus => { +const transformTransactionStatus = ( + tx: Wallet.TxInFlight | Wallet.Cardano.HydratedTx, + status: Wallet.TransactionStatus +): ActivityStatus => { + if (hasPhase2ValidationFailed(tx)) { + return ActivityStatus.ERROR; + } + const statuses = { [Wallet.TransactionStatus.PENDING]: ActivityStatus.PENDING, [Wallet.TransactionStatus.ERROR]: ActivityStatus.ERROR, @@ -107,6 +115,53 @@ const transformTransactionStatus = (status: Wallet.TransactionStatus): ActivityS }; return statuses[status]; }; + +type GetTxFormattedAmount = ( + args: Pick< + TxTransformerInput, + 'walletAddresses' | 'tx' | 'direction' | 'resolveInput' | 'cardanoCoin' | 'fiatCurrency' | 'fiatPrice' + > +) => Promise<{ + amount: string; + fiatAmount: string; +}>; + +const getTxFormattedAmount: GetTxFormattedAmount = async ({ + resolveInput, + tx, + walletAddresses, + direction, + cardanoCoin, + fiatCurrency, + fiatPrice +}) => { + if (hasPhase2ValidationFailed(tx)) { + return { + amount: Wallet.util.getFormattedAmount({ amount: tx.body.totalCollateral.toString(), cardanoCoin }), + fiatAmount: getFormattedFiatAmount({ + amount: new BigNumber(tx.body.totalCollateral?.toString() ?? '0'), + fiatCurrency, + fiatPrice + }) + }; + } + + const outputAmount = await getTransactionTotalAmount({ + addresses: walletAddresses, + inputs: tx.body.inputs, + outputs: tx.body.outputs, + fee: tx.body.fee, + direction, + withdrawals: tx.body.withdrawals, + resolveInput + }); + + return { + amount: Wallet.util.getFormattedAmount({ amount: outputAmount.toString(), cardanoCoin }), + fiatAmount: getFormattedFiatAmount({ amount: outputAmount, fiatCurrency, fiatPrice }) + }; +}; + /** Simplifies the transaction object to be used in the activity list @@ -145,15 +200,7 @@ export const txTransformer = async ({ tx: tx as unknown as Wallet.Cardano.HydratedTx, direction }); - const outputAmount = await getTransactionTotalAmount({ - addresses: walletAddresses, - inputs: tx.body.inputs, - outputs: tx.body.outputs, - fee: tx.body.fee, - direction, - withdrawals: tx.body.withdrawals, - resolveInput - }); + const formattedDate = dayjs().isSame(date, 'day') ? 'Today' : formatDate({ date, format: 'DD MMMM YYYY', type: 'local' }); @@ -168,14 +215,24 @@ export const txTransformer = async ({ .sort((a, b) => Number(b.val) - Number(a.val)) : []; + const formattedAmount = await getTxFormattedAmount({ + cardanoCoin, + fiatCurrency, + resolveInput, + tx, + walletAddresses, + direction, + fiatPrice + }); + const baseTransformedActivity = { id: tx.id.toString(), deposit, depositReclaim, fee: Wallet.util.lovelacesToAdaString(tx.body.fee.toString()), - status: transformTransactionStatus(status), - amount: Wallet.util.getFormattedAmount({ amount: outputAmount.toString(), cardanoCoin }), - fiatAmount: getFormattedFiatAmount({ amount: outputAmount, fiatCurrency, fiatPrice }), + status: transformTransactionStatus(tx, status), + amount: formattedAmount.amount, + fiatAmount: formattedAmount.fiatAmount, assets: assetsEntries, assetsNumber: (assets?.size ?? 0) + 1, date, diff --git a/packages/core/src/ui/components/ActivityDetail/Collateral.tsx b/packages/core/src/ui/components/ActivityDetail/Collateral.tsx index 4b3159a2b..763f165d1 100644 --- a/packages/core/src/ui/components/ActivityDetail/Collateral.tsx +++ b/packages/core/src/ui/components/ActivityDetail/Collateral.tsx @@ -1,21 +1,55 @@ import React from 'react'; import { useTranslate } from '@src/ui/hooks'; -import { TransactionSummary } from '@lace/ui'; +import { Box, TransactionSummary, InfoBar } from '@lace/ui'; +import { ReactComponent as InfoIcon } from '@lace/icons/dist/InfoComponent'; + +export enum CollateralStatus { + REVIEW = 'review', + SUCCESS = 'success', + ERROR = 'error', + NONE = 'none' +} export interface Props { collateral: string; amountTransformer: (amount: string) => string; coinSymbol: string; + status?: CollateralStatus; } -export const Collateral = ({ collateral, amountTransformer, coinSymbol }: Props): React.ReactElement => { + +export const Collateral = ({ + collateral, + amountTransformer, + coinSymbol, + status = CollateralStatus.REVIEW +}: Props): React.ReactElement => { const { t } = useTranslate(); + const getTooltipText = (): string => { + switch (status) { + case 'review': + case 'error': + return t('package.core.activityDetails.collateral.tooltip.info'); + case 'success': + return t('package.core.activityDetails.collateral.tooltip.success'); + } + + return ''; + }; + return ( - + <> + + {status === CollateralStatus.ERROR && ( + + } message={t('package.core.activityDetails.collateral.error')} /> + + )} + ); }; diff --git a/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx b/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx index ecd094a3c..4cd059b35 100644 --- a/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx +++ b/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx @@ -20,6 +20,7 @@ import { TxDetails, TxDetail } from './types'; +import { Collateral, CollateralStatus } from './Collateral'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const displayMetadataMsg = (value: any[]): string => value?.find((val: any) => val.hasOwnProperty('msg'))?.msg || ''; @@ -49,6 +50,10 @@ export interface TransactionDetailsProps { * Transaction total output */ totalOutput?: string; + /** + * Transaction collateral + */ + collateral?: string; /** * Transaction fee */ @@ -125,7 +130,8 @@ export const TransactionDetails = ({ sendAnalyticsOutputs, proposalProcedures, votingProcedures, - certificates + certificates, + collateral }: TransactionDetailsProps): React.ReactElement => { const { t } = useTranslate(); @@ -219,6 +225,21 @@ export const TransactionDetails = ({ ) ); + const getCollateralStatus = (): CollateralStatus => { + switch (status) { + case ActivityStatus.SPENDABLE: + return CollateralStatus.NONE; + case ActivityStatus.PENDING: + return CollateralStatus.REVIEW; + case ActivityStatus.SUCCESS: + return CollateralStatus.SUCCESS; + case ActivityStatus.ERROR: + return CollateralStatus.ERROR; + default: + return CollateralStatus.REVIEW; + } + }; + const renderDepositValueSection = ({ value, label }: { value: string; label: string }) => (
{label}
@@ -370,6 +391,16 @@ export const TransactionDetails = ({  {includedTime}
+ {collateral && ( + + + + )} {fee && fee !== '-' && ( diff --git a/packages/core/src/ui/lib/translations/en.json b/packages/core/src/ui/lib/translations/en.json index 9c775016b..452ed9656 100644 --- a/packages/core/src/ui/lib/translations/en.json +++ b/packages/core/src/ui/lib/translations/en.json @@ -116,6 +116,14 @@ "copiedToClipboard": "Copied to clipboard", "pools": "Pool(s)", "self": "Self Transaction", + "collateral": { + "label": "Collateral", + "tooltip": { + "info": "Amount set as collateral to cover contract execution failure. In case of no failure collateral remains unspent.", + "success": "Amount set as collateral. Since this Tx was successful collateral was not used" + }, + "error": "Since the transaction was unsuccessful, collateral has been used to cover the costs incurred from the contract execution failure." + }, "RegisterDelegateRepresentativeCertificate": "DRep Registration", "UnregisterDelegateRepresentativeCertificate": "DRep De-Registration", "UpdateDelegateRepresentativeCertificate": "DRep Update", diff --git a/packages/ui/src/design-system/index.ts b/packages/ui/src/design-system/index.ts index 6f05636a5..5498d4b91 100644 --- a/packages/ui/src/design-system/index.ts +++ b/packages/ui/src/design-system/index.ts @@ -48,3 +48,4 @@ export { ActionCard } from './action-card'; export { Loader } from './loader'; export * from './auto-suggest-box'; export * from './table'; +export { InfoBar } from './info-bar'; diff --git a/packages/ui/src/design-system/info-bar/index.ts b/packages/ui/src/design-system/info-bar/index.ts new file mode 100644 index 000000000..56542d46e --- /dev/null +++ b/packages/ui/src/design-system/info-bar/index.ts @@ -0,0 +1 @@ +export { InfoBar } from './info-bar.component'; diff --git a/packages/ui/src/design-system/info-bar/info-bar.component.tsx b/packages/ui/src/design-system/info-bar/info-bar.component.tsx new file mode 100644 index 000000000..e46795f0c --- /dev/null +++ b/packages/ui/src/design-system/info-bar/info-bar.component.tsx @@ -0,0 +1,44 @@ +import type { ReactNode } from 'react'; +import React from 'react'; + +import { Box } from '../box'; +import { CallToAction } from '../buttons'; +import { Flex } from '../flex'; +import * as Typography from '../typography'; + +import * as cx from './info-bar.css'; + +export interface Props { + message: string; + icon: ReactNode; + callToAction?: { + label?: string; + onClick?: () => void; + }; +} + +export const InfoBar = ({ + message, + icon, + callToAction, +}: Readonly): JSX.Element => { + return ( + + {icon} + + + {message} + + + + {callToAction && ( + + + + )} + + ); +}; diff --git a/packages/ui/src/design-system/info-bar/info-bar.css.ts b/packages/ui/src/design-system/info-bar/info-bar.css.ts new file mode 100644 index 000000000..659c3d435 --- /dev/null +++ b/packages/ui/src/design-system/info-bar/info-bar.css.ts @@ -0,0 +1,30 @@ +import { style } from '@vanilla-extract/css'; + +import { sx } from '../../design-tokens'; + +export const container = sx({ + px: '$24', + py: '$16', + backgroundColor: '$info_bar_container_bgColor', + borderRadius: '$medium', + alignItems: 'center', +}); + +export const icon = sx({ + width: '$24', + height: '$24', + fontSize: '$25', + mr: '$24', + color: '$info_bar_icon_color', +}); + +export const message = style([ + sx({ + color: '$info_bar_message_color', + mt: '$8', + }), + { + textAlign: 'center', + whiteSpace: 'pre-wrap', + }, +]); diff --git a/packages/ui/src/design-system/info-bar/info-bar.stories.tsx b/packages/ui/src/design-system/info-bar/info-bar.stories.tsx new file mode 100644 index 000000000..ea6ef71aa --- /dev/null +++ b/packages/ui/src/design-system/info-bar/info-bar.stories.tsx @@ -0,0 +1,95 @@ +import React from 'react'; + +import { ReactComponent as InfoIcon } from '@lace/icons/dist/InfoComponent'; + +import { LocalThemeProvider, ThemeColorScheme } from '../../design-tokens'; +import { page, Section, Variants } from '../decorators'; +import { Divider } from '../divider'; +import { Flex } from '../flex'; +import { Cell, Grid } from '../grid'; + +import { InfoBar } from './info-bar.component'; + +const subtitle = + 'The info bar control is for displaying app-wide status messages to users that are highly visible yet non-intrusive. There are built-in severity levels to easily indicate the type of message shown as well as the option to include your own call to action or hyperlink button.'; + +export default { + title: 'Status & info/Info Bar', + component: InfoBar, + decorators: [page({ title: 'Info bar', subtitle })], +}; + +const UsageSample = ({ + withCTA = false, +}: Readonly<{ withCTA?: boolean }>): JSX.Element => ( + } + message={`Lorem ipsum dolor sit amet, consectetuer adipiscing elit\nmaecenas porttitor congue massa. Fusce posuere, magna.`} + callToAction={ + withCTA + ? { + label: 'Label', + } + : undefined + } + /> +); + +const VariantsTable = (): JSX.Element => ( +
+ + + + + + + + + + +
+); + +const MainComponents = (): JSX.Element => ( + <> + + + + + + + + + + + +); + +export const Overview = (): JSX.Element => ( + + +
+ + + +
+ + + + + + + +
+ + + + + + + + +
+
+
+); diff --git a/packages/ui/src/design-system/tooltip/tooltip-root.component.tsx b/packages/ui/src/design-system/tooltip/tooltip-root.component.tsx index 1fa710470..b3e310ae3 100644 --- a/packages/ui/src/design-system/tooltip/tooltip-root.component.tsx +++ b/packages/ui/src/design-system/tooltip/tooltip-root.component.tsx @@ -3,6 +3,7 @@ import React from 'react'; import * as Tooltip from '@radix-ui/react-tooltip'; import { TooltipContent } from './tooltip-content.component'; +import * as cx from './tooltip-root.css'; export type Props = Pick< Tooltip.PopperContentProps, @@ -24,7 +25,12 @@ export const Root = ({ {children} - + diff --git a/packages/ui/src/design-system/tooltip/tooltip-root.css.ts b/packages/ui/src/design-system/tooltip/tooltip-root.css.ts new file mode 100644 index 000000000..6c4043a7a --- /dev/null +++ b/packages/ui/src/design-system/tooltip/tooltip-root.css.ts @@ -0,0 +1,7 @@ +import { style } from '../../design-tokens'; + +export const root = style([ + { + zIndex: 9999, + }, +]); diff --git a/packages/ui/src/design-tokens/colors.data.ts b/packages/ui/src/design-tokens/colors.data.ts index 0c1ce7a27..a77f4e07c 100644 --- a/packages/ui/src/design-tokens/colors.data.ts +++ b/packages/ui/src/design-tokens/colors.data.ts @@ -298,6 +298,10 @@ export const colors = { $stake_pool_header_text_color: '', $stake_pool_item_bg_hover: '', $stake_pool_item_text_color: '', + + $info_bar_container_bgColor: '', + $info_bar_message_color: '', + $info_bar_icon_color: '', }; export type Colors = typeof colors; diff --git a/packages/ui/src/design-tokens/theme/dark-theme.css.ts b/packages/ui/src/design-tokens/theme/dark-theme.css.ts index 0df923ed5..65017e510 100644 --- a/packages/ui/src/design-tokens/theme/dark-theme.css.ts +++ b/packages/ui/src/design-tokens/theme/dark-theme.css.ts @@ -396,6 +396,10 @@ const colors: Colors = { $stake_pool_item_bg_hover: darkColorScheme.$primary_dark_grey_plus, $stake_pool_header_text_color: darkColorScheme.$primary_white, $stake_pool_item_text_color: darkColorScheme.$primary_light_grey, + + $info_bar_container_bgColor: darkColorScheme.$primary_dark_grey_plus, + $info_bar_icon_color: darkColorScheme.$secondary_data_pink, + $info_bar_message_color: darkColorScheme.$primary_light_grey, }; const elevation: Elevation = { diff --git a/packages/ui/src/design-tokens/theme/light-theme.css.ts b/packages/ui/src/design-tokens/theme/light-theme.css.ts index 2aad7bd66..50f553764 100644 --- a/packages/ui/src/design-tokens/theme/light-theme.css.ts +++ b/packages/ui/src/design-tokens/theme/light-theme.css.ts @@ -424,6 +424,10 @@ const colors: Colors = { $stake_pool_item_bg_hover: lightColorScheme.$primary_light_grey, $stake_pool_header_text_color: lightColorScheme.$primary_dark_grey, $stake_pool_item_text_color: lightColorScheme.$primary_black, + + $info_bar_container_bgColor: lightColorScheme.$secondary_cream, + $info_bar_icon_color: lightColorScheme.$secondary_data_pink, + $info_bar_message_color: lightColorScheme.$primary_black, }; export const elevation: Elevation = {