Skip to content

Commit

Permalink
feat(APP-3769): Update layouts of DataListItem components (#332)
Browse files Browse the repository at this point in the history
  • Loading branch information
thekidnamedkd authored Nov 22, 2024
1 parent 16f92af commit 442e870
Show file tree
Hide file tree
Showing 23 changed files with 296 additions and 243 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Added

- Update `VoteDataListItem` component to add "Voted" string and possibility to customise it through the
`confirmationLabel` property

### Fixed

- Update layout of `DataListItem` core component and layouts of components using it (Asset, Dao, Member, Proposal,
Transaction, Vote)
- Update implementation of `DataListItem` skeleton components for better parity and no layout shift
- Improve responsiveness for `DefinitionList` container and items for middle breakpoints
- Update `DaoAvatar` to correctly set text size depending on `size` property
- Update `formatterUtils` documentation to add number formatting examples
- Include styles on `AccordionItemHeader` for stronger visual cue when expanded

### Changed

- Remove `plugin` property from `DaoDataListItem` module component
- Update `formatterUtils` documentation to add number formatting examples
- Update minor and patch dependencies
- Update `eslint` to v9
- Bump `cross-spawn` from 7.0.3 to 7.0.5
Expand All @@ -22,6 +34,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Removed `xs` size variant from `Avatar` component
- Update eslint rules to enforce consistent type imports and exports

# <<<<<<< HEAD

### Fixed

- Improve responsiveness for `DefinitionList` container and items for middle breakpoints
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const DataListFilter: React.FC<IDataListFilterProps> = (props) => {
'flex flex-row items-center rounded-xl border p-3 pr-2 transition-all md:pl-4 md:pr-3',
'border-neutral-100 bg-neutral-0 text-neutral-500 shadow-neutral-sm',
'text-base font-normal leading-tight',
'hover:border-neutral-300 hover:shadow-neutral',
'hover:border-neutral-200 hover:shadow-neutral',
'focus-within:border-primary-400 focus-within:shadow-primary',
'focus-within:hover:border-primary-400 focus-within:hover:shadow-primary',
)}
Expand Down
6 changes: 3 additions & 3 deletions src/core/components/dataList/dataListItem/dataListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ export const DataListItem: React.FC<IDataListItemProps> = (props) => {
const isInteractiveElement = !isSkeletonElement && (isLinkElement || props.onClick != null);

const actionItemClasses = classNames(
'w-full rounded-xl border border-neutral-100 bg-neutral-0 px-4 py-3 text-left outline-none transition-all focus:outline-none', // Default
'w-full rounded-xl border border-neutral-100 bg-neutral-0 px-4 text-left shadow-neutral-sm outline-none transition-all focus:outline-none', // Default
{ 'focus-visible:ring focus-visible:ring-primary focus-visible:ring-offset': isInteractiveElement }, // Interactive focus state
{ 'hover:border-neutral-200 hover:shadow-neutral-md active:border-neutral-300': isInteractiveElement }, // Interactive hover state
{ 'hover:border-neutral-200 hover:shadow-neutral active:border-neutral-300': isInteractiveElement }, // Interactive hover state
{ 'cursor-pointer': isInteractiveElement }, // Interactive default state
{ 'cursor-default': !isInteractiveElement }, // Non-interactive default state
'md:px-6 md:py-3.5', // Responsive
'md:px-6', // Responsive
className,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ const meta: Meta<typeof DataList.Root> = {
type Story = StoryObj<typeof DataList.Root>;

const ListItemComponent = (props: { id: number }) => (
<DataListItem className="flex flex-row gap-2" href="https://aragon.org" target="_blank">
<DataListItem className="flex flex-row gap-2 py-4 md:py-6" href="https://aragon.org" target="_blank">
<Avatar />
<p className="grow text-base font-normal leading-normal text-neutral-800">#{props.id}</p>
<p className="text-sm font-normal leading-normal text-neutral-500">Some info</p>
</DataListItem>
);

const ListItemComponentLoading = () => (
<DataListItem className="flex animate-pulse flex-row items-center gap-2">
<DataListItem className="flex animate-pulse flex-row items-center gap-2 py-4 md:py-6">
<div className="size-6 rounded-full bg-neutral-50" />
<div className="flex grow flex-col gap-2">
<div className="h-2 grow rounded bg-neutral-50" />
Expand Down
1 change: 1 addition & 0 deletions src/modules/assets/copy/modulesCopy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export const modulesCopy = {
voteDataListItemStructure: {
yourDelegate: 'Your delegate',
you: 'You',
voted: 'Voted',
},
voteProposalDataListItemStructure: {
voted: 'Voted',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,24 @@ export const AssetDataListItemSkeleton: React.FC<IAssetDataListItemSkeletonProps
tabIndex={0}
aria-busy="true"
aria-label="loading"
className={classNames('flex flex-col gap-y-4 bg-neutral-0 py-3 md:py-3.5', className)}
className={classNames(
'flex min-h-[70px] w-full items-center gap-x-3 gap-y-4 bg-neutral-0 py-3 md:min-h-[92.5px] md:py-5',
className,
)}
{...otherProps}
>
<div className="flex w-full items-center gap-x-3 py-0.5 md:py-1.5">
<StateSkeletonCircular responsiveSize={{ md: 'lg' }} />
<div className="flex w-full justify-between">
<div className="flex w-full flex-col gap-y-1 md:gap-y-1.5">
<StateSkeletonBar className="shrink-0" responsiveSize={{ md: 'lg' }} width="100%" />
<div className="flex size-full items-center justify-start md:w-1/2">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="50%" />
</div>
</div>
<div className="flex w-full flex-col items-end gap-y-1 md:gap-y-1.5">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="40%" />
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="33%" />
<StateSkeletonCircular responsiveSize={{ md: 'lg' }} />
<div className="flex w-full justify-between">
<div className="flex w-full flex-col gap-y-1 md:gap-y-1.5">
<StateSkeletonBar className="shrink-0" responsiveSize={{ md: 'lg' }} width="100%" />
<div className="flex size-full items-center justify-start md:w-1/2">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="50%" />
</div>
</div>
<div className="flex w-full flex-col items-end gap-y-1 md:gap-y-1.5">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="40%" />
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="33%" />
</div>
</div>
</DataList.Item>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type IAssetDataListItemStructureProps = IDataListItemProps & {
};

export const AssetDataListItemStructure: React.FC<IAssetDataListItemStructureProps> = (props) => {
const { logoSrc, name, amount, symbol, fiatPrice, priceChange = 0, ...otherProps } = props;
const { logoSrc, name, amount, symbol, fiatPrice, priceChange = 0, className, ...otherProps } = props;

const { copy } = useGukModulesContext();

Expand Down Expand Up @@ -79,36 +79,32 @@ export const AssetDataListItemStructure: React.FC<IAssetDataListItemStructurePro
});

return (
<DataList.Item {...otherProps}>
<div className="flex gap-x-3 py-0 md:py-1.5">
<div className="flex items-center">
<Avatar src={logoSrc} responsiveSize={{ md: 'md', sm: 'sm' }} className="block" />
<DataList.Item className={classNames('flex items-center gap-x-3 py-3 md:py-5', className)} {...otherProps}>
<Avatar src={logoSrc} responsiveSize={{ md: 'md', sm: 'sm' }} className="block" />
<div className="flex w-full min-w-0 shrink items-center justify-between gap-3">
<div className="flex flex-col gap-y-1 truncate">
<span className="truncate text-base leading-tight text-neutral-800 md:text-lg">{name}</span>
<p className="truncate text-sm leading-tight text-neutral-500 md:text-base">
<span>{formattedAmount} </span>
<span className="truncate">{symbol}</span>
</p>
</div>
<div className="flex w-full min-w-0 shrink justify-between gap-3">
<div className="flex flex-col gap-y-0.5 truncate">
<span className="truncate text-sm leading-tight text-neutral-800 md:text-base">{name}</span>
<p className="truncate text-sm leading-tight text-neutral-500 md:text-base">
<span>{formattedAmount} </span>
<span className="truncate">{symbol}</span>
</p>
</div>
<div className="flex flex-col items-end justify-center gap-y-0.5">
{fiatPrice ? (
<>
<span className="text-sm leading-tight text-neutral-800 md:text-base">
{formattedPrice}
</span>
<div className="flex items-center gap-x-1">
<span className={changedAmountClasses}>{formattedPriceChanged}</span>
<Tag label={formattedPriceChangedPercentage!} variant={tagVariant} />
</div>
</>
) : (
<span className="text-sm leading-tight text-neutral-800 md:text-base">
{copy.assetDataListItemStructure.unknown}
<div className="flex flex-col items-end justify-center gap-y-1">
{fiatPrice ? (
<>
<span className="text-base leading-tight text-neutral-800 md:text-lg">
{formattedPrice}
</span>
)}
</div>
<div className="flex items-center gap-x-1">
<span className={changedAmountClasses}>{formattedPriceChanged}</span>
<Tag label={formattedPriceChangedPercentage!} variant={tagVariant} />
</div>
</>
) : (
<span className="text-sm leading-tight text-neutral-800 md:text-base">
{copy.assetDataListItemStructure.unknown}
</span>
)}
</div>
</div>
</DataList.Item>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import classNames from 'classnames';
import type React from 'react';
import { DataList, type IDataListItemProps, StateSkeletonBar, StateSkeletonCircular } from '../../../../../core';

Expand All @@ -7,23 +8,29 @@ export const DaoDataListItemSkeleton: React.FC<IDaoDataListItemSkeletonProps> =
const { className, ...otherProps } = props;

return (
<DataList.Item tabIndex={0} aria-busy="true" aria-label="loading" {...otherProps}>
<div className="grid gap-y-5 py-1.5">
<div className="flex w-full justify-between space-x-4">
<div className="grid w-full gap-y-3 text-neutral-800 md:w-2/3 md:gap-y-2">
<StateSkeletonBar size="xl" responsiveSize={{ md: '2xl' }} width="100%" />
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="50%" />
</div>
<StateSkeletonCircular size="lg" />
</div>
<div className="flex flex-col gap-y-2">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="100%" />
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="85%" />
</div>
<div className="flex w-3/4 justify-between gap-x-8 text-neutral-400 md:w-1/2">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="50%" />
<DataList.Item
tabIndex={0}
aria-busy="true"
aria-label="loading"
className={classNames(
'flex min-h-[173.5px] w-full flex-col justify-center gap-y-3 py-4 md:min-h-[207px] md:gap-y-4 md:py-6',
className,
)}
{...otherProps}
>
<div className="flex w-full justify-between">
<div className="flex w-2/3 flex-col gap-y-2.5 text-neutral-800">
<StateSkeletonBar size="lg" responsiveSize={{ md: 'xl' }} width="100%" />
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="50%" />
</div>
<StateSkeletonCircular size="md" responsiveSize={{ md: 'lg' }} />
</div>
<div className="flex w-full flex-col gap-y-2">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="100%" />
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="85%" />
</div>
<div className="flex w-3/4 justify-between text-neutral-400 md:w-1/2">
<StateSkeletonBar responsiveSize={{ md: 'lg' }} width="50%" />
</div>
</DataList.Item>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export const Default: Story = {
logoSrc: 'https://cdn.discordapp.com/icons/672466989217873929/acffa3e9e09ac5962ff803a5f8649040.webp?size=240',
description:
'Papito DAO is responsible for maximizing effective coordination and collaboration between different Patito teams and enabling them to perform at their best ability with the highest velocity they can achieve. Our main focus is on managing the day-to-day tasks of the Patito Guilds, such as enabling contractual relationships, legal operations, accounting, finance, and HR. We are also responsible for addressing any issues that may arise within the teams and deploying new tools, and infrastructure to ensure smooth operations.',
plugin: 'token-based',
network: 'Ethereum Mainnet',
ens: 'patito.dao.eth',
},
Expand All @@ -36,7 +35,6 @@ export const LongNames: Story = {
logoSrc: 'https://cdn.discordapp.com/icons/672466989217873929/acffa3e9e09ac5962ff803a5f8649040.webp?size=240',
description:
'Papito DAO is responsible for maximizing effective coordination and collaboration between different Patito teams and enabling them to perform at their best ability with the highest velocity they can achieve. Our main focus is on managing the day-to-day tasks of the Patito Guilds, such as enabling contractual relationships, legal operations, accounting, finance, and HR. We are also responsible for addressing any issues that may arise within the teams and deploying new tools, and infrastructure to ensure smooth operations.',
plugin: 'token-based',
network: 'Ethereum Mainnet',
ens: 'a_dao_with_an_extremely_long_ens_name_that_should_be_truncated.dao.eth',
},
Expand All @@ -50,7 +48,6 @@ export const Fallback: Story = {
name: 'Patito DAO',
description:
'Papito DAO is responsible for maximizing effective coordination and collaboration between different Patito teams and enabling them to perform at their best ability with the highest velocity they can achieve. Our main focus is on managing the day-to-day tasks of the Patito Guilds, such as enabling contractual relationships, legal operations, accounting, finance, and HR. We are also responsible for addressing any issues that may arise within the teams and deploying new tools, and infrastructure to ensure smooth operations.',
plugin: 'token-based',
network: 'Ethereum Mainnet',
ens: 'patito.dao.eth',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,9 @@ describe('<DaoDataListItemStructure /> component', () => {
expect(descriptionElement).toHaveClass('line-clamp-2');
});

it('renders the network and plugin information correctly', () => {
it('renders the network information correctly', () => {
const network = 'ethereum';
const plugin = 'token-based';
render(createTestComponent({ network, plugin }));
render(createTestComponent({ network }));
expect(screen.getByText(network)).toBeInTheDocument();
expect(screen.getByText(plugin)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,47 +23,32 @@ export type IDaoDataListItemStructureProps = IDataListItemProps & {
* The ENS (Ethereum Name Service) address of the DAO.
*/
ens?: string;
/**
* The plugin used by the DAO.
* @default token-based
*/
plugin?: string;
/**
* The network on which the DAO operates.
*/
network?: string;
};

export const DaoDataListItemStructure: React.FC<IDaoDataListItemStructureProps> = (props) => {
const { name, logoSrc, description, network, plugin = 'token-based', address, ens, ...otherProps } = props;
const { name, logoSrc, description, network, address, ens, ...otherProps } = props;

return (
<DataList.Item {...otherProps}>
<div className="grid gap-y-4 py-1 md:py-1.5">
<div className="flex w-full justify-between gap-2">
<div className="grid shrink gap-y-1.5 text-neutral-800">
<Heading size="h2" as="h1" className="truncate">
{name}
</Heading>
<Heading size="h4" as="h2" className="truncate">
{ens ?? address}
</Heading>
</div>
<DaoAvatar name={name} src={logoSrc} size="md" />
</div>
<p className="line-clamp-2 text-base font-normal leading-normal text-neutral-500 md:text-lg">
{description}
</p>
<div className="flex space-x-6 text-neutral-400 md:space-x-8">
<div className="flex items-center gap-2 text-sm md:text-base">
<span className="capitalize">{network}</span>
<Icon icon={IconType.BLOCKCHAIN_BLOCKCHAIN} />
</div>
<div className="flex items-center gap-2 text-sm md:text-base">
<span className="capitalize">{plugin}</span>
<Icon icon={IconType.APP_MEMBERS} />
</div>
<DataList.Item className="grid gap-y-3 py-4 md:gap-y-4 md:py-6" {...otherProps}>
<div className="flex w-full justify-between gap-2">
<div className="grid shrink gap-y-1.5 text-neutral-800">
<Heading size="h3" as="h2" className="truncate">
{name}
</Heading>
<Heading size="h5" as="h3" className="truncate">
{ens ?? address}
</Heading>
</div>
<DaoAvatar name={name} src={logoSrc} size="md" responsiveSize={{ md: 'lg' }} />
</div>
<p className="line-clamp-2 text-base leading-normal text-neutral-500 md:text-lg">{description}</p>
<div className="mt-1 flex items-center gap-x-1 text-neutral-400 md:mt-0 md:gap-x-2">
<span className="text-sm capitalize leading-tight md:text-base">{network}</span>
<Icon icon={IconType.BLOCKCHAIN_BLOCKCHAIN} size="sm" responsiveSize={{ md: 'md' }} />
</div>
</DataList.Item>
);
Expand Down
Loading

0 comments on commit 442e870

Please sign in to comment.