feat(L2): network alert cards (optimism and arbitrum) (#1957)

* design review for arbitrum UI

* add optimism L2 UI

* better gradients, remove v2 links/routes, some minor padding and margin fixes
This commit is contained in:
Jordan Frankfurt 2021-07-06 22:38:47 -04:00 committed by GitHub
parent 8c1e9b394b
commit 2d20fc939d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 645 additions and 341 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 250 KiB

@ -0,0 +1,5 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="250" cy="250" r="250" fill="#FF0420"/>
<path d="M177.133 316.446C162.247 316.446 150.051 312.943 140.544 305.938C131.162 298.808 126.471 288.676 126.471 275.541C126.471 272.789 126.784 269.411 127.409 265.408C129.036 256.402 131.35 245.581 134.352 232.947C142.858 198.547 164.812 181.347 200.213 181.347C209.845 181.347 218.476 182.973 226.107 186.225C233.738 189.352 239.742 194.106 244.12 200.486C248.498 206.74 250.688 214.246 250.688 223.002C250.688 225.629 250.375 228.944 249.749 232.947C247.873 244.08 245.621 254.901 242.994 265.408C238.616 282.546 231.048 295.368 220.29 303.874C209.532 312.255 195.147 316.446 177.133 316.446ZM179.76 289.426C186.766 289.426 192.707 287.362 197.586 283.234C202.59 279.106 206.155 272.789 208.281 264.283C211.158 252.524 213.348 242.266 214.849 233.51C215.349 230.883 215.599 228.194 215.599 225.441C215.599 214.058 209.657 208.366 197.774 208.366C190.768 208.366 184.764 210.43 179.76 214.558C174.882 218.687 171.379 225.004 169.253 233.51C167.001 241.891 164.749 252.149 162.498 264.283C161.997 266.784 161.747 269.411 161.747 272.163C161.747 283.672 167.752 289.426 179.76 289.426Z" fill="white"/>
<path d="M259.303 314.57C257.927 314.57 256.863 314.132 256.113 313.256C255.487 312.255 255.3 311.13 255.55 309.879L281.444 187.914C281.694 186.538 282.382 185.412 283.508 184.536C284.634 183.661 285.822 183.223 287.073 183.223H336.985C350.87 183.223 362.003 186.1 370.384 191.854C378.891 197.609 383.144 205.927 383.144 216.81C383.144 219.937 382.769 223.19 382.018 226.567C378.891 240.953 372.574 251.586 363.067 258.466C353.685 265.346 340.8 268.786 324.413 268.786H299.082L290.451 309.879C290.2 311.255 289.512 312.38 288.387 313.256C287.261 314.132 286.072 314.57 284.822 314.57H259.303ZM325.727 242.892C330.98 242.892 335.546 241.453 339.424 238.576C343.427 235.699 346.054 231.571 347.305 226.192C347.68 224.065 347.868 222.189 347.868 220.563C347.868 216.935 346.805 214.183 344.678 212.307C342.551 210.305 338.924 209.305 333.795 209.305H311.278L304.148 242.892H325.727Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -1,20 +1,27 @@
import { Trans } from '@lingui/macro'
import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
import { YellowCard } from 'components/Card'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useActiveWeb3React } from 'hooks/web3'
import { transparentize } from 'polished'
import React, { useEffect, useRef, useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import { ArrowDownCircle } from 'react-feather'
import { ApplicationModal } from 'state/application/actions'
import { useModalOpen, useToggleModal } from 'state/application/hooks'
import styled, { css } from 'styled-components'
import { ExternalLink } from 'theme'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
import { switchToNetwork } from 'utils/switchToNetwork'
import { NETWORK_LABELS, SupportedChainId } from '../../constants/chains'
import { L2_CHAIN_IDS, L2_INFO, NETWORK_LABELS, SupportedChainId } from '../../constants/chains'
const StopOverflowQuery = `@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) and (max-width: ${
MEDIA_WIDTHS.upToMedium + 400
}px)`
const BaseWrapper = css`
position: relative;
${StopOverflowQuery} {
position: absolute;
top: 80px;
right: 20px;
}
${({ theme }) => theme.mediaWidth.upToMedium`
margin-left: 12px;
`};
@ -26,12 +33,12 @@ const BaseWrapper = css`
flex-shrink: 1;
`};
`
const ArbitrumWrapper = styled.div`
const L2Wrapper = styled.div`
${BaseWrapper}
`
const BaseMenuItem = css`
align-items: center;
background-color: ${({ theme }) => transparentize(0.9, theme.primary1)};
background-color: transparent;
border-radius: 12px;
color: ${({ theme }) => theme.text2};
cursor: pointer;
@ -41,7 +48,6 @@ const BaseMenuItem = css`
font-size: 14px;
font-weight: 400;
justify-content: space-between;
padding: 12px;
:hover {
color: ${({ theme }) => theme.text1};
text-decoration: none;
@ -64,6 +70,7 @@ const DisabledMenuItem = styled.div`
`
const FallbackWrapper = styled(YellowCard)`
${BaseWrapper}
width: auto;
border-radius: 12px;
padding: 8px 12px;
`
@ -74,8 +81,8 @@ const L1Tag = styled.div`
color: #c4d9f8;
opacity: 40%;
`
const L2Tag = styled.div`
background-color: ${({ theme }) => theme.primary1};
const L2Tag = styled.div<{ chainId: SupportedChainId }>`
background-color: ${({ chainId }) => (chainId === SupportedChainId.ARBITRUM_ONE ? '#28A0F0' : '#FF0420')};
border-radius: 6px;
color: white;
font-size: 12px;
@ -87,7 +94,7 @@ const MenuFlyout = styled.span`
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
0px 24px 32px rgba(0, 0, 0, 0.01);
border-radius: 20px;
padding: 8px;
padding: 12px;
display: flex;
flex-direction: column;
font-size: 1rem;
@ -97,16 +104,20 @@ const MenuFlyout = styled.span`
z-index: 100;
width: 237px;
${({ theme }) => theme.mediaWidth.upToMedium`
top: -14.25rem;
top: -10.25rem;
`};
> {
padding: 12px;
}
> :not(:first-child) {
margin-top: 4px;
margin-top: 8px;
}
> :not(:last-child) {
margin-bottom: 4px;
margin-bottom: 8px;
}
${StopOverflowQuery} {
left: unset;
right: 0rem;
}
`
const LinkOutCircle = styled(ArrowDownCircle)`
@ -145,6 +156,7 @@ const NetworkInfo = styled.button`
background-color: ${({ theme }) => theme.bg3};
}
`
export default function NetworkCard() {
const { chainId, library } = useActiveWeb3React()
const node = useRef<HTMLDivElement>(null)
@ -169,29 +181,30 @@ export default function NetworkCard() {
return null
}
if (chainId === SupportedChainId.ARBITRUM_ONE) {
if (L2_CHAIN_IDS.includes(chainId)) {
const info = L2_INFO[chainId]
return (
<ArbitrumWrapper ref={node}>
<L2Wrapper ref={node}>
<NetworkInfo onClick={toggle}>
<Icon src={arbitrumLogoUrl} />
<span>Arbitrum</span>
<L2Tag>L2 Alpha</L2Tag>
<Icon src={info.logoUrl} />
<span>{NETWORK_LABELS[chainId]}</span>
<L2Tag chainId={chainId}>L2 Alpha</L2Tag>
</NetworkInfo>
{open && (
<MenuFlyout>
<MenuItem href="https://bridge.arbitrum.io/">
<MenuItem href={info.bridge}>
<div>
<Trans>Arbitrum Token Bridge</Trans>
<Trans>{NETWORK_LABELS[chainId]} Bridge</Trans>
</div>
<LinkOutCircle />
</MenuItem>
<MenuItem href="https://explorer.arbitrum.io/">
<MenuItem href={info.explorer}>
<div>
<Trans>Arbitrum Explorer</Trans>
<Trans>{NETWORK_LABELS[chainId]} Explorer</Trans>
</div>
<LinkOutCircle />
</MenuItem>
<MenuItem href="https://offchainlabs.com/">
<MenuItem href={info.docs}>
<div>
<Trans>Learn more</Trans>
</div>
@ -211,7 +224,7 @@ export default function NetworkCard() {
)}
</MenuFlyout>
)}
</ArbitrumWrapper>
</L2Wrapper>
)
}

@ -8,9 +8,9 @@ import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen, useToggleModal } from '../../state/application/hooks'
import { Trans } from '@lingui/macro'
import { ExternalLink } from '../../theme'
import { ButtonPrimary } from '../Button'
import { L2_CHAIN_IDS } from 'constants/chains'
export enum FlyoutAlignment {
LEFT = 'LEFT',
@ -86,7 +86,8 @@ const MenuFlyout = styled.span<{ flyoutAlignment?: FlyoutAlignment }>`
left: 0rem;
`};
${({ theme }) => theme.mediaWidth.upToMedium`
top: -17.25rem;
top: unset;
bottom: 3em
`};
`
@ -124,13 +125,14 @@ const InternalMenuItem = styled(Link)`
const CODE_LINK = 'https://github.com/Uniswap/uniswap-interface'
export default function Menu() {
const { account } = useActiveWeb3React()
const { account, chainId } = useActiveWeb3React()
const node = useRef<HTMLDivElement>()
const open = useModalOpen(ApplicationModal.MENU)
const toggle = useToggleModal(ApplicationModal.MENU)
useOnClickOutside(node, open ? toggle : undefined)
const openClaimModal = useToggleModal(ApplicationModal.ADDRESS_CLAIM)
const showUNIClaimOption = Boolean(!!account && !!chainId && !L2_CHAIN_IDS.includes(chainId))
return (
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30451
@ -171,7 +173,7 @@ export default function Menu() {
<Trans>Analytics</Trans>
</div>
</MenuItem>
{account && (
{showUNIClaimOption && (
<UNIbutton onClick={openClaimModal} padding="8px 16px" width="100%" $borderRadius="12px" mt="0.5rem">
<Trans>Claim UNI</Trans>
</UNIbutton>

@ -0,0 +1,123 @@
import { Trans } from '@lingui/macro'
import {
ArbitrumWrapperBackgroundDarkMode,
ArbitrumWrapperBackgroundLightMode,
OptimismWrapperBackgroundDarkMode,
OptimismWrapperBackgroundLightMode,
} from 'components/NetworkAlert/NetworkAlert'
import { L2_CHAIN_IDS, L2_INFO, NETWORK_LABELS, SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { ArrowDownCircle } from 'react-feather'
import { useArbitrumAlphaAlert, useDarkModeManager } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { MEDIA_WIDTHS } from 'theme'
const L2Icon = styled.img`
display: none;
height: 40px;
margin: auto 20px auto 4px;
width: 40px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
display: block;
}
`
const DesktopTextBreak = styled.div`
display: none;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
display: block;
}
`
const Wrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string }>`
${({ chainId, darkMode }) =>
chainId === SupportedChainId.OPTIMISM
? darkMode
? OptimismWrapperBackgroundDarkMode
: OptimismWrapperBackgroundLightMode
: darkMode
? ArbitrumWrapperBackgroundDarkMode
: ArbitrumWrapperBackgroundLightMode};
border-radius: 20px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 12px;
position: relative;
width: 100%;
:before {
background-image: url(${({ logoUrl }) => logoUrl});
background-repeat: no-repeat;
background-size: 300px;
content: '';
height: 300px;
opacity: 0.1;
position: absolute;
transform: rotate(25deg) translate(-90px, -40px);
width: 300px;
z-index: -1;
}
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
flex-direction: row;
padding: 16px 20px;
}
`
const Body = styled.div`
line-height: 143%;
margin: 12px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
margin: 16px 20px 31px;
flex: 1 1 auto;
margin: 0;
}
`
const LinkOutCircle = styled(ArrowDownCircle)`
transform: rotate(230deg);
width: 20px;
height: 20px;
`
const LinkOutToBridge = styled.a`
align-items: center;
background-color: black;
border-radius: 16px;
color: white;
display: flex;
justify-content: space-between;
margin: 0;
max-height: 47px;
padding: 14px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: black;
}
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
margin: auto 0 auto auto;
padding: 14px 17px;
min-width: 226px;
}
`
export function MinimalNetworkAlert() {
const { chainId } = useActiveWeb3React()
const [darkMode] = useDarkModeManager()
const [arbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged) {
return null
}
const info = L2_INFO[chainId]
return (
<Wrapper darkMode={darkMode} chainId={chainId} logoUrl={info.logoUrl}>
<L2Icon src={info.logoUrl} />
<Body>
<Trans>This is an alpha release of Uniswap on the {NETWORK_LABELS[chainId]} network.</Trans>
<DesktopTextBreak /> <Trans>You must bridge L1 assets to the network to swap them.</Trans>
</Body>
<LinkOutToBridge href={info.bridge} target="_blank" rel="noopener noreferrer">
<Trans>Deposit to {NETWORK_LABELS[chainId]}</Trans>
<LinkOutCircle />
</LinkOutToBridge>
</Wrapper>
)
}

@ -0,0 +1,155 @@
import { Trans } from '@lingui/macro'
import { L2_CHAIN_IDS, NETWORK_LABELS, SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { useCallback, useState } from 'react'
import { ArrowDownCircle, X } from 'react-feather'
import { useArbitrumAlphaAlert, useDarkModeManager } from 'state/user/hooks'
import { useETHBalances } from 'state/wallet/hooks'
import styled, { css } from 'styled-components/macro'
import { MEDIA_WIDTHS, TYPE } from 'theme'
import { L2_INFO } from '../../constants/chains'
const L2Icon = styled.img`
width: 40px;
height: 40px;
justify-self: center;
`
const CloseIcon = styled(X)`
cursor: pointer;
position: absolute;
top: 16px;
right: 16px;
`
const ContentWrapper = styled.div`
align-items: center;
display: grid;
grid-gap: 4px;
grid-template-columns: 40px 4fr;
grid-template-rows: auto auto;
margin: 20px 16px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
grid-template-columns: 42px 4fr;
grid-gap: 8px;
}
`
export const ArbitrumWrapperBackgroundDarkMode = css`
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.3) 0%, rgba(33, 114, 229, 0.3) 100%), hsla(0, 0%, 100%, 0.1);
`
export const ArbitrumWrapperBackgroundLightMode = css`
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1);
`
export const OptimismWrapperBackgroundDarkMode = css`
background: radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.2) 0%, rgba(255, 255, 255, 0.1) 100%),
radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.5) 0%, rgba(235, 0, 255, 0.345) 96%);
`
export const OptimismWrapperBackgroundLightMode = css`
background: radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),
radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.5);
`
const RootWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string }>`
${({ chainId, darkMode }) =>
chainId === SupportedChainId.OPTIMISM
? darkMode
? OptimismWrapperBackgroundDarkMode
: OptimismWrapperBackgroundLightMode
: darkMode
? ArbitrumWrapperBackgroundDarkMode
: ArbitrumWrapperBackgroundLightMode};
border-radius: 20px;
display: flex;
flex-direction: column;
max-width: 480px;
min-height: 218px;
overflow: hidden;
position: relative;
width: 100%;
:before {
background-image: url(${({ logoUrl }) => logoUrl});
background-repeat: no-repeat;
background-size: 300px;
content: '';
height: 300px;
opacity: 0.1;
position: absolute;
transform: rotate(25deg) translate(-90px, -40px);
width: 300px;
z-index: -1;
}
`
const Header = styled(TYPE.largeHeader)`
margin: 0;
padding-right: 30px;
`
const Body = styled.p`
grid-column: 1 / 3;
line-height: 143%;
margin: 0;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
grid-column: 2 / 3;
}
`
const LinkOutCircle = styled(ArrowDownCircle)`
transform: rotate(230deg);
width: 20px;
height: 20px;
`
const LinkOutToBridge = styled.a`
align-items: center;
background-color: black;
border-radius: 16px;
color: white;
display: flex;
justify-content: space-between;
margin: 0 18px 18px 18px;
padding: 14px 24px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: black;
}
`
export function NetworkAlert() {
const { account, chainId } = useActiveWeb3React()
const [darkMode] = useDarkModeManager()
const [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
const [locallyDismissed, setLocallyDimissed] = useState(false)
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
const dismiss = useCallback(() => {
if (userEthBalance?.greaterThan(0)) {
setArbitrumAlphaAcknowledged(true)
} else {
setLocallyDimissed(true)
}
}, [setArbitrumAlphaAcknowledged, userEthBalance])
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged || locallyDismissed) {
return null
}
const info = L2_INFO[chainId]
return (
<RootWrapper chainId={chainId} darkMode={darkMode} logoUrl={info.logoUrl}>
<CloseIcon onClick={dismiss} />
<ContentWrapper>
<L2Icon src={info.logoUrl} />
<Header>
<Trans>Uniswap on {NETWORK_LABELS[chainId]}</Trans>
</Header>
<Body>
<Trans>
This is an alpha release of Uniswap on the {NETWORK_LABELS[chainId]} network. You must bridge L1 assets to
the network to swap them.
</Trans>
</Body>
</ContentWrapper>
<LinkOutToBridge href={info.bridge} target="_blank" rel="noopener noreferrer">
<Trans>Deposit to {NETWORK_LABELS[chainId]}</Trans>
<LinkOutCircle />
</LinkOutToBridge>
</RootWrapper>
)
}

@ -1,115 +0,0 @@
import { Trans } from '@lingui/macro'
import arbitrumMaskUrl from 'assets/svg/arbitrum_mask.svg'
import { SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import React, { useCallback, useState } from 'react'
import { ArrowDownCircle, X } from 'react-feather'
import { useArbitrumAlphaAlert } from 'state/user/hooks'
import { useETHBalances } from 'state/wallet/hooks'
import styled from 'styled-components'
const CloseIcon = styled(X)`
cursor: pointer;
position: absolute;
top: 1em;
right: 1em;
`
const Wrapper = styled.div`
border-radius: 20px;
background: radial-gradient(285.11% 8200.45% at 29.05% 48.94%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
radial-gradient(76.02% 75.41% at 1.84% 0%, rgba(150, 190, 220, 0.3) 0%, rgba(33, 114, 229, 0.3) 100%);
display: flex;
flex-direction: column;
max-width: 480px;
min-height: 212px;
overflow: hidden;
position: relative;
width: 100%;
:before {
content: '';
position: absolute;
width: 100%;
height: 100%;
z-index: -1;
background-image: url(${arbitrumMaskUrl});
background-repeat: no-repeat;
transform: rotate(15deg), scale(1);
}
`
const ArbitrumTextStyles = styled.span`
font-style: italic;
font-weight: 900;
color: #f3de1e;
background: linear-gradient(to right, #f3de1e, #ffffff);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
`
const Header = styled.h3`
margin: 0;
padding: 20px 20px 0;
`
const Body = styled.p`
line-height: 143%;
margin: 16px 20px 31px;
`
const LinkOutCircle = styled(ArrowDownCircle)`
transform: rotate(230deg);
width: 20px;
height: 20px;
`
const LinkOutToBridge = styled.a`
align-items: center;
background-color: black;
border-radius: 16px;
color: white;
display: flex;
justify-content: space-between;
margin: 0 18px 18px 18px;
padding: 14px 24px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: black;
}
`
export function SwapNetworkAlert() {
const { account, chainId } = useActiveWeb3React()
const [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
const [locallyDismissed, setLocallyDimissed] = useState(false)
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
const dismiss = useCallback(() => {
if (userEthBalance?.greaterThan(0)) {
setArbitrumAlphaAcknowledged(true)
} else {
setLocallyDimissed(true)
}
}, [setArbitrumAlphaAcknowledged, userEthBalance])
if (chainId !== SupportedChainId.ARBITRUM_ONE || arbitrumAlphaAcknowledged || locallyDismissed) {
return null
}
return (
<Wrapper>
<CloseIcon onClick={dismiss} />
<Header>
<Trans>
Uniswap on <ArbitrumTextStyles>Arbitrum</ArbitrumTextStyles>
</Trans>
</Header>
<Body>
<Trans>
This is an alpha release of Uniswap on the Arbitrum network. You must bridge L1 assets to the network to swap
them.
</Trans>
</Body>
<LinkOutToBridge href="https://bridge.arbitrum.io/" target="_blank" rel="noopener noreferrer">
<Trans>Deposit to Arbitrum</Trans>
<LinkOutCircle />
</LinkOutToBridge>
</Wrapper>
)
}

@ -0,0 +1,60 @@
import { Trans } from '@lingui/macro'
import { L2_CHAIN_IDS } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
const EmptyProposals = styled.div`
border: 1px solid ${({ theme }) => theme.text4};
padding: 16px 12px;
border-radius: 12px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`
const Sub = styled.i`
align-items: center;
display: flex;
justify-content: center;
text-align: center;
`
interface EmptyStateProps {
HeaderContent: () => JSX.Element
SubHeaderContent: () => JSX.Element
}
const EmptyState = ({ HeaderContent, SubHeaderContent }: EmptyStateProps) => (
<EmptyProposals>
<TYPE.body style={{ marginBottom: '8px' }}>
<HeaderContent />
</TYPE.body>
<TYPE.subHeader>
<Sub>
<SubHeaderContent />
</Sub>
</TYPE.subHeader>
</EmptyProposals>
)
export default function ProposalEmptyState() {
const { chainId } = useActiveWeb3React()
if (chainId && L2_CHAIN_IDS.includes(chainId)) {
return (
<EmptyState
HeaderContent={() => <Trans>Please connect to Layer 1 Ethereum</Trans>}
SubHeaderContent={() => (
<Trans>
Uniswap governance is only available on Layer 1. Switch your network to Ethereum Mainnet to view Proposals
and Vote.
</Trans>
)}
/>
)
}
return (
<EmptyState
HeaderContent={() => <Trans>No proposals found.</Trans>}
SubHeaderContent={() => <Trans>Proposals submitted by community members will appear here.</Trans>}
/>
)
}

@ -29,6 +29,8 @@ const NETWORK_URLS: {
[SupportedChainId.KOVAN]: `https://kovan.infura.io/v3/${INFURA_KEY}`,
[SupportedChainId.ARBITRUM_ONE]: `https://arb1.arbitrum.io/rpc`,
[SupportedChainId.ARBITRUM_RINKEBY]: `https://rinkeby.arbitrum.io/rpc`,
[SupportedChainId.OPTIMISM]: `https://mainnet.optimism.io`,
[SupportedChainId.OPTIMISTIC_KOVAN]: `https://kovan.optimism.io`,
}
const SUPPORTED_CHAIN_IDS: SupportedChainId[] = [
@ -39,6 +41,8 @@ const SUPPORTED_CHAIN_IDS: SupportedChainId[] = [
SupportedChainId.ROPSTEN,
SupportedChainId.ARBITRUM_ONE,
SupportedChainId.ARBITRUM_RINKEBY,
SupportedChainId.OPTIMISM,
SupportedChainId.OPTIMISTIC_KOVAN,
]
export const network = new NetworkConnector({

@ -1,3 +1,6 @@
import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
import optimismLogoUrl from 'assets/svg/optimism_logo.svg'
export enum SupportedChainId {
MAINNET = 1,
ROPSTEN = 3,
@ -6,6 +9,25 @@ export enum SupportedChainId {
KOVAN = 42,
ARBITRUM_ONE = 42161,
ARBITRUM_RINKEBY = 421611,
OPTIMISM = 10,
OPTIMISTIC_KOVAN = 69,
}
export const L2_CHAIN_IDS = [SupportedChainId.ARBITRUM_ONE, SupportedChainId.OPTIMISM]
export const L2_INFO: Record<number, { bridge: string; docs: string; explorer: string; logoUrl: string }> = {
[SupportedChainId.OPTIMISM]: {
bridge: 'https://gateway.optimism.io/',
docs: 'https://optimism.io/',
explorer: 'https://optimistic.etherscan.io/',
logoUrl: optimismLogoUrl,
},
[SupportedChainId.ARBITRUM_ONE]: {
bridge: 'https://bridge.arbitrum.io/',
explorer: 'https://explorer.arbitrum.io/',
docs: 'https://offchainlabs.com/',
logoUrl: arbitrumLogoUrl,
},
}
export const NETWORK_LABELS: { [chainId in SupportedChainId | number]: string } = {
@ -16,4 +38,6 @@ export const NETWORK_LABELS: { [chainId in SupportedChainId | number]: string }
[SupportedChainId.KOVAN]: 'Kovan',
[SupportedChainId.ARBITRUM_ONE]: 'Arbitrum',
[SupportedChainId.ARBITRUM_RINKEBY]: 'Arbitrum Testnet',
[SupportedChainId.OPTIMISM]: 'Optimism',
[SupportedChainId.OPTIMISTIC_KOVAN]: 'Optimism Testnet',
}

@ -132,6 +132,20 @@ export const WETH9_EXTENDED: { [chainId: number]: Token } = {
'WETH',
'Wrapped Ether'
),
[SupportedChainId.OPTIMISM]: new Token(
SupportedChainId.OPTIMISM,
'0x4200000000000000000000000000000000000006',
18,
'WETH',
'Wrapped Ether'
),
[SupportedChainId.OPTIMISTIC_KOVAN]: new Token(
SupportedChainId.OPTIMISTIC_KOVAN,
'0x4200000000000000000000000000000000000006',
18,
'WETH',
'Wrapped Ether'
),
}
export class ExtendedEther extends Ether {

@ -28,7 +28,7 @@ import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallbac
import useTransactionDeadline from '../../hooks/useTransactionDeadline'
import { useWalletModalToggle } from '../../state/application/hooks'
import { Field, Bound } from '../../state/mint/v3/actions'
import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
import { useTransactionAdder } from '../../state/transactions/hooks'
import { useIsExpertMode, useUserSlippageToleranceWithDefault } from '../../state/user/hooks'
import { TYPE, ExternalLink } from '../../theme'
@ -388,6 +388,7 @@ export default function AddLiquidity({
return (
<>
<ScrollablePage>
<NetworkAlert />
<TransactionConfirmationModal
isOpen={showConfirm}
onDismiss={handleDismissConfirmation}

@ -20,7 +20,7 @@ export const Wrapper = styled.div`
export const ScrollablePage = styled.div`
position: relative;
display: flex;
flex-direction: row;
flex-direction: column;
`
export const DynamicSection = styled(AutoColumn)<{ disabled?: boolean }>`

@ -29,6 +29,8 @@ import { PositionPage } from './Pool/PositionPage'
import AddLiquidity from './AddLiquidity'
import ApeModeQueryParamReader from 'hooks/useApeModeQueryParamReader'
import CreateProposal from './CreateProposal'
import { useActiveWeb3React } from 'hooks/web3'
import { L2_CHAIN_IDS } from 'constants/chains'
const AppWrapper = styled.div`
display: flex;
@ -69,6 +71,46 @@ function TopLevelModals() {
return <AddressClaimModal isOpen={open} onDismiss={toggle} />
}
const Routes = () => {
const { chainId } = useActiveWeb3React()
const HIDE_ON_L2 = Boolean(chainId && L2_CHAIN_IDS.includes(chainId))
return (
<Switch>
<Route exact strict path="/vote" component={Vote} />
<Route exact strict path="/vote/:governorIndex/:id" component={VotePage} />
<Route exact strict path="/claim" component={OpenClaimAddressModalAndRedirectToSwap} />
{HIDE_ON_L2 && <Route exact strict path="/uni" component={Earn} />}
{HIDE_ON_L2 && <Route exact strict path="/uni/:currencyIdA/:currencyIdB" component={Manage} />}
<Route exact strict path="/send" component={RedirectPathToSwapOnly} />
<Route exact strict path="/swap/:outputCurrency" component={RedirectToSwap} />
<Route exact strict path="/swap" component={Swap} />
{HIDE_ON_L2 && <Route exact strict path="/pool/v2/find" component={PoolFinder} />}
{HIDE_ON_L2 && <Route exact strict path="/pool/v2" component={PoolV2} />}
<Route exact strict path="/pool" component={Pool} />
<Route exact strict path="/pool/:tokenId" component={PositionPage} />
{HIDE_ON_L2 && (
<Route exact strict path="/add/v2/:currencyIdA?/:currencyIdB?" component={RedirectDuplicateTokenIdsV2} />
)}
<Route exact strict path="/add/:currencyIdA?/:currencyIdB?/:feeAmount?" component={RedirectDuplicateTokenIds} />
<Route exact strict path="/increase/:currencyIdA?/:currencyIdB?/:feeAmount?/:tokenId?" component={AddLiquidity} />
{HIDE_ON_L2 && <Route exact strict path="/remove/v2/:currencyIdA/:currencyIdB" component={RemoveLiquidity} />}
<Route exact strict path="/remove/:tokenId" component={RemoveLiquidityV3} />
{HIDE_ON_L2 && <Route exact strict path="/migrate/v2" component={MigrateV2} />}
{HIDE_ON_L2 && <Route exact strict path="/migrate/v2/:address" component={MigrateV2Pair} />}
<Route exact strict path="/create-proposal" component={CreateProposal} />
<Route component={RedirectPathToSwapOnly} />
</Switch>
)
}
export default function App() {
return (
<ErrorBoundary>
@ -84,46 +126,7 @@ export default function App() {
<Polling />
<TopLevelModals />
<Web3ReactManager>
<Switch>
<Route exact strict path="/vote" component={Vote} />
<Route exact strict path="/vote/:governorIndex/:id" component={VotePage} />
<Route exact strict path="/claim" component={OpenClaimAddressModalAndRedirectToSwap} />
<Route exact strict path="/uni" component={Earn} />
<Route exact strict path="/uni/:currencyIdA/:currencyIdB" component={Manage} />
<Route exact strict path="/send" component={RedirectPathToSwapOnly} />
<Route exact strict path="/swap/:outputCurrency" component={RedirectToSwap} />
<Route exact strict path="/swap" component={Swap} />
<Route exact strict path="/pool/v2/find" component={PoolFinder} />
<Route exact strict path="/pool/v2" component={PoolV2} />
<Route exact strict path="/pool" component={Pool} />
<Route exact strict path="/pool/:tokenId" component={PositionPage} />
<Route exact strict path="/add/v2/:currencyIdA?/:currencyIdB?" component={RedirectDuplicateTokenIdsV2} />
<Route
exact
strict
path="/add/:currencyIdA?/:currencyIdB?/:feeAmount?"
component={RedirectDuplicateTokenIds}
/>
<Route
exact
strict
path="/increase/:currencyIdA?/:currencyIdB?/:feeAmount?/:tokenId?"
component={AddLiquidity}
/>
<Route exact strict path="/remove/v2/:currencyIdA/:currencyIdB" component={RemoveLiquidity} />
<Route exact strict path="/remove/:tokenId" component={RemoveLiquidityV3} />
<Route exact strict path="/migrate/v2" component={MigrateV2} />
<Route exact strict path="/migrate/v2/:address" component={MigrateV2Pair} />
<Route exact strict path="/create-proposal" component={CreateProposal} />
<Route component={RedirectPathToSwapOnly} />
</Switch>
<Routes />
</Web3ReactManager>
<Marginer />
</BodyWrapper>

@ -1,16 +1,18 @@
import { Trans } from '@lingui/macro'
import { AutoColumn } from 'components/Column'
import { MinimalNetworkAlert } from 'components/NetworkAlert/MinimalNetworkAlert'
import { RowBetween } from 'components/Row'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { Trans } from '@lingui/macro'
import { ExternalLink } from '../../theme'
import { AutoColumn } from 'components/Column'
import Squiggle from '../../assets/images/squiggle.png'
import Texture from '../../assets/images/sandtexture.webp'
import { RowBetween } from 'components/Row'
import Squiggle from '../../assets/images/squiggle.png'
import { ExternalLink } from '../../theme'
const CTASection = styled.section`
display: grid;
grid-template-columns: 2fr 1fr;
gap: 8px;
margin-top: 8px;
${({ theme }) => theme.mediaWidth.upToSmall`
grid-template-columns: auto;
@ -118,32 +120,35 @@ const StyledImage = styled.img`
export default function CTACards() {
return (
<CTASection>
<CTA1 href={'https://docs.uniswap.org/concepts/introduction/liquidity-user-guide'}>
<ResponsiveColumn>
<HeaderText>
<Trans>Uniswap V3 is here!</Trans>
</HeaderText>
<TYPE.body fontWeight={300} style={{ alignItems: 'center', display: 'flex', maxWidth: '80%' }}>
<Trans>Check out our v3 LP walkthrough and migration guides.</Trans>
</TYPE.body>
<RowBetween align="flex-end">
<HeaderText></HeaderText>
<StyledImage src={Squiggle} />
</RowBetween>
</ResponsiveColumn>
</CTA1>
<CTA2 href={'https://info.uniswap.org/#/pools'}>
<ResponsiveColumn>
<HeaderText style={{ alignSelf: 'flex-start' }}>
<Trans>Top pools</Trans>
</HeaderText>
<TYPE.body fontWeight={300} style={{ alignSelf: 'flex-start' }}>
<Trans>Explore popular pools on Uniswap Analytics.</Trans>
</TYPE.body>
<HeaderText style={{ alignSelf: 'flex-end' }}></HeaderText>
</ResponsiveColumn>
</CTA2>
</CTASection>
<div>
<MinimalNetworkAlert />
<CTASection>
<CTA1 href={'https://docs.uniswap.org/concepts/introduction/liquidity-user-guide'}>
<ResponsiveColumn>
<HeaderText>
<Trans>Uniswap V3 is here!</Trans>
</HeaderText>
<TYPE.body fontWeight={300} style={{ alignItems: 'center', display: 'flex', maxWidth: '80%' }}>
<Trans>Check out our v3 LP walkthrough and migration guides.</Trans>
</TYPE.body>
<RowBetween align="flex-end">
<HeaderText></HeaderText>
<StyledImage src={Squiggle} />
</RowBetween>
</ResponsiveColumn>
</CTA1>
<CTA2 href={'https://info.uniswap.org/#/pools'}>
<ResponsiveColumn>
<HeaderText style={{ alignSelf: 'flex-start' }}>
<Trans>Top pools</Trans>
</HeaderText>
<TYPE.body fontWeight={300} style={{ alignSelf: 'flex-start' }}>
<Trans>Explore popular pools on Uniswap Analytics.</Trans>
</TYPE.body>
<HeaderText style={{ alignSelf: 'flex-end' }}></HeaderText>
</ResponsiveColumn>
</CTA2>
</CTASection>
</div>
)
}

@ -473,6 +473,15 @@ export function PositionPage({
)
}
const showCollectAsWeth = Boolean(
ownsNFT &&
(feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) &&
currency0 &&
currency1 &&
(currency0.isNative || currency1.isNative) &&
!collectMigrationHash
)
return loading || poolState === PoolState.LOADING || !feeAmount ? (
<LoadingRows>
<div />
@ -721,12 +730,7 @@ export function PositionPage({
</RowBetween>
</AutoColumn>
</LightCard>
{ownsNFT &&
(feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) &&
currency0 &&
currency1 &&
(currency0.isNative || currency1.isNative) &&
!collectMigrationHash ? (
{showCollectAsWeth && (
<AutoColumn gap="md">
<RowBetween>
<TYPE.main>
@ -739,7 +743,7 @@ export function PositionPage({
/>
</RowBetween>
</AutoColumn>
) : null}
)}
</AutoColumn>
</DarkCard>
</AutoColumn>

@ -1,25 +1,25 @@
import { useContext } from 'react'
import { Trans } from '@lingui/macro'
import { ButtonGray, ButtonOutlined, ButtonPrimary } from 'components/Button'
import { AutoColumn } from 'components/Column'
import { FlyoutAlignment, NewMenu } from 'components/Menu'
import { SwapPoolTabs } from 'components/NavigationTabs'
import PositionList from 'components/PositionList'
import { RowBetween, RowFixed } from 'components/Row'
import { useActiveWeb3React } from 'hooks/web3'
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
import Toggle from 'components/Toggle'
import { L2_CHAIN_IDS } from 'constants/chains'
import { useV3Positions } from 'hooks/useV3Positions'
import { BookOpen, ChevronDown, Download, Inbox, PlusCircle, ChevronsRight, Layers } from 'react-feather'
import { Trans } from '@lingui/macro'
import { useActiveWeb3React } from 'hooks/web3'
import { useContext } from 'react'
import { BookOpen, ChevronDown, ChevronsRight, Download, Inbox, Layers, PlusCircle } from 'react-feather'
import { Link } from 'react-router-dom'
import { useWalletModalToggle } from 'state/application/hooks'
import { useUserHideClosedPositions } from 'state/user/hooks'
import styled, { ThemeContext } from 'styled-components'
import { HideSmall, TYPE } from 'theme'
import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
import { LoadingRows } from './styleds'
import Toggle from 'components/Toggle'
import { useUserHideClosedPositions } from 'state/user/hooks'
import CTACards from './CTACards'
import { PositionDetails } from 'types/position'
import CTACards from './CTACards'
import { LoadingRows } from './styleds'
const PageWrapper = styled(AutoColumn)`
max-width: 870px;
@ -107,7 +107,7 @@ const ShowInactiveToggle = styled.div`
`
export default function Pool() {
const { account } = useActiveWeb3React()
const { account, chainId } = useActiveWeb3React()
const toggleWalletModal = useWalletModalToggle()
const theme = useContext(ThemeContext)
@ -124,6 +124,8 @@ export default function Pool() {
) ?? [[], []]
const filteredPositions = [...openPositions, ...(userHideClosedPositions ? [] : closedPositions)]
const showConnectAWallet = Boolean(!account)
const showV2Features = !!chainId && !L2_CHAIN_IDS.includes(chainId)
const menuItems = [
{
@ -146,16 +148,6 @@ export default function Pool() {
link: '/migrate/v2',
external: false,
},
{
content: (
<MenuItem>
<Layers size={16} style={{ marginRight: '12px' }} />
<Trans>V2 liquidity</Trans>
</MenuItem>
),
link: '/pool/v2',
external: false,
},
{
content: (
<MenuItem>
@ -168,6 +160,19 @@ export default function Pool() {
},
]
if (showV2Features) {
menuItems.splice(2, 0, {
content: (
<MenuItem>
<Layers size={16} style={{ marginRight: '12px' }} />
<Trans>V2 liquidity</Trans>
</MenuItem>
),
link: '/pool/v2',
external: false,
})
}
return (
<>
<PageWrapper>
@ -241,11 +246,12 @@ export default function Pool() {
<Trans>Your V3 liquidity positions will appear here.</Trans>
</div>
</TYPE.mediumHeader>
{!account ? (
{showConnectAWallet && (
<ButtonPrimary style={{ marginTop: '2em', padding: '8px 16px' }} onClick={toggleWalletModal}>
<Trans>Connect a wallet</Trans>
</ButtonPrimary>
) : (
)}
{showV2Features && (
<ButtonGray
as={Link}
to="/migrate/v2"
@ -259,27 +265,11 @@ export default function Pool() {
</NoLiquidity>
)}
</MainContentWrapper>
<RowFixed justify="center" style={{ width: '100%' }}>
<ButtonOutlined
as={Link}
to="/pool/v2"
id="import-pool-link"
style={{
padding: '8px 16px',
margin: '0 4px',
borderRadius: '12px',
width: 'fit-content',
fontSize: '14px',
}}
>
<Layers size={14} style={{ marginRight: '8px' }} />
<Trans>View V2 Liquidity</Trans>
</ButtonOutlined>
{positions && positions.length > 0 && (
{showV2Features && (
<RowFixed justify="center" style={{ width: '100%' }}>
<ButtonOutlined
as={Link}
to="/migrate/v2"
to="/pool/v2"
id="import-pool-link"
style={{
padding: '8px 16px',
@ -289,12 +279,30 @@ export default function Pool() {
fontSize: '14px',
}}
>
<ChevronsRight size={16} style={{ marginRight: '8px' }} />
<Layers size={14} style={{ marginRight: '8px' }} />
<Trans>Migrate Liquidity</Trans>
<Trans>View V2 Liquidity</Trans>
</ButtonOutlined>
)}
</RowFixed>
{positions && positions.length > 0 && (
<ButtonOutlined
as={Link}
to="/migrate/v2"
id="import-pool-link"
style={{
padding: '8px 16px',
margin: '0 4px',
borderRadius: '12px',
width: 'fit-content',
fontSize: '14px',
}}
>
<ChevronsRight size={16} style={{ marginRight: '8px' }} />
<Trans>Migrate Liquidity</Trans>
</ButtonOutlined>
)}
</RowFixed>
)}
</AutoColumn>
</AutoColumn>
</PageWrapper>

@ -2,8 +2,8 @@ import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
import { AdvancedSwapDetails } from 'components/swap/AdvancedSwapDetails'
import { SwapNetworkAlert } from 'components/swap/SwapNetworkAlert'
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
import { MouseoverTooltip, MouseoverTooltipContent } from 'components/Tooltip'
import JSBI from 'jsbi'
@ -358,7 +358,7 @@ export default function Swap({ history }: RouteComponentProps) {
onConfirm={handleConfirmTokenWarning}
onDismiss={handleDismissTokenWarning}
/>
<SwapNetworkAlert />
<NetworkAlert />
<AppBody>
<SwapHeader allowedSlippage={allowedSlippage} />
<Wrapper id="swap-page">

@ -1,29 +1,30 @@
import { AutoColumn } from '../../components/Column'
import styled from 'styled-components/macro'
import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
import { UNI } from '../../constants/tokens'
import { ExternalLink, TYPE } from '../../theme'
import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
import { Link } from 'react-router-dom'
import { getExplorerLink, ExplorerDataType } from '../../utils/getExplorerLink'
import { ProposalStatus } from './styled'
import { ButtonPrimary } from '../../components/Button'
import { Button } from 'rebass/styled-components'
import { darken } from 'polished'
import { CardBGImage, CardNoise, CardSection, DataCard } from '../../components/earn/styled'
import { ProposalData, useAllProposalData, useUserDelegatee, useUserVotes } from '../../state/governance/hooks'
import DelegateModal from '../../components/vote/DelegateModal'
import { useTokenBalance } from '../../state/wallet/hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { ZERO_ADDRESS } from '../../constants/misc'
import { Token, CurrencyAmount } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
import { shortenAddress } from '../../utils'
import Loader from '../../components/Loader'
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
import { useModalOpen, useToggleDelegateModal } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/actions'
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import ProposalEmptyState from 'components/vote/ProposalEmptyState'
import JSBI from 'jsbi'
import { darken } from 'polished'
import { Link } from 'react-router-dom'
import { Button } from 'rebass/styled-components'
import styled from 'styled-components/macro'
import { ButtonPrimary } from 'components/Button'
import { AutoColumn } from 'components/Column'
import { CardBGImage, CardNoise, CardSection, DataCard } from 'components/earn/styled'
import FormattedCurrencyAmount from 'components/FormattedCurrencyAmount'
import Loader from 'components/Loader'
import { AutoRow, RowBetween, RowFixed } from 'components/Row'
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
import DelegateModal from 'components/vote/DelegateModal'
import { ZERO_ADDRESS } from '../../constants/misc'
import { UNI } from '../../constants/tokens'
import { useActiveWeb3React } from 'hooks/web3'
import { ApplicationModal } from 'state/application/actions'
import { useModalOpen, useToggleDelegateModal } from 'state/application/hooks'
import { ProposalData, useAllProposalData, useUserDelegatee, useUserVotes } from 'state/governance/hooks'
import { useTokenBalance } from 'state/wallet/hooks'
import { ExternalLink, TYPE } from 'theme'
import { shortenAddress } from 'utils'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
import { ProposalStatus } from './styled'
const PageWrapper = styled(AutoColumn)``
@ -95,16 +96,6 @@ const StyledExternalLink = styled(ExternalLink)`
color: ${({ theme }) => theme.text1};
`
const EmptyProposals = styled.div`
border: 1px solid ${({ theme }) => theme.text4};
padding: 16px 12px;
border-radius: 12px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`
export default function Vote() {
const { account, chainId } = useActiveWeb3React()
@ -239,18 +230,7 @@ export default function Vote() {
)}
</RowBetween>
)}
{allProposals?.length === 0 && (
<EmptyProposals>
<TYPE.body style={{ marginBottom: '8px' }}>
<Trans>No proposals found.</Trans>
</TYPE.body>
<TYPE.subHeader>
<i>
<Trans>Proposals submitted by community members will appear here.</Trans>
</i>
</TYPE.subHeader>
</EmptyProposals>
)}
{allProposals?.length === 0 && <ProposalEmptyState />}
{allProposals
?.slice(0)
?.reverse()

@ -1,22 +1,54 @@
import { useActiveWeb3React } from 'hooks/web3'
import { useEffect } from 'react'
import { useDarkModeManager } from 'state/user/hooks'
import { SupportedChainId } from '../constants/chains'
import { useActiveWeb3React } from '../hooks/web3'
const initialStyles = {
width: '200vw',
height: '200vh',
transform: 'translate(-50vw, -100vh)',
}
const backgroundResetStyles = {
width: '100vw',
height: '100vh',
transform: 'unset',
}
type TargetBackgroundStyles = typeof initialStyles | typeof backgroundResetStyles
const backgroundRadialGradientElement = document.getElementById('background-radial-gradient')
const setBackground = (newValues: TargetBackgroundStyles) =>
Object.entries(newValues).forEach(([key, value]) => {
if (backgroundRadialGradientElement) {
backgroundRadialGradientElement.style[key as keyof typeof backgroundResetStyles] = value
}
})
export default function RadialGradientByChainUpdater(): null {
const { chainId } = useActiveWeb3React()
const [darkMode] = useDarkModeManager()
// manage background color
useEffect(() => {
if (!backgroundRadialGradientElement) {
return
}
if (chainId === SupportedChainId.ARBITRUM_ONE) {
backgroundRadialGradientElement.style.background =
'radial-gradient(96.19% 96.19% at 50% -5.43%, hsla(204, 87%, 55%, 0.2) 0%, hsla(227, 0%, 0%, 0) 100%)'
} else {
backgroundRadialGradientElement.style.background = ''
switch (chainId) {
case SupportedChainId.ARBITRUM_ONE:
setBackground(backgroundResetStyles)
const arbitrumLightGradient = 'radial-gradient(150% 100% at 50% 0%, #CDE8FB 0%, #FCF3F9 50%, #FFFFFF 100%)'
const arbitrumDarkGradient = 'radial-gradient(150% 100% at 50% 0%, #0A294B 0%, #221E30 50%, #1F2128 100%)'
backgroundRadialGradientElement.style.background = darkMode ? arbitrumDarkGradient : arbitrumLightGradient
break
case SupportedChainId.OPTIMISM:
setBackground(backgroundResetStyles)
const optimismLightGradient = 'radial-gradient(150% 100% at 50% 0%, #FFFBF2 2%, #FFF4F9 53%, #FFFFFF 100%)'
const optimismDarkGradient = 'radial-gradient(150% 100% at 50% 0%, #3E2E38 2%, #2C1F2D 53%, #1F2128 100%)'
backgroundRadialGradientElement.style.background = darkMode ? optimismDarkGradient : optimismLightGradient
break
default:
setBackground(initialStyles)
backgroundRadialGradientElement.style.background = ''
}
}, [chainId])
}, [darkMode, chainId])
return null
}