Skip to content

Commit

Permalink
Update styles of outlined buttons and more (blockscout#1978)
Browse files Browse the repository at this point in the history
* selected state for Button

* tests

* fix menu filter button hover issue

* update screenshots

* try to fix SearchBar recent keywords test
  • Loading branch information
tom2drum authored Jun 5, 2024
1 parent cf1caf7 commit e0259db
Show file tree
Hide file tree
Showing 123 changed files with 363 additions and 245 deletions.
94 changes: 65 additions & 29 deletions theme/components/Button/Button.pw.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,75 @@
import { Button } from '@chakra-ui/react';
import { Box, Button, Flex } from '@chakra-ui/react';
import React from 'react';

import { test, expect } from 'playwright/lib';

test.use({ viewport: { width: 150, height: 350 } });

[
{ variant: 'solid' },
{ variant: 'solid', colorScheme: 'gray', withDarkMode: true },
{ variant: 'outline', colorScheme: 'gray', withDarkMode: true },
{ variant: 'outline', colorScheme: 'gray-dark', withDarkMode: true },
{ variant: 'outline', colorScheme: 'blue', withDarkMode: true },
{ variant: 'simple', withDarkMode: true },
{ variant: 'ghost', withDarkMode: true },
{ variant: 'subtle' },
{ variant: 'subtle', colorScheme: 'gray', withDarkMode: true },
].forEach(({ variant, colorScheme, withDarkMode }) => {
{ variant: 'solid', states: [ 'default', 'disabled', 'hovered', 'active' ] },
{ variant: 'outline', colorScheme: 'gray', withDarkMode: true, states: [ 'default', 'disabled', 'hovered', 'active', 'selected' ] },
{ variant: 'outline', colorScheme: 'blue', withDarkMode: true, states: [ 'default', 'disabled', 'hovered', 'active', 'selected' ] },
{ variant: 'simple', withDarkMode: true, states: [ 'default', 'hovered' ] },
{ variant: 'ghost', withDarkMode: true, states: [ 'default', 'hovered', 'active' ] },
{ variant: 'subtle', states: [ 'default', 'hovered' ] },
{ variant: 'subtle', colorScheme: 'gray', states: [ 'default', 'hovered' ], withDarkMode: true },
].forEach(({ variant, colorScheme, withDarkMode, states }) => {
test.describe(`variant ${ variant }${ colorScheme ? ` with ${ colorScheme } color scheme` : '' }${ withDarkMode ? ' +@dark-mode' : '' }`, () => {
test('base', async({ render }) => {
const component = await render(<Button variant={ variant } colorScheme={ colorScheme }>Click me</Button>);
await expect(component.locator('button')).toHaveScreenshot();
});

test('disabled', async({ render }) => {
const component = await render(<Button variant={ variant } colorScheme={ colorScheme } isDisabled>Click me</Button>);
await expect(component.locator('button')).toHaveScreenshot();
});

test('hovered', async({ render }) => {
const component = await render(<Button variant={ variant } colorScheme={ colorScheme }>Click me</Button>);
await component.getByText(/click/i).hover();
await expect(component.locator('button')).toHaveScreenshot();
});
test('', async({ render }) => {
const component = await render(
<Flex p={ 2 } flexDir="column" rowGap={ 3 }>
{ states?.map((state) => {
switch (state) {
case 'default': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Default:</Box>
<Button variant={ variant } colorScheme={ colorScheme }>Click me</Button>
</Box>
);
}
case 'disabled': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Disabled:</Box>
<Button variant={ variant } colorScheme={ colorScheme } isDisabled>Click me</Button>
</Box>
);
}
case 'active': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Active:</Box>
<Button variant={ variant } colorScheme={ colorScheme } isActive>Click me</Button>
</Box>
);
}
case 'hovered': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Hovered:</Box>
<Button variant={ variant } colorScheme={ colorScheme }>Hover me</Button>
</Box>
);
}
case 'selected': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Selected:</Box>
<Button variant={ variant } colorScheme={ colorScheme } data-selected="true">Click me</Button>
</Box>
);
}

test('active', async({ render }) => {
const component = await render(<Button variant={ variant } colorScheme={ colorScheme } isActive>Click me</Button>);
await expect(component.locator('button')).toHaveScreenshot();
default: {
return null;
}
}
}) }
</Flex>,
);
await component.getByText('Hover me').hover();
await expect(component).toHaveScreenshot();
});
});
});
85 changes: 35 additions & 50 deletions theme/components/Button/Button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,10 @@ import { runIfFn } from '@chakra-ui/utils';
const variantSolid = defineStyle((props) => {
const { colorScheme: c } = props;

if (c === 'gray') {
const bg = mode(`gray.100`, `whiteAlpha.200`)(props);

return {
bg,
_hover: {
bg: mode(`gray.200`, `whiteAlpha.300`)(props),
_disabled: {
bg,
},
},
_active: { bg: mode(`gray.300`, `whiteAlpha.400`)(props) },
};
}

const bg = `${ c }.600`;
const color = 'white';
const hoverBg = `${ c }.400`;
const activeBg = `${ c }.700`;
const activeBg = hoverBg;

return {
bg,
Expand All @@ -37,6 +22,8 @@ const variantSolid = defineStyle((props) => {
_disabled: {
opacity: 0.2,
},
// According to design there is no "active" or "pressed" state
// It is simply should be the same as the "hover" state
_active: { bg: activeBg },
fontWeight: 600,
};
Expand All @@ -45,65 +32,63 @@ const variantSolid = defineStyle((props) => {
const variantOutline = defineStyle((props) => {
const { colorScheme: c } = props;

const isGrayTheme = c === 'gray' || c === 'gray-dark';
const isGrayTheme = c === 'gray';

const bg = 'transparent';

const color = isGrayTheme ? mode('blackAlpha.800', 'whiteAlpha.800')(props) : mode(`${ c }.600`, `${ c }.300`)(props);
const borderColor = isGrayTheme ? mode('gray.200', 'gray.600')(props) : mode(`${ c }.600`, `${ c }.300`)(props);
const activeBg = isGrayTheme ? mode('blue.50', 'gray.600')(props) : mode(`${ c }.50`, 'gray.600')(props);
const activeColor = (() => {
if (c === 'gray') {
return mode('blue.600', 'gray.50')(props);
}
if (c === 'gray-dark') {
return mode('blue.600', 'gray.50')(props);
}
if (c === 'blue') {
return mode('blue.600', 'gray.50')(props);
}
return 'blue.600';
})();

const selectedBg = isGrayTheme ? mode('blue.50', 'gray.600')(props) : mode(`${ c }.50`, 'gray.600')(props);
const selectedColor = mode('blue.600', 'gray.50')(props);

return {
color,
fontWeight: props.fontWeight || 600,
borderWidth: props.borderWidth || '2px',
borderStyle: 'solid',
borderColor,
bg: 'transparent',
bg,
_hover: {
color: 'link_hovered',
borderColor: 'link_hovered',
bg: 'transparent',
_active: {
bg: props.isActive ? activeBg : 'transparent',
borderColor: props.isActive ? activeBg : 'link_hovered',
color: props.isActive ? activeColor : 'link_hovered',
p: {
color: 'link_hovered',
},
bg,
span: {
color: 'link_hovered',
},
_disabled: {
color,
borderColor,
},
p: {
color: 'link_hovered',
},
},
_disabled: {
opacity: 0.2,
},
// According to design there is no "active" or "pressed" state
// It is simply should be the same as the "hover" state
_active: {
bg: activeBg,
borderColor: activeBg,
color: activeColor,
_disabled: {
color,
borderColor,
color: 'link_hovered',
borderColor: 'link_hovered',
bg,
span: {
color: 'link_hovered',
},
p: {
color: activeColor,
_disabled: {
color: 'link_hovered',
borderColor: 'link_hovered',
},
},
// We have a special state for this button variant that serves as a popover trigger.
// When any items (filters) are selected in the popover, the button should change its background and text color.
// The last CSS selector is for redefining styles for the TabList component.
[`
&[data-selected=true],
&[data-selected=true][aria-selected=true]
`]: {
bg: selectedBg,
color: selectedColor,
borderColor: selectedBg,
},
};
});

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
2 changes: 1 addition & 1 deletion ui/address/AddressAccountHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const AddressAccountHistory = ({ scrollRef, shouldRender = true }: Props) => {
<AccountHistoryFilter
defaultFilter={ filterValue }
onFilterChange={ handleFilterChange }
isActive={ Boolean(filterValue) }
hasActiveFilter={ Boolean(filterValue) }
isLoading={ pagination.isLoading }
/>

Expand Down
53 changes: 17 additions & 36 deletions ui/address/AddressAccountHistoryFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,35 @@
import {
Menu,
MenuButton,
MenuList,
MenuOptionGroup,
MenuItemOption,
useDisclosure,
} from '@chakra-ui/react';
import React from 'react';

import type { NovesHistoryFilterValue } from 'types/api/noves';

import useIsInitialLoading from 'lib/hooks/useIsInitialLoading';
import FilterButton from 'ui/shared/filters/FilterButton';
import PopoverFilterRadio from 'ui/shared/filters/PopoverFilterRadio';

const OPTIONS = [
{ value: 'all', label: 'All' },
{ value: 'received', label: 'Received from' },
{ value: 'sent', label: 'Sent to' },
];

interface Props {
isActive: boolean;
hasActiveFilter: boolean;
defaultFilter: NovesHistoryFilterValue;
onFilterChange: (nextValue: string | Array<string>) => void;
isLoading?: boolean;
}

const AccountHistoryFilter = ({ onFilterChange, defaultFilter, isActive, isLoading }: Props) => {
const { isOpen, onToggle } = useDisclosure();
const AccountHistoryFilter = ({ onFilterChange, defaultFilter, hasActiveFilter, isLoading }: Props) => {
const isInitialLoading = useIsInitialLoading(isLoading);

const onCloseMenu = React.useCallback(() => {
if (isOpen) {
onToggle();
}
}, [ isOpen, onToggle ]);

return (
<Menu isOpen={ isOpen } onClose={ onCloseMenu }>
<MenuButton onClick={ onToggle }>
<FilterButton
isActive={ isOpen || isActive }
isLoading={ isInitialLoading }
onClick={ onToggle }
appliedFiltersNum={ isActive ? 1 : 0 }
as="div"
/>
</MenuButton>
<MenuList zIndex={ 2 }>
<MenuOptionGroup defaultValue={ defaultFilter || 'all' } type="radio" onChange={ onFilterChange }>
<MenuItemOption value="all">All</MenuItemOption>
<MenuItemOption value="received">Received from</MenuItemOption>
<MenuItemOption value="sent">Sent to</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
<PopoverFilterRadio
name="account_history_filter"
options={ OPTIONS }
onChange={ onFilterChange }
hasActiveFilter={ hasActiveFilter }
isLoading={ isInitialLoading }
defaultValue={ defaultFilter || OPTIONS[0].value }
/>
);
};

Expand Down
2 changes: 1 addition & 1 deletion ui/address/AddressInternalTxs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const AddressInternalTxs = ({ scrollRef, shouldRender = true }: Props) => {
<AddressTxsFilter
defaultFilter={ filterValue }
onFilterChange={ handleFilterChange }
isActive={ Boolean(filterValue) }
hasActiveFilter={ Boolean(filterValue) }
isLoading={ pagination.isLoading }
/>
<AddressCsvExportLink
Expand Down
2 changes: 1 addition & 1 deletion ui/address/AddressTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const AddressTokens = ({ shouldRender = true }: Props) => {
}

const nftTypeFilter = (
<PopoverFilter isActive={ tokenTypes && tokenTypes.length > 0 } contentProps={{ w: '200px' }} appliedFiltersNum={ tokenTypes?.length }>
<PopoverFilter contentProps={{ w: '200px' }} appliedFiltersNum={ tokenTypes?.length }>
<TokenTypeFilter<NFTTokenType> nftOnly onChange={ handleTokenTypesChange } defaultValue={ tokenTypes }/>
</PopoverFilter>
);
Expand Down
2 changes: 1 addition & 1 deletion ui/address/AddressTxs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shouldRender =
<AddressTxsFilter
defaultFilter={ filterValue }
onFilterChange={ handleFilterChange }
isActive={ Boolean(filterValue) }
hasActiveFilter={ Boolean(filterValue) }
isLoading={ addressTxsQuery.pagination.isLoading }
/>
);
Expand Down
Loading

0 comments on commit e0259db

Please sign in to comment.