diff --git a/packages/ui/src/accounts/components/SelectAccount/OptionAccount.tsx b/packages/ui/src/accounts/components/SelectAccount/OptionAccount.tsx index ca68033611..c80a000c46 100644 --- a/packages/ui/src/accounts/components/SelectAccount/OptionAccount.tsx +++ b/packages/ui/src/accounts/components/SelectAccount/OptionAccount.tsx @@ -1,21 +1,22 @@ import React from 'react' -import styled from 'styled-components' +import styled, { css } from 'styled-components' import { AccountInfo } from '@/accounts/components/AccountInfo' -import { AccountLocks, AccountLocksWrapper } from '@/accounts/components/AccountLocks' +import { AccountLocks } from '@/accounts/components/AccountLocks' import { useBalance } from '@/accounts/hooks/useBalance' import { AccountOption } from '@/accounts/types' -import { BalanceInfoNarrow, InfoTitle, InfoValue } from '@/common/components/Modal' +import { BalanceInfo, InfoTitle } from '@/common/components/Modal' import { TokenValue } from '@/common/components/typography' -import { Colors } from '@/common/constants' +import { BreakPoints, Colors } from '@/common/constants' interface Props { option: AccountOption isForStaking?: boolean variant?: 's' | 'm' | 'l' + isSelected?: boolean } -export const OptionAccount = ({ option, isForStaking, variant }: Props) => { +export const OptionAccount = ({ option, isForStaking, variant, isSelected }: Props) => { const balances = useBalance(option.address) const balance = isForStaking ? balances?.total : balances?.transferable const balanceType = isForStaking ? 'Total' : 'Transferable' @@ -25,23 +26,41 @@ export const OptionAccount = ({ option, isForStaking, variant }: Props) => { return ( <> - + {balanceType} balance - + - - + + ) } -const Value = styled(TokenValue)<{ locked?: boolean }>` - color: ${({ locked }) => (locked ? Colors.Black[500] : 'default')}; +const InfoContainer = styled.div` + display: flex; + flex-direction: column; + align-items: end; ` -export const InfoValueWithLocks = styled(InfoValue)` - ${AccountLocksWrapper} { - right: 0; +const StyledBalanceInfo = styled(BalanceInfo)>` + gap: 12px; + + @media (max-width: ${BreakPoints.sm - 1}px) { + ${({ isSelected }) => + isSelected + ? css` + display: none; + ` + : css` + display: flex; + ${InfoContainer} { + display: contents; + } + `}; } ` + +const Value = styled(TokenValue)<{ locked?: boolean }>` + color: ${({ locked }) => (locked ? Colors.Black[500] : 'default')}; +` diff --git a/packages/ui/src/accounts/components/SelectAccount/OptionListAccount.stories.tsx b/packages/ui/src/accounts/components/SelectAccount/OptionListAccount.stories.tsx new file mode 100644 index 0000000000..abf9fdb582 --- /dev/null +++ b/packages/ui/src/accounts/components/SelectAccount/OptionListAccount.stories.tsx @@ -0,0 +1,53 @@ +import { Meta, StoryFn } from '@storybook/react' +import React from 'react' +import styled from 'styled-components' + +import { useMyAccounts } from '@/accounts/hooks/useMyAccounts' +import { member } from '@/mocks/data/members' +import { MocksParameters } from '@/mocks/providers' +import { AccountMock } from '@/mocks/providers/accounts' + +import { OptionListAccount as OptionListAccountComponent } from './OptionListAccount' + +export const mockAccounts: AccountMock[] = [ + { member: member('alice'), balances: { transferable: 0.00001, locks: ['Apps Worker'] } }, + { + member: member('bob'), + balances: { transferable: 101_300_098.123, locks: ['Councilor', 'Voting', 'Council Candidate'] }, + }, + { member: member('charlie'), balances: 200 }, + { member: member('dave'), balances: { transferable: 0, locks: ['Bound Staking Account'] } }, + { member: member('eve'), balances: { transferable: 1000, locks: ['Staking'] } }, + { member: member('ferdie'), balances: 500 }, +] + +export default { + title: 'Accounts/SelectAccount/OptionListAccount', + component: OptionListAccountComponent, + + parameters: { + mocks: { + accounts: { list: mockAccounts }, + } satisfies MocksParameters, + }, + + excludeStories: ['mockAccounts'], +} satisfies Meta + +export const OptionListAccount: StoryFn = () => { + const { allAccounts } = useMyAccounts() + + const free = allAccounts.slice(0, 3) + + const optionLocks = [['insufficientFunds', 'boundMembership'], ['rivalrousLock', 'recoverableLock'], ['optOutLock']] + const locked = allAccounts.slice(3).map((account, i) => ({ ...account, optionLocks: optionLocks[i] })) + + return +} + +const AccountsOptions = styled(OptionListAccountComponent)` + position: static; + transform: none; + max-height: none; + max-width: 856px; +` diff --git a/packages/ui/src/accounts/components/SelectAccount/OptionListAccount.tsx b/packages/ui/src/accounts/components/SelectAccount/OptionListAccount.tsx index 226acfa929..8977e0dd10 100644 --- a/packages/ui/src/accounts/components/SelectAccount/OptionListAccount.tsx +++ b/packages/ui/src/accounts/components/SelectAccount/OptionListAccount.tsx @@ -9,7 +9,7 @@ import { OptionAccount } from './OptionAccount' interface Props { options: AccountOption[] - onChange: (option: AccountOption) => void + onChange?: (option: AccountOption) => void className?: string isForStaking?: boolean variant?: 's' | 'm' | 'l' @@ -21,13 +21,13 @@ export const OptionListAccount = React.memo(({ options, onChange, className, isF return ( {freeAccounts.map((option) => ( - ))} {lockedAccounts.map((option) => ( - diff --git a/packages/ui/src/accounts/components/SelectAccount/SelectAccount.stories.tsx b/packages/ui/src/accounts/components/SelectAccount/SelectAccount.stories.tsx index 75bb6b348c..b3d58df947 100644 --- a/packages/ui/src/accounts/components/SelectAccount/SelectAccount.stories.tsx +++ b/packages/ui/src/accounts/components/SelectAccount/SelectAccount.stories.tsx @@ -1,60 +1,40 @@ -import { Meta, Story } from '@storybook/react' -import React, { ReactNode, useState } from 'react' +import { Meta, StoryFn } from '@storybook/react' +import React, { useState } from 'react' +import styled from 'styled-components' -import { AccountsContextProvider } from '@/accounts/providers/accounts/provider' import { Account } from '@/accounts/types' import { InputComponent } from '@/common/components/forms' -import { Warning } from '@/common/components/Warning' -import { KeyringContextProvider } from '@/common/providers/keyring/provider' -import { MockApolloProvider } from '@/mocks/components/storybook/MockApolloProvider' +import { MocksParameters } from '@/mocks/providers' import { SelectAccount } from '.' +import { mockAccounts } from './OptionListAccount.stories' export default { title: 'Accounts/SelectAccount', component: SelectAccount, -} as Meta -const renderWarning = (accountSelect: ReactNode) => ( - <> - - To render this component properly:{' '} - - Open the canvas in a new tab - - - } - /> -
- {accountSelect} - -) + parameters: { + mocks: { + accounts: { list: mockAccounts }, + } satisfies MocksParameters, + }, +} satisfies Meta -export const Default: Story = () => { +export const Default: StoryFn = () => { const [selected, setSelected] = useState() - const accountSelect = ( - - - ) - - return window.self === window.top ? ( - - - {accountSelect} - - - ) : ( - renderWarning(accountSelect) + ) } + +const StyledInputComponent = styled(InputComponent)` + max-width: 856px; +` diff --git a/packages/ui/src/accounts/components/SelectAccount/SelectAccount.tsx b/packages/ui/src/accounts/components/SelectAccount/SelectAccount.tsx index 9c88dc5d0f..349848ce5c 100644 --- a/packages/ui/src/accounts/components/SelectAccount/SelectAccount.tsx +++ b/packages/ui/src/accounts/components/SelectAccount/SelectAccount.tsx @@ -39,7 +39,7 @@ interface BaseSelectAccountProps extends SelectAccountProps { isForStaking?: boolean } -export const BaseSelectAccount = React.memo( +const BaseSelectAccount = React.memo( ({ id, onChange, accounts, filter, selected, disabled, onBlur, isForStaking, variant }: BaseSelectAccountProps) => { const options = accounts.filter(filter || (() => true)) @@ -88,7 +88,7 @@ export const BaseSelectAccount = React.memo( const renderSelected = (isForStaking?: boolean, variant?: 's' | 'm' | 'l') => (option: AccountOption) => ( - + ) diff --git a/packages/ui/src/accounts/modals/ClaimVestingModal/components/SelectVestingAccount.tsx b/packages/ui/src/accounts/modals/ClaimVestingModal/components/SelectVestingAccount.tsx index 42c187e86f..7cd8e76ca3 100644 --- a/packages/ui/src/accounts/modals/ClaimVestingModal/components/SelectVestingAccount.tsx +++ b/packages/ui/src/accounts/modals/ClaimVestingModal/components/SelectVestingAccount.tsx @@ -4,14 +4,13 @@ import styled from 'styled-components' import { AccountInfo } from '@/accounts/components/AccountInfo' import { filterByText } from '@/accounts/components/SelectAccount/helpers' -import { InfoValueWithLocks } from '@/accounts/components/SelectAccount/OptionAccount' import { useBalance } from '@/accounts/hooks/useBalance' import { useMyAccounts } from '@/accounts/hooks/useMyAccounts' import { accountOrNamed } from '@/accounts/model/accountOrNamed' import { isValidAddress } from '@/accounts/model/isValidAddress' import { Account, AccountOption } from '@/accounts/types' import { VestingLockIcon } from '@/common/components/icons/locks/VestingLockIcon' -import { BalanceInfoInRow } from '@/common/components/Modal' +import { BalanceInfoInRow, InfoValue } from '@/common/components/Modal' import { ColumnGapBlock } from '@/common/components/page/PageContent' import { Option, OptionsListComponent, Select, SelectedOption } from '@/common/components/selects' import { TextMedium, TokenValue } from '@/common/components/typography' @@ -91,9 +90,9 @@ export const VestingListItem = ({ option, vestingClaimable }: { option: AccountO Vesting - + - + ) diff --git a/packages/ui/src/accounts/model/walletConnect.ts b/packages/ui/src/accounts/model/walletConnect.ts index 8b3d874181..945c374b6a 100644 --- a/packages/ui/src/accounts/model/walletConnect.ts +++ b/packages/ui/src/accounts/model/walletConnect.ts @@ -85,7 +85,7 @@ export class WalletConnect extends BaseDotsamaWallet { polkadot: { methods: ['polkadot_signTransaction', 'polkadot_signMessage'], chains: [chainCAIP], - events: ['chainChanged", "accountsChanged'], + events: ['chainChanged', 'accountsChanged'], }, } diff --git a/packages/ui/src/app/App.stories.tsx b/packages/ui/src/app/App.stories.tsx index feb02e4d28..4d7cc51067 100644 --- a/packages/ui/src/app/App.stories.tsx +++ b/packages/ui/src/app/App.stories.tsx @@ -355,7 +355,7 @@ export const NoAccount: Story = { const modal = withinModal(canvasElement) expectActiveStepToBe(modal, 'Connect account') expect(modal.getByText('Connect account', { selector: '[class^=ModalBody] *' })) - expect(getButtonByText(modal, 'Return to wallet selection')).toBeEnabled() + expect(getButtonByText(modal, 'Change wallet')).toBeEnabled() expect(getButtonByText(modal, 'Connect Account')).toBeDisabled() expect(modal.queryByText('alice')).toBeNull() }, @@ -376,7 +376,7 @@ export const FaucetMembership: Story = { expectActiveStepToBe(modal, 'Connect account') expect(modal.getByText('Connect account', { selector: '[class^=ModalBody] *' })) - expect(getButtonByText(modal, 'Return to wallet selection')).toBeEnabled() + expect(getButtonByText(modal, 'Change wallet')).toBeEnabled() const connectAccountButton = getButtonByText(modal, 'Connect Account') expect(connectAccountButton).toBeDisabled() @@ -426,6 +426,7 @@ export const BuyMembershipHappy: Story = { expect(screen.queryByText('Become a member')).toBeNull() await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await step('Form', async () => { const createButton = getButtonByText(modal, 'Create a Membership') @@ -539,6 +540,7 @@ export const BuyMembershipNotEnoughFund: Story = { const modal = withinModal(canvasElement) await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await fillMembershipForm(modal) const createButton = getButtonByText(modal, 'Create a Membership') @@ -559,6 +561,7 @@ export const BuyMembershipTxFailure: Story = { const modal = withinModal(canvasElement) await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await fillMembershipForm(modal) const createButton = getButtonByText(modal, 'Create a Membership') @@ -598,6 +601,7 @@ export const BuyMembershipHappyBindOneValidatorHappy: Story = { expect(screen.queryByText('Become a member')).toBeNull() await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await step('Form', async () => { const createButton = getButtonByText(modal, 'Create a Membership') @@ -679,6 +683,7 @@ export const BuyMembershipHappyAddTwoValidatorHappy: Story = { expect(screen.queryByText('Become a member')).toBeNull() await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await step('Form', async () => { const createButton = getButtonByText(modal, 'Create a Membership') @@ -773,6 +778,8 @@ export const InvalidValidatorAccountInput: Story = { const modal = withinModal(canvasElement) await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) + await fillMembershipForm(modal) const validatorCheckButton = modal.getAllByText('Yes')[1] await userEvent.click(validatorCheckButton) @@ -798,6 +805,7 @@ export const BuyMembershipWithValidatorAccountNotEnoughFunds: Story = { const modal = withinModal(canvasElement) await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await fillMembershipFormValidatorAccounts(modal, ['charlie']) const createButton = getButtonByText(modal, 'Create a Membership') @@ -818,6 +826,7 @@ export const BuyMembershipWithValidatorAccountFailure: Story = { const modal = withinModal(canvasElement) await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await fillMembershipFormValidatorAccounts(modal, ['charlie']) const createButton = getButtonByText(modal, 'Create a Membership') @@ -842,6 +851,7 @@ export const BuyMembershipHappyAddOneValidatorFailure: Story = { expect(screen.queryByText('Become a member')).toBeNull() await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await step('Form', async () => { const createButton = getButtonByText(modal, 'Create a Membership') @@ -888,6 +898,7 @@ export const BuyMembershipAddValidatorAccHappyConfirmTxFailure: Story = { expect(screen.queryByText('Become a member')).toBeNull() await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await step('Form', async () => { const createButton = getButtonByText(modal, 'Create a Membership') @@ -944,6 +955,7 @@ export const BuyMembershipAddTwoValidatorAccHappyConfirmTxFailure: Story = { expect(screen.queryByText('Become a member')).toBeNull() await userEvent.click(getButtonByText(screen, 'Join Now')) + await userEvent.click(await modal.findByText('New Member')) await step('Form', async () => { const createButton = getButtonByText(modal, 'Create a Membership') diff --git a/packages/ui/src/app/GlobalModals.tsx b/packages/ui/src/app/GlobalModals.tsx index 9f69df316e..148ac24c03 100644 --- a/packages/ui/src/app/GlobalModals.tsx +++ b/packages/ui/src/app/GlobalModals.tsx @@ -3,7 +3,6 @@ import React, { memo, ReactElement, useEffect, useMemo, useState } from 'react' import ReactDOM from 'react-dom' import styled from 'styled-components' -import { useMyAccounts } from '@/accounts/hooks/useMyAccounts' import { ClaimVestingModalCall } from '@/accounts/modals/ClaimVestingModal' import { ClaimVestingModal } from '@/accounts/modals/ClaimVestingModal/ClaimVestingModal' import { MoveFundsModal, MoveFundsModalCall } from '@/accounts/modals/MoveFundsModal' @@ -26,11 +25,9 @@ import { TransferModal, TransferModalCall } from '@/accounts/modals/TransferModa import { FailureModal } from '@/common/components/FailureModal' import { Loading } from '@/common/components/Loading' import { ModalGlass } from '@/common/components/Modal' -import { NotSupportMobileModal } from '@/common/components/NotSupportMobileModal' import { SearchResultsModal, SearchResultsModalCall } from '@/common/components/Search/SearchResultsModal' import { SuccessModal } from '@/common/components/SuccessModal' import { useModal } from '@/common/hooks/useModal' -import { useResponsive } from '@/common/hooks/useResponsive' import { useTransactionStatus } from '@/common/hooks/useTransactionStatus' import { ConfirmModal } from '@/common/modals/ConfirmModal/ConfirmModal' import { OnBoardingModal, OnBoardingModalCall } from '@/common/modals/OnBoardingModal' @@ -223,32 +220,10 @@ export const MODAL_WITH_CLOSE_CONFIRMATION: ModalNames[] = [ 'VoteForProposalModal', ] -const NON_TRANSACTIONAL_MODALS: ModalNames[] = [ - 'Member', - 'ApplicationDetails', - 'VoteRationaleModal', - 'SearchResults', - 'CandidacyPreview', - 'EmailConfirmationModal', -] - -const MOBILE_SUPPORTED_MODALS: ModalNames[] = [ - ...NON_TRANSACTIONAL_MODALS, - 'SwitchMember', - 'DisconnectWallet', - 'SignOut', - 'CreatePost', - 'PostReplyModal', - 'CreateThreadModal', - 'EmailSubscriptionModal', -] - export const GlobalModals = () => { const { modal, hideModal, currentModalMachine, showModal, modalData, isClosing } = useModal() const { active: activeMember } = useMyMemberships() - const { wallet } = useMyAccounts() const { status } = useTransactionStatus() - const { isMobileWallet } = useResponsive() const Modal = useMemo(() => (modal && modal in modals ? memo(() => modals[modal as ModalNames]) : null), [modal]) const [container, setContainer] = useState(document.body) @@ -259,11 +234,6 @@ export const GlobalModals = () => { const potentialFallback = useGlobalModalHandler(currentModalMachine, hideModal) - const mobileSupported = wallet ? MOBILE_SUPPORTED_MODALS : NON_TRANSACTIONAL_MODALS - if (isMobileWallet && modal && !mobileSupported.includes(modal as ModalNames)) { - return - } - if (modal && !GUEST_ACCESSIBLE_MODALS.includes(modal as ModalNames) && !activeMember) { showModal({ modal: 'SwitchMember', diff --git a/packages/ui/src/app/components/OnboardingOverlay/OnBoardingOverlay.tsx b/packages/ui/src/app/components/OnboardingOverlay/OnBoardingOverlay.tsx index 7598c1f9df..cf80c4f8d8 100644 --- a/packages/ui/src/app/components/OnboardingOverlay/OnBoardingOverlay.tsx +++ b/packages/ui/src/app/components/OnboardingOverlay/OnBoardingOverlay.tsx @@ -88,19 +88,10 @@ export const OnBoardingOverlay = () => { showModal({ modal: 'OnBoardingModal' }) }, [wallet, selectedWallet]) - if (isLoading || !status || status === 'finished' || !api?.isConnected) { + if (isMobile || isLoading || !status || status === 'finished' || !api?.isConnected) { return null } - if (isMobile) { - return ( - - To become a member visit this page from desktop - It requires browser extension - - ) - } - return ( <> @@ -246,20 +237,3 @@ export const StepperContainer = styled.div` padding: 10px; justify-content: center; ` - -const WrapperMobileMode = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - gap: 4px; - width: 100%; - background-color: ${Colors.Black[700]}; - color: ${Colors.White}; - position: relative; - padding: 10px 16px; - - p { - text-align: center; - } -` diff --git a/packages/ui/src/app/pages/Forum/ForumCategory.tsx b/packages/ui/src/app/pages/Forum/ForumCategory.tsx index fed06f054f..992d54e203 100644 --- a/packages/ui/src/app/pages/Forum/ForumCategory.tsx +++ b/packages/ui/src/app/pages/Forum/ForumCategory.tsx @@ -82,6 +82,7 @@ export const ForumCategory = () => { style="primary" size="medium" onClick={() => showModal({ modal: 'CreateThreadModal', data: { categoryId: id } })} + isResponsive > Add New Thread diff --git a/packages/ui/src/common/components/ContextMenu/ContextMenu.tsx b/packages/ui/src/common/components/ContextMenu/ContextMenu.tsx index f19a2b7de2..7219731eaf 100644 --- a/packages/ui/src/common/components/ContextMenu/ContextMenu.tsx +++ b/packages/ui/src/common/components/ContextMenu/ContextMenu.tsx @@ -19,9 +19,10 @@ export interface ContextMenuProps { items: ContextMenuItem[] size?: ButtonSize title?: string + isResponsive?: boolean } -export const ContextMenu = ({ items, size, title }: ContextMenuProps) => { +export const ContextMenu = ({ items, size, title, isResponsive }: ContextMenuProps) => { const [isMenuVisible, setMenuVisible] = useState(false) const [referenceElementRef, setReferenceElementRef] = useState(null) const [popperElementRef, setPopperElementRef] = useState(null) @@ -56,6 +57,7 @@ export const ContextMenu = ({ items, size, title }: ContextMenuProps) => { size={size ?? 'medium'} {...contextMenuHandlers} title={title ?? 'Context menu'} + isResponsive={isResponsive} > diff --git a/packages/ui/src/common/components/EditableInputList/EditableInputList.tsx b/packages/ui/src/common/components/EditableInputList/EditableInputList.tsx index aad7c011cc..dc471d1dad 100644 --- a/packages/ui/src/common/components/EditableInputList/EditableInputList.tsx +++ b/packages/ui/src/common/components/EditableInputList/EditableInputList.tsx @@ -2,8 +2,7 @@ import * as React from 'react' import { ChangeEvent } from 'react' import styled from 'styled-components' -import { ButtonBareGhost } from '@/common/components/buttons' -import { TransactionButton } from '@/common/components/buttons/TransactionButton' +import { ButtonBareGhost, ButtonPrimary } from '@/common/components/buttons' import { InputComponent, InputNotification, InputText, ToggleCheckbox } from '@/common/components/forms' import { BinIcon } from '@/common/components/icons' import { PlusIcon } from '@/common/components/icons/PlusIcon' @@ -53,10 +52,10 @@ const EditableInputList: React.FC = React.memo( {title} - addFields()}> + addFields()}> {buttonText} - + {value.map((questionFields, index) => ( diff --git a/packages/ui/src/common/components/Info.tsx b/packages/ui/src/common/components/Info.tsx index 7a5d19b250..6a273b4b15 100644 --- a/packages/ui/src/common/components/Info.tsx +++ b/packages/ui/src/common/components/Info.tsx @@ -3,8 +3,7 @@ import styled from 'styled-components' import { Colors } from '@/common/constants' -import { ColumnGapBlock, RowGapBlock } from './page/PageContent' -import { Tooltip, TooltipDefault } from './Tooltip' +import { RowGapBlock } from './page/PageContent' export interface InfoProps { title?: string @@ -14,14 +13,7 @@ export interface InfoProps { export const Info = ({ title, children }: InfoProps) => { return ( - {title && ( - - - - -
{title}
-
- )} + {title &&
{title}
} {children}
) diff --git a/packages/ui/src/common/components/Modal/Modal.tsx b/packages/ui/src/common/components/Modal/Modal.tsx index 746d49a9da..7305a5bc2a 100644 --- a/packages/ui/src/common/components/Modal/Modal.tsx +++ b/packages/ui/src/common/components/Modal/Modal.tsx @@ -5,7 +5,7 @@ import { ConnectionStatusDot } from '@/app/components/ConnectionStatusDot' import { useEscape } from '@/common/hooks/useEscape' import { Animations, BorderRad, BreakPoints, Colors, Fonts, RemoveScrollbar, Shadows, ZIndex } from '../../constants' -import { CloseButton } from '../buttons' +import { ButtonsGroup, CloseButton } from '../buttons' import { TextMedium, ValueInJoys } from '../typography' interface ModalHeaderBasicProps { @@ -172,19 +172,27 @@ export const ModalFooterComponent = styled.footer` display: inline-flex; flex-wrap: wrap; grid-area: modalfooter; - gap: 16px; + gap: 16px 4px; justify-self: end; justify-content: end; align-items: center; width: 100%; height: content-fit; min-height: 64px; - padding: 12px 26px 12px 24px; + padding: 12px; border-radius: 0 0 2px 2px; position: relative; + max-width: 100vw; @media (min-width: ${BreakPoints.sm}px) { - flex-flow: nowrap; + flex-wrap: nowrap; + gap: 16px; + padding: 12px 26px 12px 24px; + + ${ButtonsGroup} { + gap: 16px; + } + } } ` @@ -310,7 +318,11 @@ export const ScrolledModalContainer = styled.div` grid-row-gap: 16px; width: 100%; height: 100%; - padding: 24px 24px 20px; + padding: 24px 12px 20px; + + @media (min-width: ${BreakPoints.sm}px) { + padding: 24px 24px 20px; + } &:after { content: ''; diff --git a/packages/ui/src/common/components/Modal/ModalTransactionFooter.tsx b/packages/ui/src/common/components/Modal/ModalTransactionFooter.tsx index fc5decbfe6..e7057d28d1 100644 --- a/packages/ui/src/common/components/Modal/ModalTransactionFooter.tsx +++ b/packages/ui/src/common/components/Modal/ModalTransactionFooter.tsx @@ -1,12 +1,14 @@ import BN from 'bn.js' import React, { FC, ReactNode } from 'react' +import { useTranslation } from 'react-i18next' +import styled from 'styled-components' import { useTransactionFee } from '@/accounts/hooks/useTransactionFee' import { ButtonGhost, ButtonPrimary, ButtonsGroup } from '@/common/components/buttons' import { Arrow } from '@/common/components/icons' import { ModalFooter, TransactionInfoContainer } from '@/common/components/Modal' -import { TransactionFee } from '../TransactionFee' +import { TransactionInfo } from '../TransactionInfo' interface ButtonState { disabled?: boolean @@ -33,27 +35,44 @@ export const ModalTransactionFooter: FC = ({ children, }) => { const { feeInfo } = useTransactionFee() + const { t } = useTranslation() + return ( - - {extraLeftButtons} - {prev && !prev.disabled && ( - - - {prev.label ?? 'Previous step'} - - )} - - - {children} - {(transactionFee || feeInfo) && } - - + {(extraLeftButtons || (prev && !prev.disabled)) && ( + + {prev && !prev.disabled && ( + + + {prev.label ?? 'Previous step'} + + )} + {extraLeftButtons} + + )} + + {(children || transactionFee || feeInfo) && ( + + {children} + {(transactionFee || feeInfo) && ( + + )} + + )} + + {extraButtons} {next.label ?? 'Next step'} - + ) } + +const MainButtonGroup = styled(ButtonsGroup)` + justify-content: end; +` diff --git a/packages/ui/src/common/components/Modal/Modals.tsx b/packages/ui/src/common/components/Modal/Modals.tsx index 5752ab32c5..536e52ce85 100644 --- a/packages/ui/src/common/components/Modal/Modals.tsx +++ b/packages/ui/src/common/components/Modal/Modals.tsx @@ -63,7 +63,9 @@ export const TransactionAmount = styled.div` export const TransactionInfoContainer = styled.div` display: grid; - margin-right: 24px; + align-items: center; + grid-template-columns: 1fr auto auto; + column-gap: 8px; ` export const BalanceInfo = styled.div` @@ -78,11 +80,6 @@ export const BalanceInfoInRow = styled(BalanceInfo)` justify-self: end; ` -export const BalanceInfoNarrow = styled(BalanceInfo)` - grid-template-columns: 1fr 128px; - width: auto; -` - export const InfoTitle = styled.span` font-size: 10px; line-height: 16px; @@ -92,7 +89,7 @@ export const InfoTitle = styled.span` color: ${Colors.Black[400]}; ` -export const InfoValue = styled.span` +export const InfoValue = styled.div` text-align: right; text-align: -webkit-right; line-height: 20px; diff --git a/packages/ui/src/common/components/NotSupportMobileModal.tsx b/packages/ui/src/common/components/NotSupportMobileModal.tsx deleted file mode 100644 index 040a0a7828..0000000000 --- a/packages/ui/src/common/components/NotSupportMobileModal.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react' - -import { Modal, ModalBody, ModalHeader } from '@/common/components/Modal' -import { TextMedium } from '@/common/components/typography' - -interface Props { - onClose: () => void -} - -export const NotSupportMobileModal = ({ onClose }: Props) => ( - - - - This action requires a browser extension, please visit this page from a desktop browser. - - -) diff --git a/packages/ui/src/common/components/Stepper/HorizontalStepper.tsx b/packages/ui/src/common/components/Stepper/HorizontalStepper.tsx index d461ebf0bc..b73c4055f7 100644 --- a/packages/ui/src/common/components/Stepper/HorizontalStepper.tsx +++ b/packages/ui/src/common/components/Stepper/HorizontalStepper.tsx @@ -2,7 +2,7 @@ import React from 'react' import styled, { css } from 'styled-components' import { asStepsToRender, StepperStep, StepToRender } from '@/common/components/Stepper/types' -import { BorderRad, Colors, Fonts, Transitions } from '@/common/constants' +import { BorderRad, BreakPoints, Colors, Fonts, Transitions } from '@/common/constants' import { CheckboxIcon } from '../icons' @@ -16,17 +16,26 @@ export const HorizontalStepper = ({ steps }: HorizontalStepperProps) => { return ( {stepsToRender.map((step, index) => ( - - {step.isPast ? : index + 1} - - {step.title} - - + <> + + {step.isPast ? : index + 1} + + {step.title} + + + {index < stepsToRender.length - 1 && } + ))} ) } +const Separator = styled.i` + min-width: 20px; + height: 1px; + background-color: ${Colors.Black[500]}; +` + const pastStepCss = css` border-color: ${Colors.Black[500]}; color: ${Colors.White}; @@ -40,10 +49,10 @@ const activeStepCss = css` const StepTitle = styled.h6` align-self: center; + text-align: center; text-transform: capitalize; transition: ${Transitions.all}; font-weight: 400; - padding-left: 8px; color: ${Colors.Black[400]}; ` @@ -68,24 +77,15 @@ export const StepCircle = styled.span` ` export const Step = styled.div<{ step: StepToRender }>` + align-self: flex-start; display: flex; + flex-direction: column; + gap: 8px; position: relative; align-items: center; + justify-content: center; width: fit-content; - - &:not(:first-child) { - margin-left: 12px; - } - - &:not(:last-child) { - &:after { - margin-left: 12px; - content: ''; - min-width: 20px; - height: 1px; - background-color: ${Colors.Black[500]}; - } - } + flex: 1 1 0; ${StepCircle} { ${({ step: { isActive } }) => (isActive ? activeStepCss : pastStepCss)}; @@ -96,6 +96,11 @@ export const Step = styled.div<{ step: StepToRender }>` return isActive ? 'color: white; font-weight: 700' : `color: ${Colors.Black[400]}` }}; } + + @media (min-width: ${BreakPoints.sm}px) { + flex-direction: row; + flex: auto; + } ` const StepBody = styled.div` @@ -108,4 +113,5 @@ const HorizontalStepperWrapper = styled.div` display: flex; justify-content: space-between; align-items: center; + gap: 12px; ` diff --git a/packages/ui/src/common/components/Tooltip/Tooltip.tsx b/packages/ui/src/common/components/Tooltip/Tooltip.tsx index 8b7d9f058a..f34db56099 100644 --- a/packages/ui/src/common/components/Tooltip/Tooltip.tsx +++ b/packages/ui/src/common/components/Tooltip/Tooltip.tsx @@ -366,7 +366,7 @@ export const TooltipComponent = styled.i<{ maxWidth?: boolean }>` } ` -export const TooltipContainer = styled.span<{ absolute?: boolean; maxWidth?: boolean }>` +export const TooltipContainer = styled.div<{ absolute?: boolean; maxWidth?: boolean }>` display: inline-flex; position: ${({ absolute }) => (absolute ? 'absolute' : 'relative')}; right: ${({ absolute }) => (absolute ? '-24px' : 'auto')}; diff --git a/packages/ui/src/common/components/TransactionFee.stories.tsx b/packages/ui/src/common/components/TransactionFee.stories.tsx deleted file mode 100644 index de4fcb8ac4..0000000000 --- a/packages/ui/src/common/components/TransactionFee.stories.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Meta, Story } from '@storybook/react' -import BN from 'bn.js' -import React from 'react' - -import { TransactionFee, TransactionFeeProps } from '@/common/components/TransactionFee' - -export default { - title: 'Common/TransactionFee', - component: TransactionFee, -} as Meta - -export const Default: Story = (args) => - -Default.args = { - title: 'Transaction Fee', - value: new BN(6.43535), - tooltipTitle: 'Blockchain Transaction', - tooltipText: 'This action requires a blockchain transaction, which comes with a fee', -} diff --git a/packages/ui/src/common/components/TransactionFee.tsx b/packages/ui/src/common/components/TransactionFee.tsx deleted file mode 100644 index d4b8af126c..0000000000 --- a/packages/ui/src/common/components/TransactionFee.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import BN from 'bn.js' -import React from 'react' -import { useTranslation } from 'react-i18next' - -import { BalanceInfoNarrow, InfoTitle, InfoValue } from './Modal' -import { Tooltip, TooltipDefault } from './Tooltip' -import { TokenValue } from './typography' - -export interface TransactionFeeProps { - title?: string - value: BN - tooltipText?: React.ReactNode - tooltipTitle?: string - tooltipLinkText?: React.ReactNode - tooltipLinkURL?: string -} - -export const TransactionFee = ({ - title, - value, - tooltipText, - tooltipTitle, - tooltipLinkText, - tooltipLinkURL, -}: TransactionFeeProps) => { - const { t } = useTranslation() - return ( - - {title ?? t('modals.transactionFee.label')} - - - - {tooltipText && ( - - - - )} - - ) -} diff --git a/packages/ui/src/common/components/TransactionInfo.stories.tsx b/packages/ui/src/common/components/TransactionInfo.stories.tsx new file mode 100644 index 0000000000..fe75b70266 --- /dev/null +++ b/packages/ui/src/common/components/TransactionInfo.stories.tsx @@ -0,0 +1,19 @@ +import { Meta, StoryFn } from '@storybook/react' +import BN from 'bn.js' +import React from 'react' + +import { TransactionInfo, TransactionInfoProps } from './TransactionInfo' + +export default { + title: 'Common/TransactionInfo', + component: TransactionInfo, +} as Meta + +export const Default: StoryFn = (args) => + +Default.args = { + title: 'Transaction Fee', + value: new BN(6.43535), + tooltipTitle: 'Blockchain Transaction', + tooltipText: 'This action requires a blockchain transaction, which comes with a fee', +} diff --git a/packages/ui/src/common/components/TransactionInfo.tsx b/packages/ui/src/common/components/TransactionInfo.tsx index 36a155a2ba..e9e91e2ec5 100644 --- a/packages/ui/src/common/components/TransactionInfo.tsx +++ b/packages/ui/src/common/components/TransactionInfo.tsx @@ -1,7 +1,7 @@ import BN from 'bn.js' import React from 'react' -import { BalanceInfoNarrow, InfoTitle, InfoValue } from './Modal' +import { InfoTitle, InfoValue } from './Modal' import { Tooltip, TooltipDefault } from './Tooltip' import { TokenValue } from './typography' @@ -23,22 +23,23 @@ export const TransactionInfo = ({ tooltipLinkURL, }: TransactionInfoProps) => { return ( - + <> {title} - {tooltipText && ( + {tooltipText ? ( + ) : ( + )} - + ) } diff --git a/packages/ui/src/common/components/buttons/Buttons.tsx b/packages/ui/src/common/components/buttons/Buttons.tsx index 2bb0118d38..2144ec19e1 100644 --- a/packages/ui/src/common/components/buttons/Buttons.tsx +++ b/packages/ui/src/common/components/buttons/Buttons.tsx @@ -504,20 +504,31 @@ export const ButtonLinkStyles = styled.button` ` export const ButtonsGroup = styled.div<{ align?: 'left' | 'center' | 'right' }>` - display: grid; - grid-auto-flow: column; - grid-column-gap: 8px; - align-items: center; - width: fit-content; - justify-self: ${({ align }) => { + display: flex; + flex-flow: row wrap; + gap: 8px; + + ${({ align }) => { switch (align) { case 'left': - default: - return 'start' + return css` + justify-content: start; + justify-self: start; + margin-right: auto; + ` case 'center': - return 'center' + return css` + justify-content: center; + justify-self: center; + margin-left: auto; + margin-right: auto; + ` case 'right': - return 'end' + return css` + justify-content: end; + justify-self: end; + margin-left: auto; + ` } }}; ` diff --git a/packages/ui/src/common/components/buttons/TransactionButton.tsx b/packages/ui/src/common/components/buttons/TransactionButton.tsx index 31477b7bf3..b4f89bd6d1 100644 --- a/packages/ui/src/common/components/buttons/TransactionButton.tsx +++ b/packages/ui/src/common/components/buttons/TransactionButton.tsx @@ -1,6 +1,7 @@ import React, { ReactNode } from 'react' import { ReactElement } from 'react-markdown/lib/react-markdown' +import { useResponsive } from '@/common/hooks/useResponsive' import { useTransactionStatus } from '@/common/hooks/useTransactionStatus' import { Tooltip } from '../Tooltip' @@ -9,10 +10,14 @@ import { ButtonGhost, ButtonPrimary, ButtonProps, ButtonSecondary } from '.' interface WrapperProps { children: ReactNode + isResponsive?: boolean } -export const TransactionButtonWrapper = ({ children }: WrapperProps) => { +export const TransactionButtonWrapper = ({ isResponsive, children }: WrapperProps) => { const { isTransactionPending } = useTransactionStatus() + const { size } = useResponsive() + + if (!isResponsive && (size === 'xxs' || size === 'xs')) return null if (isTransactionPending) { return {children} @@ -25,16 +30,17 @@ type StyleOption = 'primary' | 'ghost' | 'secondary' interface TransactionButtonProps extends ButtonProps { style: StyleOption + isResponsive?: boolean } -export const TransactionButton = (props: TransactionButtonProps) => { +export const TransactionButton = ({ isResponsive, disabled, ...props }: TransactionButtonProps) => { const { isTransactionPending } = useTransactionStatus() const Button = buttonTypes[props.style] return ( - -