feat: UI responsiveness on mint and AP flow (#245)

* wip: make mint flow responsive

* feat: add responsivness

* feat: add button connection

* refactor: remove iconSpacing from button for responsiveness

* styles: text ellipsis variation

* style: ellipsis on combobox
This commit is contained in:
Camila Sosa Morales 2023-04-28 12:16:24 -03:00 committed by GitHub
parent 0983e28755
commit f685d6800b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 174 additions and 169 deletions

View File

@ -2,6 +2,7 @@ import { styled } from '@/theme';
export abstract class CardStyles { export abstract class CardStyles {
static readonly Container = styled('div', { static readonly Container = styled('div', {
width: '$full',
backgroundColor: '$slate2', backgroundColor: '$slate2',
borderRadius: '$xlh', borderRadius: '$xlh',
padding: '$7', padding: '$7',

View File

@ -1,57 +1,23 @@
import React from 'react'; import React from 'react';
import { ButtonProps } from '.'; import { ButtonProps } from '.';
import {
StyledButtonContentFlex,
StyledButtonContentGrid,
} from './button-content.styles';
import { ButtonIcon } from './button-icon'; import { ButtonIcon } from './button-icon';
export type ButtonContentProps = Pick< export type ButtonContentProps = Pick<
ButtonProps, ButtonProps,
| 'leftIcon' 'leftIcon' | 'rightIcon' | 'children'
| 'rightIcon'
| 'topIcon'
| 'bottomIcon'
| 'children'
| 'iconSpacing'
>; >;
export const ButtonContent: React.FC<ButtonContentProps> = (props) => { export const ButtonContent: React.FC<ButtonContentProps> = (props) => {
const { const { leftIcon, rightIcon, children } = props;
leftIcon,
rightIcon,
topIcon,
bottomIcon,
children,
iconSpacing = '1h',
} = props;
const midNode = ( const midNode = (
<> <>
{leftIcon && ( {leftIcon && <ButtonIcon>{leftIcon}</ButtonIcon>}
<ButtonIcon css={{ marginRight: `$${iconSpacing}` }}>
{leftIcon}
</ButtonIcon>
)}
{children} {children}
{rightIcon && ( {rightIcon && <ButtonIcon>{rightIcon}</ButtonIcon>}
<ButtonIcon css={{ marginLeft: `$${iconSpacing}` }}>
{rightIcon}
</ButtonIcon>
)}
</> </>
); );
if (!topIcon && !bottomIcon) { return midNode;
return midNode;
}
return (
<StyledButtonContentGrid>
{topIcon && <ButtonIcon>{topIcon}</ButtonIcon>}
<StyledButtonContentFlex>{midNode}</StyledButtonContentFlex>
{bottomIcon && <ButtonIcon>{bottomIcon}</ButtonIcon>}
</StyledButtonContentGrid>
);
}; };

View File

@ -49,11 +49,6 @@ export interface ButtonProps extends StyledButtonProps {
* @type React.ReactElement * @type React.ReactElement
*/ */
bottomIcon?: React.ReactElement; bottomIcon?: React.ReactElement;
/**
* The space between the button icon and label.
* @type SystemProps["marginRight"]
*/
iconSpacing?: string;
/** /**
* Replace the spinner component when `isLoading` is set to `true` * Replace the spinner component when `isLoading` is set to `true`
* @type React.ReactElement * @type React.ReactElement

View File

@ -13,9 +13,6 @@ export const Button = forwardStyledRef<HTMLButtonElement, ButtonProps>(
spinnerPlacement = 'start', spinnerPlacement = 'start',
spinner, spinner,
loadingText, loadingText,
iconSpacing,
topIcon,
bottomIcon,
rightIcon, rightIcon,
leftIcon, leftIcon,
isFullWidth, isFullWidth,
@ -26,9 +23,6 @@ export const Button = forwardStyledRef<HTMLButtonElement, ButtonProps>(
const contentProps = { const contentProps = {
rightIcon, rightIcon,
leftIcon, leftIcon,
bottomIcon,
topIcon,
iconSpacing,
children, children,
}; };
@ -40,16 +34,12 @@ export const Button = forwardStyledRef<HTMLButtonElement, ButtonProps>(
data-loading={isLoading} data-loading={isLoading}
css={{ css={{
width: isFullWidth ? '100%' : undefined, width: isFullWidth ? '100%' : undefined,
...(ownProps?.css || {}), ...ownProps?.css,
}} }}
{...ownProps} {...ownProps}
> >
{isLoading && spinnerPlacement === 'start' && ( {isLoading && spinnerPlacement === 'start' && (
<ButtonSpinner <ButtonSpinner label={loadingText} placement={spinnerPlacement}>
label={loadingText}
placement={spinnerPlacement}
spacing={iconSpacing}
>
{spinner} {spinner}
</ButtonSpinner> </ButtonSpinner>
)} )}
@ -65,11 +55,7 @@ export const Button = forwardStyledRef<HTMLButtonElement, ButtonProps>(
)} )}
{isLoading && spinnerPlacement === 'end' && ( {isLoading && spinnerPlacement === 'end' && (
<ButtonSpinner <ButtonSpinner label={loadingText} placement={spinnerPlacement}>
label={loadingText}
placement={spinnerPlacement}
spacing={iconSpacing}
>
{spinner} {spinner}
</ButtonSpinner> </ButtonSpinner>
)} )}

View File

@ -8,7 +8,6 @@ type OmittedProps =
| 'isFullWidth' | 'isFullWidth'
| 'rightIcon' | 'rightIcon'
| 'loadingText' | 'loadingText'
| 'iconSpacing'
| 'spinnerPlacement'; | 'spinnerPlacement';
type BaseButtonProps = Omit<ButtonProps, OmittedProps>; type BaseButtonProps = Omit<ButtonProps, OmittedProps>;

View File

@ -62,7 +62,7 @@ export const ColorPicker: React.FC<ColorPickerProps> = ({
</Button> </Button>
<input <input
ref={inputColorRef} ref={inputColorRef}
className="absolute right-16" className="absolute right-16 h-5"
type="color" type="color"
value={logoColor} value={logoColor}
onChange={handleColorChange} onChange={handleColorChange}

View File

@ -1,3 +1,13 @@
import { styled } from '@/theme'; import { styled } from '@/theme';
export const Text = styled('span'); export const Text = styled('span', {
variants: {
ellipsis: {
true: {
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
},
},
},
});

View File

@ -6,12 +6,17 @@ type RowDataProps = {
leftIcon: React.ReactNode; leftIcon: React.ReactNode;
label: string; label: string;
rightComponent: React.ReactNode; rightComponent: React.ReactNode;
onClick?: () => void;
}; };
export const RowData = forwardStyledRef<HTMLDivElement, RowDataProps>( export const RowData = forwardStyledRef<HTMLDivElement, RowDataProps>(
({ leftIcon, label, rightComponent, ...props }, ref) => { ({ leftIcon, label, rightComponent, onClick, ...props }, ref) => {
const handleOnClick = (): void => {
if (onClick) onClick();
};
return ( return (
<S.Container ref={ref} {...props}> <S.Container ref={ref} {...props} onClick={handleOnClick}>
<S.Text.Container> <S.Text.Container>
{leftIcon} {leftIcon}
<S.Text.Label>{label}</S.Text.Label> <S.Text.Label>{label}</S.Text.Label>

View File

@ -0,0 +1,26 @@
import { Flex } from '@/components';
import { styled } from '@/theme';
export const StepStyles = {
Container: styled(Flex, {
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
width: '$full',
gap: '$6',
'@media (min-width: 768px)': {
flexDirection: 'row',
justifyContent: 'center',
},
'@media (min-width: 1024px)': {
gap: '$34',
},
}),
Indicator: styled(Flex, {
flexDirection: 'column',
justifyContent: 'center',
maxWidth: '$106',
}),
};

View File

@ -1,37 +1,6 @@
import { Flex, Stepper } from '@/components'; import { Stepper } from '@/components';
type StepperIndicatorContainerProps = { import { StepStyles as S } from './step.styles';
children: React.ReactNode;
};
const StepperIndicatorContainer: React.FC<StepperIndicatorContainerProps> = ({
children,
}: StepperIndicatorContainerProps) => {
return (
<Flex
css={{
flexDirection: 'column',
justifyContent: 'center',
mr: '$34',
width: '$106',
}}
>
{children}
</Flex>
);
};
type MintStepContainerProps = {
children: React.ReactNode;
};
const Container: React.FC<MintStepContainerProps> = ({
children,
}: MintStepContainerProps) => (
<Flex css={{ flexDirection: 'row', justifyContent: 'center' }}>
{children}
</Flex>
);
type StepProps = { type StepProps = {
children: React.ReactNode; children: React.ReactNode;
@ -40,12 +9,12 @@ type StepProps = {
export const Step: React.FC<StepProps> = ({ children, header }: StepProps) => { export const Step: React.FC<StepProps> = ({ children, header }: StepProps) => {
return ( return (
<Container> <S.Container>
<StepperIndicatorContainer> <S.Indicator>
<Stepper.Indicator /> <Stepper.Indicator />
<h2 className="text-4xl">{header}</h2> <h2 className="text-4xl">{header}</h2>
</StepperIndicatorContainer> </S.Indicator>
{children} {children}
</Container> </S.Container>
); );
}; };

View File

@ -10,6 +10,7 @@ export const themeGlobals = globalCss({
fontFamily: 'Manrope', fontFamily: 'Manrope',
fontSize: '16px', fontSize: '16px',
'@media (max-width: 850px)': { '@media (max-width: 850px)': {
fontSize: '13px', fontSize: '13px',
}, },

View File

@ -6,7 +6,7 @@ export const CreateAccessPointForm: React.FC = () => {
const { prevStep } = Stepper.useContext(); const { prevStep } = Stepper.useContext();
return ( return (
<Card.Container css={{ width: '$107h' }}> <Card.Container css={{ maxWidth: '$107h' }}>
<Card.Heading <Card.Heading
title="Enter Domain" title="Enter Domain"
leftIcon={ leftIcon={

View File

@ -5,7 +5,7 @@ import { APRecordCardHeader } from './ap-record-header';
export const APRecordStep: React.FC = () => { export const APRecordStep: React.FC = () => {
return ( return (
<Card.Container css={{ width: '$107h' }}> <Card.Container css={{ maxWidth: '$107h' }}>
<APRecordCardHeader /> <APRecordCardHeader />
<APRecordCardBody /> <APRecordCardBody />
</Card.Container> </Card.Container>

View File

@ -111,7 +111,7 @@ export const CreateAccessPointPreview: React.FC = () => {
}, [writeStatus, transactionStatus]); }, [writeStatus, transactionStatus]);
return ( return (
<Card.Container css={{ width: '$107h' }}> <Card.Container css={{ maxWidth: '$107h' }}>
<Card.Heading <Card.Heading
title="Review Details" title="Review Details"
leftIcon={ leftIcon={

View File

@ -6,7 +6,7 @@ import { AccessPointDataFragment } from './create-ap-preview';
export const CreateAccessPointSuccess: React.FC = () => { export const CreateAccessPointSuccess: React.FC = () => {
const { nfa } = CreateAccessPoint.useContext(); const { nfa } = CreateAccessPoint.useContext();
return ( return (
<Card.Container css={{ width: '$107h' }}> <Card.Container css={{ maxWidth: '$107h' }}>
<Card.Heading <Card.Heading
title="Hosting Successful" title="Hosting Successful"
leftIcon={ leftIcon={

View File

@ -0,0 +1,34 @@
import { Button, ButtonProps } from '@/components';
import { forwardStyledRef } from '@/theme';
import { Icon, IconName } from '../../components/core/icon';
type ButtonConnectionProps = {
icon: IconName;
label: string;
} & Omit<ButtonProps, 'rightIcon' | 'leftIcon'>;
export const ButtonConnection = forwardStyledRef<
HTMLButtonElement,
ButtonConnectionProps
>(({ icon, label, ...props }, ref) => {
return (
<Button
ref={ref}
{...props}
size="lg"
variant="ghost"
css={{
backgroundColor: '$slate4',
color: '$slate12',
justifyContent: 'space-between',
py: '$2h',
}}
rightIcon={
<Icon name={icon} css={{ color: 'white', fontSize: '$4xl' }} />
}
>
{label}
</Button>
);
});

View File

@ -1,7 +1,7 @@
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import { Button, Icon } from '@/components';
import { githubActions, useAppDispatch, useGithubStore } from '@/store'; import { githubActions, useAppDispatch, useGithubStore } from '@/store';
import { ButtonConnection } from '@/views/mint/button-connection';
import { Mint } from '@/views/mint/mint.context'; import { Mint } from '@/views/mint/mint.context';
export const GithubButton: React.FC = () => { export const GithubButton: React.FC = () => {
@ -18,22 +18,11 @@ export const GithubButton: React.FC = () => {
}, [setGithubStep, state]); }, [setGithubStep, state]);
return ( return (
<Button <ButtonConnection
iconSpacing="59" icon={'github'}
size="lg" label={'GitHub'}
variant="ghost"
css={{
backgroundColor: '$slate4',
color: '$slate12',
py: '$2h',
}}
onClick={handleGithubLogin} onClick={handleGithubLogin}
disabled={state === 'loading'} disabled={state === 'loading'}
rightIcon={ />
<Icon name="github" css={{ color: 'white', fontSize: '$4xl' }} />
}
>
GitHub
</Button>
); );
}; };

View File

@ -7,13 +7,18 @@ export const GithubConnect: React.FC = () => {
const { prevStep } = Stepper.useContext(); const { prevStep } = Stepper.useContext();
return ( return (
<Card.Container> <Card.Container css={{ maxWidth: '$107h' }}>
<MintCardHeader title="Connect GitHub" onClickBack={prevStep} /> <MintCardHeader title="Connect GitHub" onClickBack={prevStep} />
<Card.Body> <Card.Body>
<Grid css={{ rowGap: '$6' }}> <Grid css={{ rowGap: '$6' }}>
<GithubButton /> <GithubButton />
<Card.Text <Card.Text
css={{ height: '$46h', width: '$95', fontSize: '$md', px: '$12' }} css={{
height: '$46h',
maxWidth: '$95',
fontSize: '$md',
px: '$12',
}}
> >
<span> <span>
After connecting your GitHub, your repositories will show here. After connecting your GitHub, your repositories will show here.

View File

@ -0,0 +1,13 @@
import { Text } from '@/components';
import { styled } from '@/theme';
export const TextStyles = styled(Text, {
maxWidth: '12.5rem',
'@media (min-width: 375px)': {
maxWidth: '17rem',
},
'@media (min-width: 425px)': {
maxWidth: '18rem',
},
});

View File

@ -10,6 +10,7 @@ import {
import { AppLog } from '@/utils'; import { AppLog } from '@/utils';
import { Mint } from '@/views/mint/mint.context'; import { Mint } from '@/views/mint/mint.context';
import { useMintFormContext } from '@/views/mint/nfa-step/form-step'; import { useMintFormContext } from '@/views/mint/nfa-step/form-step';
import { TextStyles } from './repo-branch-commit-fields.styles';
export const RepoBranchCommitFields: React.FC = () => { export const RepoBranchCommitFields: React.FC = () => {
const { queryLoading, branches } = useGithubStore(); const { queryLoading, branches } = useGithubStore();
@ -105,12 +106,16 @@ export const RepoBranchCommitFields: React.FC = () => {
{(selected) => ( {(selected) => (
<> <>
<Icon name="branch" /> <Icon name="branch" />
{selected?.name || 'Select a branch'} <TextStyles ellipsis>
{selected?.name || 'Select a branch'}
</TextStyles>
</> </>
)} )}
</Field> </Field>
<Options>{(item) => item.name}</Options> <Options>
{(item) => <TextStyles ellipsis>{item.name}</TextStyles>}
</Options>
</> </>
)} )}
</Form.Combobox> </Form.Combobox>

View File

@ -5,7 +5,7 @@ import { RepoConfigurationHeader } from './repo-configuration-header';
export const GithubRepoConfiguration: React.FC = () => { export const GithubRepoConfiguration: React.FC = () => {
return ( return (
<Card.Container css={{ width: '$107h' }}> <Card.Container css={{ minWidth: '17rem', maxWidth: '$107h' }}>
<RepoConfigurationHeader /> <RepoConfigurationHeader />
<RepoConfigurationBody /> <RepoConfigurationBody />
</Card.Container> </Card.Container>

View File

@ -81,9 +81,10 @@ export const GithubRepositoryConnection: React.FC = () => {
<S.Container> <S.Container>
<S.Row> <S.Row>
<UserOrgsCombobox /> <UserOrgsCombobox />
<InputGroup css={{ flex: 1 }}> <InputGroup>
<S.Group.Icon name="search" /> <S.Group.Icon name="search" />
<InputGroupText <InputGroupText
css={{ overflow: 'hidden' }}
placeholder="Search repo" placeholder="Search repo"
onChange={handleSearchChange} onChange={handleSearchChange}
/> />

View File

@ -30,11 +30,11 @@ export const Repository: React.FC<RepositoryProps> = ({
leftIcon={<Icon name="github" />} leftIcon={<Icon name="github" />}
label={repository.name} label={repository.name}
css={{ cursor: 'pointer', my: '$4' }} css={{ cursor: 'pointer', my: '$4' }}
onClick={handleSelectRepo}
rightComponent={ rightComponent={
<Button <Button
colorScheme="blue" colorScheme="blue"
variant="outline" variant="outline"
onClick={handleSelectRepo}
css={{ py: '$1', height: '$5', borderRadius: '$md' }} css={{ py: '$1', height: '$5', borderRadius: '$md' }}
> >
Use for NFA Use for NFA

View File

@ -1,6 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { Avatar, Combobox, Icon } from '@/components'; import { Avatar, Combobox, Icon, Text } from '@/components';
import { import {
githubActions, githubActions,
GithubClient, GithubClient,
@ -21,7 +21,9 @@ const renderSelected = (selected?: GithubClient.UserData): JSX.Element => (
) : ( ) : (
<Icon name="github" css={{ fontSize: '$2xl' }} /> <Icon name="github" css={{ fontSize: '$2xl' }} />
)} )}
{selected?.label || 'Select'} <Text ellipsis css={{ maxWidth: '60%' }}>
{selected?.label || 'Select'}
</Text>
</> </>
); );
@ -75,7 +77,7 @@ export const UserOrgsCombobox: React.FC = () => {
<Combobox <Combobox
items={userAndOrganizations} items={userAndOrganizations}
unattached unattached
css={{ flex: 1, minWidth: '$44' }} css={{ width: '$full', flexGrow: 1 }}
selected={[selectedUserOrg, handleUserOrgChange]} selected={[selectedUserOrg, handleUserOrgChange]}
queryKey="label" queryKey="label"
> >

View File

@ -0,0 +1,13 @@
import { Flex } from '@/components';
import { styled } from '@/theme';
export const MintStyles = {
Container: styled(Flex, {
height: '100%',
justifyContent: 'center',
'@media (min-width: 1024px)': {
flexDirection: 'row',
},
}),
};

View File

@ -1,25 +1,17 @@
import { Flex } from '@/components';
import { Mint as MintContext } from './mint.context'; import { Mint as MintContext } from './mint.context';
import { MintStyles as MS } from './mint.styles';
import { MintStepper } from './mint-stepper'; import { MintStepper } from './mint-stepper';
import { MintFormProvider, useMintFormContextInit } from './nfa-step/form-step'; import { MintFormProvider, useMintFormContextInit } from './nfa-step/form-step';
export const Mint: React.FC = () => { export const Mint: React.FC = () => {
const context = useMintFormContextInit(); const context = useMintFormContextInit();
return ( return (
<Flex <MS.Container>
css={{
height: '100%',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
}}
>
<MintContext.Provider> <MintContext.Provider>
<MintFormProvider value={context}> <MintFormProvider value={context}>
<MintStepper /> <MintStepper />
</MintFormProvider> </MintFormProvider>
</MintContext.Provider> </MintContext.Provider>
</Flex> </MS.Container>
); );
}; };

View File

@ -78,7 +78,7 @@ export const MintFormStep: React.FC = () => {
}; };
return ( return (
<Card.Container css={{ width: '$107h' }}> <Card.Container css={{ maxWidth: '$107h' }}>
<MintCardHeader title="NFA Details" onClickBack={handlePrevStep} /> <MintCardHeader title="NFA Details" onClickBack={handlePrevStep} />
<Card.Body> <Card.Body>
<Grid <Grid

View File

@ -100,7 +100,7 @@ export const VerifyNFAStep: React.FC = () => {
}; };
return ( return (
<Card.Container css={{ width: '$107h' }}> <Card.Container css={{ maxWidth: '$107h' }}>
<MintCardHeader title="Verify NFA" onClickBack={prevStep} /> <MintCardHeader title="Verify NFA" onClickBack={prevStep} />
<Card.Body> <Card.Body>
<Flex css={{ flexDirection: 'column', gap: '$6' }}> <Flex css={{ flexDirection: 'column', gap: '$6' }}>

View File

@ -43,7 +43,7 @@ export const NftCard: React.FC<NftCardProps> = ({
} = useMintFormContext(); } = useMintFormContext();
return ( return (
<Card.Container css={{ width: '$107h', p: '$0' }}> <Card.Container css={{ maxWidth: '$107h', p: '$0' }}>
<NFAPreview <NFAPreview
color={logoColor} color={logoColor}
logo={appLogo} logo={appLogo}

View File

@ -1,6 +1,8 @@
import { ConnectKitButton } from 'connectkit'; import { ConnectKitButton } from 'connectkit';
import { Button, Icon, Stepper } from '@/components'; import { Button, Stepper } from '@/components';
import { ButtonConnection } from '../button-connection';
export const ConnectWalletButton: React.FC = () => { export const ConnectWalletButton: React.FC = () => {
const { nextStep } = Stepper.useContext(); const { nextStep } = Stepper.useContext();
@ -11,31 +13,17 @@ export const ConnectWalletButton: React.FC = () => {
if (isConnected && address) { if (isConnected && address) {
return ( return (
<Button onClick={nextStep} css={{ color: '$slate12' }}> <Button onClick={nextStep} css={{ color: '$slate12' }}>
Connected address: {truncatedAddress}. Continue {truncatedAddress}. Continue
</Button> </Button>
); );
} else { } else {
return ( return (
<Button <ButtonConnection
icon={'ethereum'}
label={' Connect Wallet'}
disabled={isConnected} disabled={isConnected}
iconSpacing="44"
size="lg"
variant="ghost"
css={{
backgroundColor: '$slate4',
color: '$slate12',
py: '$2h',
}}
onClick={show} onClick={show}
rightIcon={ />
<Icon
name="ethereum"
css={{ color: 'white', fontSize: '$4xl' }}
/>
}
>
Connect Wallet
</Button>
); );
} }
}} }}

View File

@ -4,7 +4,7 @@ import { ConnectWalletButton } from './connect-wallet-button';
export const WalletStep: React.FC = () => { export const WalletStep: React.FC = () => {
return ( return (
<Card.Container> <Card.Container css={{ maxWidth: '$107h' }}>
<Card.Heading <Card.Heading
title="Connect Wallet" title="Connect Wallet"
rightIcon={ rightIcon={
@ -20,7 +20,12 @@ export const WalletStep: React.FC = () => {
<Grid css={{ rowGap: '$6' }}> <Grid css={{ rowGap: '$6' }}>
<ConnectWalletButton /> <ConnectWalletButton />
<Card.Text <Card.Text
css={{ height: '$46h', width: '$95', fontSize: '$md', px: '$12' }} css={{
height: '$46h',
maxWidth: '$95',
fontSize: '$md',
px: '$12',
}}
> >
<span>Connect with the wallet you want to mint & own the NFA.</span> <span>Connect with the wallet you want to mint & own the NFA.</span>
</Card.Text> </Card.Text>