Skip to content

Commit

Permalink
refactor: remake the ChainSwitcher to own code
Browse files Browse the repository at this point in the history
  • Loading branch information
solidovic committed Oct 28, 2024
1 parent eddc38b commit 83f8197
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { FC, ReactNode } from 'react';

import { Option } from '@lidofinance/lido-ui';
import { FC, ReactNode, useState, useEffect, useRef } from 'react';

import { ReactComponent as OptimismLogo } from 'assets/icons/chain-toggler/optimism.svg';
import { ReactComponent as EthereumMainnetLogo } from 'assets/icons/chain-toggler/mainnet.svg';
Expand All @@ -9,7 +7,13 @@ import { DAPP_CHAIN_TYPE } from 'modules/web3';
import { useDappStatus } from 'modules/web3';

import { SelectIconTooltip } from './components/select-icon-tooltip/select-icon-tooltip';
import { SelectIconStyled, SelectIconWrapper } from './styles';
import {
SelectStyled,
SelectIconStyle,
SelectArrowStyle,
PopupMenuStyled,
PopupMenuOptionStyled,
} from './styles';

const iconsMap: Record<DAPP_CHAIN_TYPE, ReactNode> = {
[DAPP_CHAIN_TYPE.Ethereum]: <EthereumMainnetLogo />,
Expand All @@ -20,35 +24,67 @@ export const ChainSwitcher: FC = () => {
const { isDappActive, chainType, supportedChainTypes, setChainType } =
useDappStatus();

const [opened, setOpened] = useState(false);
const selectRef = useRef<HTMLDivElement>(null);

const handlerOnClick = () => {
setOpened((prev) => !prev);
};

const handleChainTypeSelect = (chainType: DAPP_CHAIN_TYPE) => {
setChainType(chainType);
setOpened(false);
};

const handleClickOutside = (event: MouseEvent) => {
if (
selectRef.current &&
!selectRef.current.contains(event.target as Node)
) {
setOpened(false);
}
};

useEffect(() => {
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, []);

const isChainTypeUnlocked = supportedChainTypes.length > 1;

return (
<SelectIconWrapper>
<SelectIconStyled
disabled={!isChainTypeUnlocked}
icon={iconsMap[chainType]}
value={chainType}
variant="small"
onChange={setChainType as any}
<>
<SelectStyled
ref={selectRef}
$disabled={!isChainTypeUnlocked}
onClick={handlerOnClick}
>
<Option
leftDecorator={iconsMap[DAPP_CHAIN_TYPE.Ethereum]}
value={DAPP_CHAIN_TYPE.Ethereum}
<SelectIconStyle>{iconsMap[chainType]}</SelectIconStyle>
{isChainTypeUnlocked && <SelectArrowStyle $opened={opened} />}
</SelectStyled>

<PopupMenuStyled $opened={opened}>
<PopupMenuOptionStyled
onClick={() => handleChainTypeSelect(DAPP_CHAIN_TYPE.Ethereum)}
$active={DAPP_CHAIN_TYPE.Ethereum === chainType}
>
Ethereum
</Option>
<Option
leftDecorator={iconsMap[DAPP_CHAIN_TYPE.Optimism]}
value={DAPP_CHAIN_TYPE.Optimism}
{iconsMap[DAPP_CHAIN_TYPE.Ethereum]} Ethereum
</PopupMenuOptionStyled>
<PopupMenuOptionStyled
onClick={() => handleChainTypeSelect(DAPP_CHAIN_TYPE.Optimism)}
$active={DAPP_CHAIN_TYPE.Optimism === chainType}
>
Optimism
</Option>
</SelectIconStyled>
{iconsMap[DAPP_CHAIN_TYPE.Optimism]} Optimism
</PopupMenuOptionStyled>
</PopupMenuStyled>

{isChainTypeUnlocked && !isDappActive && (
<SelectIconTooltip showArrow={true}>
This network doesn’t match your wallet’s network
</SelectIconTooltip>
)}
</SelectIconWrapper>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const SelectIconTooltipWrapper = styled.div`
left: 0;
top: calc(100% + 16px);
width: 244px;
z-index: 100;
@media ${devicesHeaderMedia.mobile} {
position: fixed;
Expand All @@ -19,7 +20,6 @@ export const SelectIconTooltipWrapper = styled.div`
right: 20px;
top: unset;
width: auto;
z-index: 5000;
}
`;

Expand Down
181 changes: 158 additions & 23 deletions shared/components/layout/header/components/chain-switcher/styles.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,171 @@
import styled, { css } from 'styled-components';
import { SelectIcon } from '@lidofinance/lido-ui';

export const SelectIconWrapper = styled.div`
type SelectProps = {
$disabled: boolean;
};

export const SelectStyled = styled.div<SelectProps>`
display: inline-flex;
flex-grow: 1;
align-items: center;
justify-content: space-between;
position: relative;
`;
overflow: ${({ $disabled }) => ($disabled ? 'hidden' : 'visible')};
box-sizing: border-box;
export const SelectIconStyled = styled(SelectIcon)`
overflow: ${({ disabled }) => (disabled ? 'hidden' : 'visible')};
width: ${({ disabled }) => (disabled ? '44px' : '68px')};
width: ${({ $disabled }) => ($disabled ? '44px' : '68px')};
height: 44px;
margin-right: 12px;
padding: 9px 8px;
font-weight: 400;
font-size: 14px;
color: var(--lido-color-text);
cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')};
border-radius: 10px;
transition: border-color 100ms;
cursor: ${({ $disabled }) => ($disabled ? 'default' : 'pointer')};
background: var(--lido-color-controlBg);
&:not(:disabled):hover {
& > span {
${({ theme, disabled }) =>
theme.name === 'dark'
? css`
background: ${!disabled && '#34343D'};
`
: css`
background: ${!disabled && '#000A3D08'};
`}
}
${({ theme, $disabled }) =>
theme.name === 'dark'
? css`
background: ${!$disabled && '#34343D'};
`
: css`
background: ${!$disabled && '#000A3D08'};
`}
}
`;

export const SelectIconStyle = styled.span`
display: flex;
align-items: center;
justify-content: center;
align-self: stretch;
justify-self: stretch;
`;

& > span {
border: 0;
padding-left: 8px;
padding-right: 14px;
type SelectArrowProps = {
$opened: boolean;
};

export const SelectArrowStyle = styled.div<SelectArrowProps>`
border: 3px solid currentColor;
border-bottom-width: 0;
border-left-color: transparent;
border-right-color: transparent;
color: var(--lido-color-text);
margin-right: 6px;
transform: rotate(${({ $opened }) => ($opened ? 180 : 0)}deg);
transition: transform ${({ theme }) => theme.duration.norm} ease;
`;

type PopupMenuProps = {
$opened: boolean;
};

const visibleCSS = css`
opacity: 1;
&[data-placement] {
transform: translate(0, 0);
}
`;

border-radius: 10px;
margin-right: 12px;
const hiddenCSS = css`
opacity: 0;
&[data-placement^='top'] {
transform: translateY(6px);
}
&[data-placement^='right'] {
transform: translateX(-6px);
}
&[data-placement^='bottom'] {
transform: translateY(-6px);
}
&[data-placement^='left'] {
transform: translateX(6px);
}
`;

export const PopupMenuStyled = styled.div<PopupMenuProps>`
min-width: 146px;
z-index: 200;
position: absolute;
top: 48px;
overflow: auto;
overflow-x: hidden;
box-sizing: border-box;
margin: 0;
padding: 0;
background: var(--lido-color-foreground);
color: var(--lido-color-text);
font-size: ${({ theme }) => theme.fontSizesMap.xs}px;
line-height: 1.5em;
font-weight: 400;
border-radius: ${({ theme }) => theme.borderRadiusesMap.lg}px;
box-shadow: ${({ theme }) => theme.boxShadows.xs}
var(--lido-color-shadowLight);
transition: opacity 150ms ease;
transition-property: opacity, transform;
${({ $opened }) => ($opened ? visibleCSS : hiddenCSS)};
`;

type PopupMenuOptionProps = {
$active: boolean;
};

export const PopupMenuOptionStyled = styled.div<PopupMenuOptionProps>`
display: flex;
align-items: center;
width: 100%;
height: 44px;
padding: 0 15px;
margin: 0;
box-sizing: border-box;
text-align: left;
color: var(--lido-color-text);
transition: opacity 100ms;
cursor: pointer;
background: var(--lido-color-controlBg);
${({ theme, $active }) =>
theme.name === 'dark'
? css`
background: ${$active && '#34343D'};
`
: css`
background: ${$active && '#000A3D08'};
`}
&:not(:disabled):hover {
${({ theme }) =>
theme.name === 'dark'
? css`
background: #34343d;
`
: css`
background: #000a3d08;
`}
`;

0 comments on commit 83f8197

Please sign in to comment.