Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1944fe4029 | ||
|
|
9921736102 | ||
|
|
11aa641dbc | ||
|
|
2f3290592b | ||
|
|
7b3fe73474 | ||
|
|
4237354bb7 | ||
|
|
f7354c9842 | ||
|
|
1636786af8 | ||
|
|
de0a716f41 | ||
|
|
9f108c406b | ||
|
|
5346d13674 | ||
|
|
d054079eeb | ||
|
|
fe6324f84d | ||
|
|
4a70eb5956 | ||
|
|
1a7b86d155 | ||
|
|
f66f8c4d59 | ||
|
|
1a9c3c3632 | ||
|
|
91f4892b0c | ||
|
|
d6d0a98afe | ||
|
|
8efc5af2bc | ||
|
|
104b62f4d8 | ||
|
|
8e9dbe31fa | ||
|
|
cf0afa01c8 | ||
|
|
c5b67ac60b | ||
|
|
110c6fc08f | ||
|
|
f349ecdd3c | ||
|
|
57fb481da9 | ||
|
|
5871e0afe1 | ||
|
|
281879ea98 | ||
|
|
b623380dd0 | ||
|
|
7645094df6 | ||
|
|
733b1885ff | ||
|
|
7adbb1e0af | ||
|
|
6d5967c981 | ||
|
|
b15f2a2bb6 | ||
|
|
3cc0a41e50 | ||
|
|
4abdca9fdd | ||
|
|
99ef9366d6 | ||
|
|
235ee5dff9 | ||
|
|
20f25803d4 | ||
|
|
09380698fa | ||
|
|
1d96961f25 | ||
|
|
b38241c675 |
1
.env
@@ -1,2 +1,3 @@
|
||||
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
|
||||
REACT_APP_FORTMATIC_KEY="pk_live_357F77728B8EB880"
|
||||
REACT_APP_AMPLITUDE_TEST_KEY="add-the-real-test-key-if-you-need-to-test-amplitude-events"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
REACT_APP_AMPLITUDE_KEY="1c694b28cd089acc2c386d518f93a775"
|
||||
REACT_APP_AMPLITUDE_KEY="b8f7dabddb1c3b03b394619767972160"
|
||||
REACT_APP_AMPLITUDE_TEST_KEY="1c694b28cd089acc2c386d518f93a775"
|
||||
REACT_APP_INFURA_KEY="099fc58e0de9451d80b18d7c74caa7c1"
|
||||
REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID="G-KDP9B6W4H8"
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"src/abis/types",
|
||||
"src/locales/**/*.js",
|
||||
"src/locales/**/en-US.po",
|
||||
"src/state/data/generated.ts",
|
||||
"node_modules",
|
||||
"coverage",
|
||||
"build",
|
||||
|
||||
6
.gitignore
vendored
@@ -1,12 +1,16 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
|
||||
# generated contract types
|
||||
/src/types/v3
|
||||
/src/abis/types
|
||||
/src/locales/**/*.js
|
||||
/src/locales/**/en-US.po
|
||||
/src/locales/**/pseudo.po
|
||||
/src/state/data/generated.ts
|
||||
|
||||
# generated graphql types
|
||||
/src/graphql/schema/
|
||||
__generated__/
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
@@ -1 +1 @@
|
||||
/src/state/data/generated.ts
|
||||
/src/schema/schema.graphql
|
||||
@@ -2,10 +2,6 @@ overrideExisting: true
|
||||
schema: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3'
|
||||
documents: 'src/**/!(*.d).{ts,tsx}'
|
||||
generates:
|
||||
./src/state/data/generated.ts:
|
||||
./src/graphql/schema/schema.graphql:
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-operations
|
||||
- typescript-rtk-query:
|
||||
importBaseApiFrom: './slice'
|
||||
exportHooks: true
|
||||
- schema-ast
|
||||
|
||||
@@ -37,8 +37,8 @@ describe('Add Liquidity', () => {
|
||||
it('loads fee tier distribution', () => {
|
||||
cy.fixture('feeTierDistribution.json').then((feeTierDistribution) => {
|
||||
cy.intercept('POST', '/subgraphs/name/uniswap/uniswap-v3', (req: CyHttpMessages.IncomingHttpRequest) => {
|
||||
if (hasQuery(req, 'feeTierDistribution')) {
|
||||
req.alias = 'feeTierDistributionQuery'
|
||||
if (hasQuery(req, 'FeeTierDistributionQuery')) {
|
||||
req.alias = 'FeeTierDistributionQuery'
|
||||
|
||||
req.reply({
|
||||
body: {
|
||||
@@ -55,7 +55,7 @@ describe('Add Liquidity', () => {
|
||||
|
||||
cy.visit('/add/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85/0xc778417E063141139Fce010982780140Aa0cD5Ab')
|
||||
|
||||
cy.wait('@feeTierDistributionQuery')
|
||||
cy.wait('@FeeTierDistributionQuery')
|
||||
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40%')
|
||||
|
||||
@@ -35,6 +35,7 @@ Cypress.Commands.overwrite(
|
||||
onBeforeLoad(win) {
|
||||
options?.onBeforeLoad?.(win)
|
||||
win.localStorage.clear()
|
||||
win.localStorage.setItem('redux_localstorage_simple_user', '{"selectedWallet":"INJECTED"}')
|
||||
win.ethereum = injected
|
||||
},
|
||||
})
|
||||
|
||||
28
package.json
@@ -8,7 +8,8 @@
|
||||
"contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types \"./src/abis/**/*.json\"",
|
||||
"contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 \"./node_modules/@uniswap/**/artifacts/contracts/**/*[!dbg].json\"",
|
||||
"contracts:compile": "yarn contracts:compile:abi && yarn contracts:compile:v3",
|
||||
"graphql:generate": "graphql-codegen --config codegen.yml",
|
||||
"relay": "relay-compiler",
|
||||
"graphql:generate": "graphql-codegen --config codegen.yml && yarn relay",
|
||||
"prei18n:extract": "node prei18n-extract.js",
|
||||
"i18n:extract": "lingui extract --locale en-US",
|
||||
"i18n:compile": "yarn i18n:extract && lingui compile",
|
||||
@@ -22,6 +23,11 @@
|
||||
"cypress:open": "cypress open --browser chrome --e2e",
|
||||
"cypress:run": "cypress run --browser chrome --e2e"
|
||||
},
|
||||
"relay": {
|
||||
"src": "./src",
|
||||
"language": "typescript",
|
||||
"schema": "./src/graphql/schema/schema.graphql"
|
||||
},
|
||||
"jest": {
|
||||
"collectCoverageFrom": [
|
||||
"src/components/**/*.ts*",
|
||||
@@ -58,8 +64,7 @@
|
||||
"@craco/craco": "6.4.3",
|
||||
"@ethersproject/experimental": "^5.4.0",
|
||||
"@graphql-codegen/cli": "1.21.5",
|
||||
"@graphql-codegen/typescript": "1.22.3",
|
||||
"@graphql-codegen/typescript-operations": "^1.18.2",
|
||||
"@graphql-codegen/schema-ast": "^2.5.1",
|
||||
"@graphql-codegen/typescript-rtk-query": "^1.1.1",
|
||||
"@lingui/cli": "^3.9.0",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
@@ -90,6 +95,9 @@
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4",
|
||||
"@typescript-eslint/parser": "^4",
|
||||
"babel-plugin-relay": "^14.1.0",
|
||||
"@vanilla-extract/babel-plugin": "^1.1.7",
|
||||
"@vanilla-extract/webpack-plugin": "^2.1.11",
|
||||
"cypress": "^10.3.1",
|
||||
"env-cmd": "^10.1.0",
|
||||
"eslint": "^7.11.0",
|
||||
@@ -104,15 +112,13 @@
|
||||
"ms.macro": "^2.0.0",
|
||||
"prettier": "^2.7.1",
|
||||
"react-scripts": "^4.0.3",
|
||||
"relay-compiler": "^14.1.0",
|
||||
"serve": "^11.3.2",
|
||||
"typechain": "^5.0.0",
|
||||
"typescript": "^4.4.3",
|
||||
"@vanilla-extract/babel-plugin": "^1.1.7",
|
||||
"@vanilla-extract/webpack-plugin": "^2.1.11"
|
||||
"typescript": "^4.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amplitude/analytics-browser": "^0.5.1",
|
||||
"@amplitude/experiment-js-client": "^1.5.4",
|
||||
"@amplitude/analytics-browser": "^1.1.4",
|
||||
"@coinbase/wallet-sdk": "^3.3.0",
|
||||
"@fontsource/ibm-plex-mono": "^4.5.1",
|
||||
"@fontsource/inter": "^4.5.1",
|
||||
@@ -127,6 +133,7 @@
|
||||
"@reach/portal": "^0.10.3",
|
||||
"@react-hook/window-scroll": "^1.3.0",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@types/react-relay": "^13.0.2",
|
||||
"@uniswap/governance": "^1.0.2",
|
||||
"@uniswap/liquidity-staker": "^1.0.2",
|
||||
"@uniswap/merkle-distributor": "1.0.1",
|
||||
@@ -141,6 +148,7 @@
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"@uniswap/v3-sdk": "^3.9.0",
|
||||
"@uniswap/widgets": "^2.1.1",
|
||||
"@vanilla-extract/css": "^1.7.2",
|
||||
"@vanilla-extract/css-utils": "^0.1.2",
|
||||
"@vanilla-extract/dynamic": "^2.0.2",
|
||||
@@ -174,7 +182,7 @@
|
||||
"firebase": "^9.1.3",
|
||||
"focus-visible": "^5.2.0",
|
||||
"fortmatic": "^2.4.0",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql": "^16.5.0",
|
||||
"graphql-request": "^3.4.0",
|
||||
"immer": "^9.0.6",
|
||||
"inter-ui": "^3.13.1",
|
||||
@@ -199,6 +207,7 @@
|
||||
"react-popper": "^2.2.3",
|
||||
"react-query": "^3.39.1",
|
||||
"react-redux": "^8.0.2",
|
||||
"react-relay": "^14.1.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-spring": "^8.0.27",
|
||||
"react-table": "^7.8.0",
|
||||
@@ -208,6 +217,7 @@
|
||||
"rebass": "^4.0.7",
|
||||
"redux": "^4.1.2",
|
||||
"redux-localstorage-simple": "^2.3.1",
|
||||
"relay-hooks": "^7.1.0",
|
||||
"setimmediate": "^1.0.5",
|
||||
"styled-components": "^5.3.5",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
|
||||
BIN
src/assets/images/arbitrumCircle.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/images/celoCircle.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/images/optimismCircle.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/images/polygonCircle.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
3
src/assets/svg/share.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="#fff">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m14-7-5-5-5 5m5-5v12"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 257 B |
@@ -1,64 +0,0 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useCopyClipboard from 'hooks/useCopyClipboard'
|
||||
import React, { useCallback } from 'react'
|
||||
import { CheckCircle, Copy } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { LinkStyledButton } from 'theme'
|
||||
|
||||
const CopyIcon = styled(LinkStyledButton)`
|
||||
color: ${({ color, theme }) => color || theme.accentAction};
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
:hover,
|
||||
:active,
|
||||
:focus {
|
||||
text-decoration: none;
|
||||
color: ${({ color, theme }) => color || theme.accentAction};
|
||||
}
|
||||
`
|
||||
const StyledText = styled.span`
|
||||
margin-left: 0.25rem;
|
||||
${({ theme }) => theme.flexRowNoWrap};
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const Copied = ({ iconSize }: { iconSize?: number }) => (
|
||||
<StyledText>
|
||||
<CheckCircle size={iconSize ?? '16'} />
|
||||
<StyledText>
|
||||
<Trans>Copied</Trans>
|
||||
</StyledText>
|
||||
</StyledText>
|
||||
)
|
||||
|
||||
const Icon = ({ iconSize }: { iconSize?: number }) => (
|
||||
<StyledText>
|
||||
<Copy size={iconSize ?? '16'} />
|
||||
</StyledText>
|
||||
)
|
||||
|
||||
interface BaseProps {
|
||||
toCopy: string
|
||||
color?: string
|
||||
iconSize?: number
|
||||
iconPosition?: 'left' | 'right'
|
||||
}
|
||||
export type CopyHelperProps = BaseProps & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, keyof BaseProps>
|
||||
|
||||
export default function CopyHelper({ color, toCopy, children, iconSize, iconPosition }: CopyHelperProps) {
|
||||
const [isCopied, setCopied] = useCopyClipboard()
|
||||
const copy = useCallback(() => {
|
||||
setCopied(toCopy)
|
||||
}, [toCopy, setCopied])
|
||||
|
||||
return (
|
||||
<CopyIcon onClick={copy} color={color}>
|
||||
{iconPosition === 'left' ? isCopied ? <Copied iconSize={iconSize} /> : <Icon iconSize={iconSize} /> : null}
|
||||
{iconPosition === 'left' && <> </>}
|
||||
{isCopied ? '' : children}
|
||||
{iconPosition === 'right' && <> </>}
|
||||
{iconPosition === 'right' ? isCopied ? <Copied iconSize={iconSize} /> : <Icon iconSize={iconSize} /> : null}
|
||||
</CopyIcon>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import CopyHelper from 'components/AccountDetails/Copy'
|
||||
import { getConnection, getConnectionName, getIsCoinbaseWallet, getIsMetaMask } from 'connection/utils'
|
||||
import { Context, useCallback, useContext } from 'react'
|
||||
import { useCallback } from 'react'
|
||||
import { ExternalLink as LinkIcon } from 'react-feather'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { updateSelectedWallet } from 'state/user/reducer'
|
||||
import { removeConnectedWallet } from 'state/wallets/reducer'
|
||||
import { DefaultTheme } from 'styled-components/macro'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { isMobile } from 'utils/userAgent'
|
||||
|
||||
import { ReactComponent as Close } from '../../assets/images/x.svg'
|
||||
import { clearAllTransactions } from '../../state/transactions/reducer'
|
||||
import { ExternalLink, LinkStyledButton, ThemedText } from '../../theme'
|
||||
import { CopyHelper, ExternalLink, LinkStyledButton, ThemedText } from '../../theme'
|
||||
import { shortenAddress } from '../../utils'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { ButtonSecondary } from '../Button'
|
||||
@@ -130,11 +128,12 @@ const AccountControl = styled.div`
|
||||
`
|
||||
|
||||
const AddressLink = styled(ExternalLink)`
|
||||
font-size: 0.825rem;
|
||||
color: ${({ theme }) => theme.deprecated_text3};
|
||||
margin-left: 1rem;
|
||||
font-size: 0.825rem;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
text-decoration: none !important;
|
||||
:hover {
|
||||
color: ${({ theme }) => theme.deprecated_text2};
|
||||
}
|
||||
@@ -207,7 +206,7 @@ export default function AccountDetails({
|
||||
const { chainId, account, connector } = useWeb3React()
|
||||
const connectionType = getConnection(connector).type
|
||||
|
||||
const theme = useContext(ThemeContext as Context<DefaultTheme>)
|
||||
const theme = useTheme()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const isMetaMask = getIsMetaMask()
|
||||
@@ -284,7 +283,7 @@ export default function AccountDetails({
|
||||
<AccountControl>
|
||||
<div>
|
||||
{account && (
|
||||
<CopyHelper toCopy={account} iconPosition="left">
|
||||
<CopyHelper toCopy={account} gap={6} iconSize={16} fontSize={14}>
|
||||
<Trans>Copy Address</Trans>
|
||||
</CopyHelper>
|
||||
)}
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Trans } from '@lingui/macro'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { ChangeEvent, Context, ReactNode, useCallback, useContext } from 'react'
|
||||
import styled, { DefaultTheme, ThemeContext } from 'styled-components/macro'
|
||||
import { ChangeEvent, ReactNode, useCallback } from 'react'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import useENS from '../../hooks/useENS'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
@@ -87,7 +87,7 @@ export default function AddressInputPanel({
|
||||
onChange: (value: string) => void
|
||||
}) {
|
||||
const { chainId } = useWeb3React()
|
||||
const theme = useContext(ThemeContext as Context<DefaultTheme>)
|
||||
const theme = useTheme()
|
||||
|
||||
const { address, loading, name } = useENS(value)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ export enum EventName {
|
||||
TOKEN_SELECTOR_OPENED = 'Token Selector Opened',
|
||||
WALLET_CONNECT_TXN_COMPLETED = 'Wallet Connect Transaction Completed',
|
||||
WALLET_SELECTED = 'Wallet Selected',
|
||||
WEB_VITALS = 'Web Vitals',
|
||||
WRAP_TOKEN_TXN_SUBMITTED = 'Wrap Token Transaction Submitted',
|
||||
// alphabetize additional event names.
|
||||
}
|
||||
@@ -74,7 +75,7 @@ export enum SWAP_PRICE_UPDATE_USER_RESPONSE {
|
||||
* Known pages in the app. Highest order context.
|
||||
*/
|
||||
export enum PageName {
|
||||
EXPLORE_PAGE = 'explore-page',
|
||||
TOKENS_PAGE = 'tokens-page',
|
||||
POOL_PAGE = 'pool-page',
|
||||
SWAP_PAGE = 'swap-page',
|
||||
VOTE_PAGE = 'vote-page',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Identify, identify, init, track } from '@amplitude/analytics-browser'
|
||||
import { isDevelopmentEnv } from 'utils/env'
|
||||
import { isProductionEnv } from 'utils/env'
|
||||
|
||||
/**
|
||||
* Initializes Amplitude with API key for project.
|
||||
@@ -8,21 +8,19 @@ import { isDevelopmentEnv } from 'utils/env'
|
||||
* member of the organization on Amplitude to view details.
|
||||
*/
|
||||
export function initializeAnalytics() {
|
||||
if (isDevelopmentEnv()) return
|
||||
const API_KEY = isProductionEnv() ? process.env.REACT_APP_AMPLITUDE_KEY : process.env.REACT_APP_AMPLITUDE_TEST_KEY
|
||||
|
||||
const API_KEY = process.env.REACT_APP_AMPLITUDE_KEY
|
||||
if (typeof API_KEY === 'undefined') {
|
||||
throw new Error(`REACT_APP_AMPLITUDE_KEY must be a defined environment variable`)
|
||||
const keyName = isProductionEnv() ? 'REACT_APP_AMPLITUDE_KEY' : 'REACT_APP_AMPLITUDE_TEST_KEY'
|
||||
console.error(`${keyName} is undefined, Amplitude analytics will not run.`)
|
||||
return
|
||||
}
|
||||
|
||||
init(
|
||||
API_KEY,
|
||||
/* userId= */ undefined, // User ID should be undefined to let Amplitude default to Device ID
|
||||
/* options= */ {
|
||||
// See documentation: https://www.docs.developers.amplitude.com/data/sdks/javascript/#track-referrers
|
||||
includeReferrer: true,
|
||||
// See documentation: https://www.docs.developers.amplitude.com/data/sdks/javascript/#track-utm-parameters
|
||||
includeUtm: true,
|
||||
/* options= */
|
||||
{
|
||||
// Disable tracking of private user information by Amplitude
|
||||
trackingOptions: {
|
||||
ipAddress: false,
|
||||
@@ -35,9 +33,9 @@ export function initializeAnalytics() {
|
||||
)
|
||||
}
|
||||
|
||||
/** Sends an event to Amplitude. */
|
||||
/** Sends an approved (finalized) event to Amplitude production project. */
|
||||
export function sendAnalyticsEvent(eventName: string, eventProperties?: Record<string, unknown>) {
|
||||
if (isDevelopmentEnv()) {
|
||||
if (!isProductionEnv()) {
|
||||
console.log(`[amplitude(${eventName})]: ${JSON.stringify(eventProperties)}`)
|
||||
return
|
||||
}
|
||||
@@ -45,6 +43,13 @@ export function sendAnalyticsEvent(eventName: string, eventProperties?: Record<s
|
||||
track(eventName, eventProperties)
|
||||
}
|
||||
|
||||
/** Sends a draft event to Amplitude test project. */
|
||||
export function sendTestAnalyticsEvent(eventName: string, eventProperties?: Record<string, unknown>) {
|
||||
if (isProductionEnv()) return
|
||||
|
||||
track(eventName, eventProperties)
|
||||
}
|
||||
|
||||
type Value = string | number | boolean | string[] | number[]
|
||||
|
||||
/**
|
||||
@@ -60,7 +65,7 @@ class UserModel {
|
||||
}
|
||||
|
||||
private call(mutate: (event: Identify) => Identify) {
|
||||
if (isDevelopmentEnv()) {
|
||||
if (!isProductionEnv()) {
|
||||
const log = (_: Identify, method: string) => this.log.bind(this, method)
|
||||
mutate(new Proxy(new Identify(), { get: log }))
|
||||
return
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { darken } from 'polished'
|
||||
import { Check, ChevronDown } from 'react-feather'
|
||||
import { Button as RebassButton, ButtonProps as ButtonPropsOriginal } from 'rebass/styled-components'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { RowBetween } from '../Row'
|
||||
|
||||
@@ -51,9 +50,12 @@ export const BaseButton = styled(RebassButton)<
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonPrimary = styled(BaseButton)`
|
||||
background-color: ${({ theme }) => theme.deprecated_primary1};
|
||||
color: white;
|
||||
export const ButtonPrimary = styled(BaseButton)<{ redesignFlag?: boolean }>`
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.accentAction : theme.deprecated_primary1)};
|
||||
font-size: ${({ redesignFlag }) => redesignFlag && '20px'};
|
||||
font-weight: ${({ redesignFlag }) => redesignFlag && '600'};
|
||||
padding: ${({ redesignFlag }) => redesignFlag && '16px'};
|
||||
color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.accentTextLightPrimary : 'white')};
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 1pt ${({ theme }) => darken(0.05, theme.deprecated_primary1)};
|
||||
background-color: ${({ theme }) => darken(0.05, theme.deprecated_primary1)};
|
||||
@@ -77,35 +79,35 @@ export const ButtonPrimary = styled(BaseButton)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonLight = styled(BaseButton)<{ phase0Flag?: boolean }>`
|
||||
background-color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.accentActionSoft : theme.deprecated_primary5)};
|
||||
color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.accentAction : theme.deprecated_primaryText1)};
|
||||
font-size: ${({ phase0Flag }) => (phase0Flag ? '20px' : '16px')};
|
||||
font-weight: ${({ phase0Flag }) => (phase0Flag ? '600' : '500')};
|
||||
export const ButtonLight = styled(BaseButton)<{ redesignFlag?: boolean }>`
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.accentActionSoft : theme.deprecated_primary5)};
|
||||
color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.accentAction : theme.deprecated_primaryText1)};
|
||||
font-size: ${({ redesignFlag }) => (redesignFlag ? '20px' : '16px')};
|
||||
font-weight: ${({ redesignFlag }) => (redesignFlag ? '600' : '500')};
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 1pt
|
||||
${({ theme, disabled, phase0Flag }) =>
|
||||
!disabled && (phase0Flag ? theme.accentActionSoft : darken(0.03, theme.deprecated_primary5))};
|
||||
background-color: ${({ theme, disabled, phase0Flag }) =>
|
||||
!disabled && (phase0Flag ? theme.accentActionSoft : darken(0.03, theme.deprecated_primary5))};
|
||||
${({ theme, disabled, redesignFlag }) =>
|
||||
!disabled && (redesignFlag ? theme.accentActionSoft : darken(0.03, theme.deprecated_primary5))};
|
||||
background-color: ${({ theme, disabled, redesignFlag }) =>
|
||||
!disabled && (redesignFlag ? theme.accentActionSoft : darken(0.03, theme.deprecated_primary5))};
|
||||
}
|
||||
&:hover {
|
||||
background-color: ${({ theme, disabled, phase0Flag }) =>
|
||||
!disabled && (phase0Flag ? theme.accentActionSoft : darken(0.03, theme.deprecated_primary5))};
|
||||
background-color: ${({ theme, disabled, redesignFlag }) =>
|
||||
!disabled && (redesignFlag ? theme.accentActionSoft : darken(0.03, theme.deprecated_primary5))};
|
||||
}
|
||||
&:active {
|
||||
box-shadow: 0 0 0 1pt
|
||||
${({ theme, disabled, phase0Flag }) =>
|
||||
!disabled && (phase0Flag ? theme.accentActionSoft : darken(0.05, theme.deprecated_primary5))};
|
||||
background-color: ${({ theme, disabled, phase0Flag }) =>
|
||||
!disabled && (phase0Flag ? theme.accentActionSoft : darken(0.05, theme.deprecated_primary5))};
|
||||
${({ theme, disabled, redesignFlag }) =>
|
||||
!disabled && (redesignFlag ? theme.accentActionSoft : darken(0.05, theme.deprecated_primary5))};
|
||||
background-color: ${({ theme, disabled, redesignFlag }) =>
|
||||
!disabled && (redesignFlag ? theme.accentActionSoft : darken(0.05, theme.deprecated_primary5))};
|
||||
}
|
||||
:disabled {
|
||||
opacity: 0.4;
|
||||
:hover {
|
||||
cursor: auto;
|
||||
background-color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.none : theme.deprecated_primary5)};
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? 'transparent' : theme.deprecated_primary5)};
|
||||
box-shadow: none;
|
||||
border: 1px solid transparent;
|
||||
outline: none;
|
||||
|
||||
@@ -11,7 +11,7 @@ interface LineChartProps<T> {
|
||||
data: T[]
|
||||
getX: (t: T) => number
|
||||
getY: (t: T) => number
|
||||
marginTop: number
|
||||
marginTop?: number
|
||||
curve?: CurveFactory
|
||||
color?: Color
|
||||
strokeWidth: number
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { scaleLinear } from 'd3'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import React from 'react'
|
||||
import { useTheme } from 'styled-components/macro'
|
||||
|
||||
import data from './data.json'
|
||||
import LineChart from './LineChart'
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import CopyHelper from 'components/AccountDetails/Copy'
|
||||
import Column from 'components/Column'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { AlertOctagon } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ExternalLink, ThemedText } from 'theme'
|
||||
|
||||
import { CopyHelper } from '../../theme'
|
||||
import Modal from '../Modal'
|
||||
|
||||
const ContentWrapper = styled(Column)`
|
||||
align-items: center;
|
||||
margin: 32px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
`
|
||||
const WarningIcon = styled(AlertOctagon)`
|
||||
min-height: 22px;
|
||||
@@ -49,7 +49,14 @@ export default function ConnectedAccountBlocked(props: ConnectedAccountBlockedPr
|
||||
<ThemedText.DeprecatedMain fontSize={12}>
|
||||
<Trans>If you believe this is an error, please send an email including your address to </Trans>{' '}
|
||||
</ThemedText.DeprecatedMain>
|
||||
<Copy iconSize={12} toCopy="compliance@uniswap.org" color={theme.deprecated_primary1} iconPosition="right">
|
||||
<Copy
|
||||
toCopy="compliance@uniswap.org"
|
||||
fontSize={14}
|
||||
iconSize={16}
|
||||
gap={6}
|
||||
color={theme.deprecated_primary1}
|
||||
iconPosition="right"
|
||||
>
|
||||
compliance@uniswap.org
|
||||
</Copy>
|
||||
</ContentWrapper>
|
||||
|
||||
@@ -4,8 +4,8 @@ import { t } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
|
||||
import HoverInlineText from 'components/HoverInlineText'
|
||||
import { useMemo } from 'react'
|
||||
import { useTheme } from 'styled-components/macro'
|
||||
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { warningSeverity } from '../../utils/prices'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
|
||||
@@ -7,15 +7,14 @@ import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { LoadingOpacityContainer, loadingOpacityMixin } from 'components/Loader/styled'
|
||||
import { isSupportedChain } from 'constants/chains'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { darken } from 'polished'
|
||||
import { ReactNode, useCallback, useState } from 'react'
|
||||
import { Lock } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
|
||||
|
||||
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { useCurrencyBalance } from '../../state/connection/hooks'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ButtonGray } from '../Button'
|
||||
@@ -26,37 +25,37 @@ import { RowBetween, RowFixed } from '../Row'
|
||||
import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
|
||||
import { FiatValue } from './FiatValue'
|
||||
|
||||
const InputPanel = styled.div<{ hideInput?: boolean; phase0Flag: boolean }>`
|
||||
const InputPanel = styled.div<{ hideInput?: boolean; redesignFlag: boolean }>`
|
||||
${({ theme }) => theme.flexColumnNoWrap}
|
||||
position: relative;
|
||||
border-radius: ${({ hideInput }) => (hideInput ? '16px' : '20px')};
|
||||
background-color: ${({ theme, phase0Flag, hideInput }) =>
|
||||
phase0Flag ? theme.none : hideInput ? 'transparent' : theme.deprecated_bg2};
|
||||
background-color: ${({ theme, redesignFlag, hideInput }) =>
|
||||
redesignFlag ? 'transparent' : hideInput ? 'transparent' : theme.deprecated_bg2};
|
||||
z-index: 1;
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
transition: height 1s ease;
|
||||
will-change: height;
|
||||
`
|
||||
|
||||
const FixedContainer = styled.div<{ phase0Flag: boolean }>`
|
||||
const FixedContainer = styled.div<{ redesignFlag: boolean }>`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
border-radius: 20px;
|
||||
background-color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.none : theme.deprecated_bg2)};
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? 'transparent' : theme.deprecated_bg2)};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2;
|
||||
`
|
||||
|
||||
const Container = styled.div<{ hideInput: boolean; disabled: boolean; phase0Flag: boolean }>`
|
||||
const Container = styled.div<{ hideInput: boolean; disabled: boolean; redesignFlag: boolean }>`
|
||||
border-radius: ${({ hideInput }) => (hideInput ? '16px' : '20px')};
|
||||
border: 1px solid ${({ theme, phase0Flag }) => (phase0Flag ? theme.none : theme.deprecated_bg0)};
|
||||
background-color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.none : theme.deprecated_bg1)};
|
||||
border: 1px solid ${({ theme, redesignFlag }) => (redesignFlag ? 'transparent' : theme.deprecated_bg0)};
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? 'transparent' : theme.deprecated_bg1)};
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
${({ theme, hideInput, disabled, phase0Flag }) =>
|
||||
!phase0Flag &&
|
||||
${({ theme, hideInput, disabled, redesignFlag }) =>
|
||||
!redesignFlag &&
|
||||
!disabled &&
|
||||
`
|
||||
:focus,
|
||||
@@ -71,11 +70,11 @@ const CurrencySelect = styled(ButtonGray)<{
|
||||
selected: boolean
|
||||
hideInput?: boolean
|
||||
disabled?: boolean
|
||||
phase0Flag: boolean
|
||||
redesignFlag: boolean
|
||||
}>`
|
||||
align-items: center;
|
||||
background-color: ${({ selected, theme, phase0Flag }) =>
|
||||
phase0Flag
|
||||
background-color: ${({ selected, theme, redesignFlag }) =>
|
||||
redesignFlag
|
||||
? selected
|
||||
? theme.backgroundSurface
|
||||
: theme.accentAction
|
||||
@@ -86,7 +85,7 @@ const CurrencySelect = styled(ButtonGray)<{
|
||||
box-shadow: ${({ selected }) => (selected ? 'none' : '0px 6px 10px rgba(0, 0, 0, 0.075)')};
|
||||
color: ${({ selected, theme }) => (selected ? theme.deprecated_text1 : theme.deprecated_white)};
|
||||
cursor: pointer;
|
||||
height: ${({ hideInput, phase0Flag }) => (phase0Flag ? 'unset' : hideInput ? '2.8rem' : '2.4rem')};
|
||||
height: ${({ hideInput, redesignFlag }) => (redesignFlag ? 'unset' : hideInput ? '2.8rem' : '2.4rem')};
|
||||
border-radius: 16px;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
@@ -94,41 +93,42 @@ const CurrencySelect = styled(ButtonGray)<{
|
||||
font-size: 24px;
|
||||
font-weight: 400;
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
padding: ${({ selected, phase0Flag }) => (phase0Flag ? (selected ? '4px 8px 4px 4px' : '6px 6px 6px 8px') : '0 8px')};
|
||||
gap: ${({ phase0Flag }) => (phase0Flag ? '8px' : '0px')};
|
||||
padding: ${({ selected, redesignFlag }) =>
|
||||
redesignFlag ? (selected ? '4px 8px 4px 4px' : '6px 6px 6px 8px') : '0 8px'};
|
||||
gap: ${({ redesignFlag }) => (redesignFlag ? '8px' : '0px')};
|
||||
justify-content: space-between;
|
||||
margin-left: ${({ hideInput }) => (hideInput ? '0' : '12px')};
|
||||
:focus,
|
||||
:hover {
|
||||
background-color: ${({ selected, theme, phase0Flag }) =>
|
||||
background-color: ${({ selected, theme, redesignFlag }) =>
|
||||
selected
|
||||
? phase0Flag
|
||||
? redesignFlag
|
||||
? theme.backgroundSurface
|
||||
: theme.deprecated_bg3
|
||||
: darken(0.05, theme.deprecated_primary1)};
|
||||
}
|
||||
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
|
||||
`
|
||||
const InputCurrencySelect = styled(CurrencySelect)<{ phase0Flag: boolean }>`
|
||||
background-color: ${({ theme, selected, phase0Flag }) =>
|
||||
phase0Flag && (selected ? theme.backgroundModule : theme.accentAction)};
|
||||
const InputCurrencySelect = styled(CurrencySelect)<{ redesignFlag: boolean }>`
|
||||
background-color: ${({ theme, selected, redesignFlag }) =>
|
||||
redesignFlag && (selected ? theme.backgroundModule : theme.accentAction)};
|
||||
:focus,
|
||||
:hover {
|
||||
background-color: ${({ selected, theme, phase0Flag }) =>
|
||||
background-color: ${({ selected, theme, redesignFlag }) =>
|
||||
selected
|
||||
? phase0Flag
|
||||
? redesignFlag
|
||||
? theme.backgroundInteractive
|
||||
: theme.deprecated_bg3
|
||||
: darken(0.05, theme.deprecated_primary1)};
|
||||
}
|
||||
`
|
||||
|
||||
const InputRow = styled.div<{ selected: boolean; phase0Flag: boolean }>`
|
||||
const InputRow = styled.div<{ selected: boolean; redesignFlag: boolean }>`
|
||||
${({ theme }) => theme.flexRowNoWrap}
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: ${({ selected, phase0Flag }) =>
|
||||
phase0Flag ? '0px' : selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 1rem 1rem'};
|
||||
padding: ${({ selected, redesignFlag }) =>
|
||||
redesignFlag ? '0px' : selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 1rem 1rem'};
|
||||
`
|
||||
|
||||
const LabelRow = styled.div`
|
||||
@@ -145,10 +145,10 @@ const LabelRow = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const FiatRow = styled(LabelRow)<{ phase0Flag: boolean }>`
|
||||
const FiatRow = styled(LabelRow)<{ redesignFlag: boolean }>`
|
||||
justify-content: flex-end;
|
||||
padding: ${({ phase0Flag }) => phase0Flag && '8px 0px'};
|
||||
height: ${({ phase0Flag }) => !phase0Flag && '24px'};
|
||||
padding: ${({ redesignFlag }) => redesignFlag && '8px 0px'};
|
||||
height: ${({ redesignFlag }) => !redesignFlag && '24px'};
|
||||
`
|
||||
|
||||
const NoBalanceState = styled.div`
|
||||
@@ -170,34 +170,34 @@ const Aligner = styled.span`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
const StyledDropDown = styled(DropDown)<{ selected: boolean; phase0Flag: boolean }>`
|
||||
const StyledDropDown = styled(DropDown)<{ selected: boolean; redesignFlag: boolean }>`
|
||||
margin: 0 0.25rem 0 0.35rem;
|
||||
height: 35%;
|
||||
margin-left: ${({ phase0Flag }) => phase0Flag && '8px'};
|
||||
margin-left: ${({ redesignFlag }) => redesignFlag && '8px'};
|
||||
|
||||
path {
|
||||
stroke: ${({ selected, theme }) => (selected ? theme.deprecated_text1 : theme.deprecated_white)};
|
||||
stroke-width: ${({ phase0Flag }) => (phase0Flag ? '2px' : '1.5px')};
|
||||
stroke-width: ${({ redesignFlag }) => (redesignFlag ? '2px' : '1.5px')};
|
||||
}
|
||||
`
|
||||
|
||||
const StyledTokenName = styled.span<{ active?: boolean; phase0Flag: boolean }>`
|
||||
const StyledTokenName = styled.span<{ active?: boolean; redesignFlag: boolean }>`
|
||||
${({ active }) => (active ? ' margin: 0 0.25rem 0 0.25rem;' : ' margin: 0 0.25rem 0 0.25rem;')}
|
||||
font-size: ${({ active }) => (active ? '18px' : '18px')};
|
||||
font-weight: ${({ phase0Flag }) => (phase0Flag ? '600' : '500')};
|
||||
font-weight: ${({ redesignFlag }) => (redesignFlag ? '600' : '500')};
|
||||
`
|
||||
|
||||
const StyledBalanceMax = styled.button<{ disabled?: boolean; phase0Flag: boolean }>`
|
||||
const StyledBalanceMax = styled.button<{ disabled?: boolean; redesignFlag: boolean }>`
|
||||
background-color: transparent;
|
||||
background-color: ${({ theme, phase0Flag }) => !phase0Flag && theme.deprecated_primary5};
|
||||
background-color: ${({ theme, redesignFlag }) => !redesignFlag && theme.deprecated_primary5};
|
||||
border: none;
|
||||
text-transform: ${({ phase0Flag }) => !phase0Flag && 'uppercase'};
|
||||
border-radius: ${({ phase0Flag }) => !phase0Flag && '12px'};
|
||||
color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.accentAction : theme.deprecated_primary1)};
|
||||
text-transform: ${({ redesignFlag }) => !redesignFlag && 'uppercase'};
|
||||
border-radius: ${({ redesignFlag }) => !redesignFlag && '12px'};
|
||||
color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.accentAction : theme.deprecated_primary1)};
|
||||
cursor: pointer;
|
||||
font-size: ${({ phase0Flag }) => (phase0Flag ? '14px' : '11px')};
|
||||
font-weight: ${({ phase0Flag }) => (phase0Flag ? '600' : '500')};
|
||||
margin-left: ${({ phase0Flag }) => (phase0Flag ? '0px' : '0.25rem')};
|
||||
font-size: ${({ redesignFlag }) => (redesignFlag ? '14px' : '11px')};
|
||||
font-weight: ${({ redesignFlag }) => (redesignFlag ? '600' : '500')};
|
||||
margin-left: ${({ redesignFlag }) => (redesignFlag ? '0px' : '0.25rem')};
|
||||
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
|
||||
padding: 4px 6px;
|
||||
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
|
||||
@@ -211,11 +211,11 @@ const StyledBalanceMax = styled.button<{ disabled?: boolean; phase0Flag: boolean
|
||||
}
|
||||
`
|
||||
|
||||
const StyledNumericalInput = styled(NumericalInput)<{ $loading: boolean; phase0Flag: boolean }>`
|
||||
const StyledNumericalInput = styled(NumericalInput)<{ $loading: boolean; redesignFlag: boolean }>`
|
||||
${loadingOpacityMixin};
|
||||
text-align: left;
|
||||
font-variant: ${({ phase0Flag }) => phase0Flag && 'small-caps'};
|
||||
font-feature-settings: ${({ phase0Flag }) => phase0Flag && 'pnum on, lnum on'};
|
||||
font-variant: ${({ redesignFlag }) => redesignFlag && 'small-caps'};
|
||||
font-feature-settings: ${({ redesignFlag }) => redesignFlag && 'pnum on, lnum on'};
|
||||
`
|
||||
|
||||
interface CurrencyInputPanelProps {
|
||||
@@ -265,8 +265,8 @@ export default function CurrencyInputPanel({
|
||||
}: CurrencyInputPanelProps) {
|
||||
const [modalOpen, setModalOpen] = useState(false)
|
||||
const { account, chainId } = useWeb3React()
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
const selectedCurrencyBalance = useCurrencyBalance(account ?? undefined, currency ?? undefined)
|
||||
const theme = useTheme()
|
||||
|
||||
@@ -277,9 +277,9 @@ export default function CurrencyInputPanel({
|
||||
const chainAllowed = isSupportedChain(chainId)
|
||||
|
||||
return (
|
||||
<InputPanel id={id} hideInput={hideInput} {...rest} phase0Flag={phase0FlagEnabled}>
|
||||
<InputPanel id={id} hideInput={hideInput} {...rest} redesignFlag={redesignFlagEnabled}>
|
||||
{locked && (
|
||||
<FixedContainer phase0Flag={phase0FlagEnabled}>
|
||||
<FixedContainer redesignFlag={redesignFlagEnabled}>
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Lock />
|
||||
<ThemedText.DeprecatedLabel fontSize="12px" textAlign="center" padding="0 12px">
|
||||
@@ -288,11 +288,11 @@ export default function CurrencyInputPanel({
|
||||
</AutoColumn>
|
||||
</FixedContainer>
|
||||
)}
|
||||
<Container hideInput={hideInput} disabled={!chainAllowed} phase0Flag={phase0FlagEnabled}>
|
||||
<Container hideInput={hideInput} disabled={!chainAllowed} redesignFlag={redesignFlagEnabled}>
|
||||
<InputRow
|
||||
style={hideInput ? { padding: '0', borderRadius: '8px' } : {}}
|
||||
selected={!onCurrencySelect}
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
>
|
||||
{!hideInput && (
|
||||
<StyledNumericalInput
|
||||
@@ -301,7 +301,7 @@ export default function CurrencyInputPanel({
|
||||
onUserInput={onUserInput}
|
||||
disabled={!chainAllowed}
|
||||
$loading={loading}
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -310,7 +310,7 @@ export default function CurrencyInputPanel({
|
||||
visible={currency !== undefined}
|
||||
selected={!!currency}
|
||||
hideInput={hideInput}
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
className="open-currency-select-button"
|
||||
onClick={() => {
|
||||
if (onCurrencySelect) {
|
||||
@@ -328,14 +328,14 @@ export default function CurrencyInputPanel({
|
||||
<CurrencyLogo style={{ marginRight: '2px' }} currency={currency} size={'24px'} />
|
||||
) : null}
|
||||
{pair ? (
|
||||
<StyledTokenName className="pair-name-container" phase0Flag={phase0FlagEnabled}>
|
||||
<StyledTokenName className="pair-name-container" redesignFlag={redesignFlagEnabled}>
|
||||
{pair?.token0.symbol}:{pair?.token1.symbol}
|
||||
</StyledTokenName>
|
||||
) : (
|
||||
<StyledTokenName
|
||||
className="token-symbol-container"
|
||||
active={Boolean(currency && currency.symbol)}
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
>
|
||||
{(currency && currency.symbol && currency.symbol.length > 20
|
||||
? currency.symbol.slice(0, 4) +
|
||||
@@ -345,13 +345,13 @@ export default function CurrencyInputPanel({
|
||||
</StyledTokenName>
|
||||
)}
|
||||
</RowFixed>
|
||||
{onCurrencySelect && <StyledDropDown selected={!!currency} phase0Flag={phase0FlagEnabled} />}
|
||||
{onCurrencySelect && <StyledDropDown selected={!!currency} redesignFlag={redesignFlagEnabled} />}
|
||||
</Aligner>
|
||||
</InputCurrencySelect>
|
||||
</InputRow>
|
||||
{phase0FlagEnabled && !currency && (
|
||||
{redesignFlagEnabled && !currency && (
|
||||
<NoBalanceState>
|
||||
<FiatRow phase0Flag={phase0FlagEnabled}>
|
||||
<FiatRow redesignFlag={redesignFlagEnabled}>
|
||||
<RowBetween>
|
||||
<NoBalanceDash>-</NoBalanceDash>
|
||||
<NoBalanceDash>-</NoBalanceDash>
|
||||
@@ -360,7 +360,7 @@ export default function CurrencyInputPanel({
|
||||
</NoBalanceState>
|
||||
)}
|
||||
{!hideInput && !hideBalance && currency && (
|
||||
<FiatRow phase0Flag={phase0FlagEnabled}>
|
||||
<FiatRow redesignFlag={redesignFlagEnabled}>
|
||||
<RowBetween>
|
||||
<LoadingOpacityContainer $loading={loading}>
|
||||
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
|
||||
@@ -388,7 +388,7 @@ export default function CurrencyInputPanel({
|
||||
name={EventName.SWAP_MAX_TOKEN_AMOUNT_SELECTED}
|
||||
element={ElementName.MAX_TOKEN_AMOUNT_BUTTON}
|
||||
>
|
||||
<StyledBalanceMax onClick={onMax} phase0Flag={phase0FlagEnabled}>
|
||||
<StyledBalanceMax onClick={onMax} redesignFlag={redesignFlagEnabled}>
|
||||
<Trans>Max</Trans>
|
||||
</StyledBalanceMax>
|
||||
</TraceEvent>
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import { darken } from 'polished'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Check, Link, Share, Twitter } from 'react-feather'
|
||||
import { useModalIsOpen, useToggleModal } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { Z_INDEX } from 'theme'
|
||||
|
||||
const TWITTER_WIDTH = 560
|
||||
const TWITTER_HEIGHT = 480
|
||||
|
||||
const ShareButtonDisplay = styled.div`
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: ${Z_INDEX.dropdown};
|
||||
|
||||
&:hover {
|
||||
color: ${({ theme }) => darken(0.1, theme.textSecondary)};
|
||||
}
|
||||
`
|
||||
const ShareActions = styled.div`
|
||||
position: absolute;
|
||||
top: 28px;
|
||||
right: 0px;
|
||||
padding: 8px 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: fit-content;
|
||||
overflow: auto;
|
||||
background-color: ${({ theme }) => theme.backgroundSurface};
|
||||
border: 1px solid ${({ theme }) => theme.backgroundOutline};
|
||||
box-shadow: ${({ theme }) => theme.flyoutDropShadow};
|
||||
border-radius: 12px;
|
||||
`
|
||||
const ShareAction = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
font-size: 16px;
|
||||
gap: 8px;
|
||||
width: 200px;
|
||||
height: 48px;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: ${({ theme }) => theme.backgroundModule};
|
||||
}
|
||||
`
|
||||
|
||||
const LinkCopied = styled.div<{ show: boolean }>`
|
||||
display: ${({ show }) => (show ? 'flex' : 'none')};
|
||||
width: 328px;
|
||||
height: 72px;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
background-color: ${({ theme }) => theme.backgroundBackdrop};
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 24px 16px;
|
||||
position: absolute;
|
||||
right: 32px;
|
||||
bottom: 32px;
|
||||
font-size: 14px;
|
||||
gap: 8px;
|
||||
border: 1px solid rgba(153, 161, 189, 0.08);
|
||||
box-shadow: ${({ theme }) => theme.flyoutDropShadow};
|
||||
border-radius: 20px;
|
||||
animation: floatIn 0s ease-in 3s forwards;
|
||||
|
||||
@keyframes floatIn {
|
||||
to {
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`
|
||||
interface TokenInfo {
|
||||
tokenName: string
|
||||
tokenSymbol: string
|
||||
}
|
||||
|
||||
export default function ShareButton(tokenInfo: TokenInfo) {
|
||||
const theme = useTheme()
|
||||
const node = useRef<HTMLDivElement | null>(null)
|
||||
const open = useModalIsOpen(ApplicationModal.SHARE)
|
||||
const toggleShare = useToggleModal(ApplicationModal.SHARE)
|
||||
useOnClickOutside(node, open ? toggleShare : undefined)
|
||||
const [showCopied, setShowCopied] = useState(false)
|
||||
const positionX = (window.screen.width - TWITTER_WIDTH) / 2
|
||||
const positionY = (window.screen.height - TWITTER_HEIGHT) / 2
|
||||
|
||||
const shareTweet = () => {
|
||||
toggleShare()
|
||||
window.open(
|
||||
`https://twitter.com/intent/tweet?text=Check%20out%20${tokenInfo.tokenName}%20(${tokenInfo.tokenSymbol})%20https://app.uniswap.org/%23/tokens/${tokenInfo.tokenSymbol}%20via%20@uniswap`,
|
||||
'newwindow',
|
||||
`left=${positionX}, top=${positionY}, width=${TWITTER_WIDTH}, height=${TWITTER_HEIGHT}`
|
||||
)
|
||||
}
|
||||
const copyLink = () => {
|
||||
navigator.clipboard.writeText(window.location.href).then(
|
||||
function handleClipboardWriteSuccess() {
|
||||
setShowCopied(true)
|
||||
toggleShare()
|
||||
setTimeout(() => setShowCopied(false), 3000)
|
||||
},
|
||||
function error() {
|
||||
console.error('Clipboard copy failed.')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ShareButtonDisplay ref={node}>
|
||||
<Share size={18} onClick={toggleShare} aria-label={`ShareOptions`} />
|
||||
{open && (
|
||||
<ShareActions>
|
||||
<ShareAction onClick={copyLink}>
|
||||
<Link color={theme.textSecondary} size={18} />
|
||||
Copy link
|
||||
</ShareAction>
|
||||
|
||||
<ShareAction onClick={shareTweet}>
|
||||
<Twitter color={theme.textSecondary} size={18} />
|
||||
Share to Twitter
|
||||
</ShareAction>
|
||||
</ShareActions>
|
||||
)}
|
||||
</ShareButtonDisplay>
|
||||
<LinkCopied show={showCopied}>
|
||||
<Check color={theme.accentSuccess} />
|
||||
Link Copied
|
||||
</LinkCopied>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
import { FeatureFlag, useUpdateFlag } from 'featureFlags'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
|
||||
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
|
||||
import { Phase1Variant, usePhase1Flag } from 'featureFlags/flags/phase1'
|
||||
import { ReactNode } from 'react'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens'
|
||||
import { TokenSafetyVariant, useTokenSafetyFlag } from 'featureFlags/flags/tokenSafety'
|
||||
import { useAtomValue } from 'jotai/utils'
|
||||
import { ReactNode, useState } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
import { useModalIsOpen, useToggleFeatureFlags } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
@@ -11,7 +15,7 @@ const StyledModal = styled.div`
|
||||
position: fixed;
|
||||
display: flex;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
top: 50vh;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 400px;
|
||||
height: fit-content;
|
||||
@@ -40,17 +44,71 @@ const Row = styled.div`
|
||||
|
||||
const CloseButton = styled.button`
|
||||
cursor: pointer;
|
||||
background: ${({ theme }) => theme.none};
|
||||
background: 'transparent';
|
||||
border: none;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
`
|
||||
|
||||
const Header = styled(Row)`
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
font-size: 16px;
|
||||
border-bottom: 1px solid ${({ theme }) => theme.backgroundOutline};
|
||||
margin-bottom: 8px;
|
||||
`
|
||||
const FlagName = styled.span`
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
padding-left: 8px;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
`
|
||||
const FlagGroupName = styled.span`
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
font-weight: 600;
|
||||
`
|
||||
const FlagDescription = styled.span`
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: ${({ theme }) => theme.textSecondary};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`
|
||||
const FlagVariantSelection = styled.select`
|
||||
border-radius: 12px;
|
||||
padding: 8px;
|
||||
background: ${({ theme }) => theme.backgroundInteractive};
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
cursor: pointer;
|
||||
|
||||
:hover {
|
||||
background: ${({ theme }) => theme.backgroundOutline};
|
||||
}
|
||||
`
|
||||
|
||||
const FlagInfo = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 8px;
|
||||
`
|
||||
|
||||
const SaveButton = styled.button`
|
||||
border-radius: 12px;
|
||||
padding: 8px;
|
||||
background: ${({ theme }) => theme.backgroundInteractive};
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
cursor: pointer;
|
||||
|
||||
:hover {
|
||||
background: ${({ theme }) => theme.backgroundOutline};
|
||||
}
|
||||
`
|
||||
|
||||
function Variant({ option }: { option: string }) {
|
||||
return <option value={option}>{option}</option>
|
||||
@@ -68,21 +126,27 @@ function FeatureFlagOption({
|
||||
label: string
|
||||
}) {
|
||||
const updateFlag = useUpdateFlag()
|
||||
const [count, setCount] = useState(0)
|
||||
const featureFlags = useAtomValue(featureFlagSettings)
|
||||
|
||||
return (
|
||||
<Row key={featureFlag}>
|
||||
{featureFlag}: {label}
|
||||
<select
|
||||
<FlagInfo>
|
||||
<FlagName>{featureFlag}</FlagName>
|
||||
<FlagDescription>{label}</FlagDescription>
|
||||
</FlagInfo>
|
||||
<FlagVariantSelection
|
||||
id={featureFlag}
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
updateFlag(featureFlag, e.target.value)
|
||||
window.location.reload()
|
||||
setCount(count + 1)
|
||||
}}
|
||||
value={featureFlags[featureFlag]}
|
||||
>
|
||||
{variants.map((variant) => (
|
||||
<Variant key={variant} option={variant} />
|
||||
))}
|
||||
</select>
|
||||
</FlagVariantSelection>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
@@ -99,19 +163,39 @@ export default function FeatureFlagModal() {
|
||||
<X size={24} />
|
||||
</CloseButton>
|
||||
</Header>
|
||||
|
||||
<FeatureFlagOption
|
||||
variants={Object.values(Phase0Variant)}
|
||||
value={usePhase0Flag()}
|
||||
featureFlag={FeatureFlag.phase0}
|
||||
label="All Phase 0 changes (redesign, explore, header)."
|
||||
/>
|
||||
<FlagGroupName>Phase 1</FlagGroupName>
|
||||
<FeatureFlagOption
|
||||
variants={Object.values(Phase1Variant)}
|
||||
value={usePhase1Flag()}
|
||||
featureFlag={FeatureFlag.phase1}
|
||||
label="All Phase 1 changes (nft features)."
|
||||
/>
|
||||
<FlagGroupName>Phase 0</FlagGroupName>
|
||||
<FeatureFlagOption
|
||||
variants={Object.values(RedesignVariant)}
|
||||
value={useRedesignFlag()}
|
||||
featureFlag={FeatureFlag.redesign}
|
||||
label="Redesign"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variants={Object.values(NavBarVariant)}
|
||||
value={useNavBarFlag()}
|
||||
featureFlag={FeatureFlag.navBar}
|
||||
label="NavBar"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variants={Object.values(TokensVariant)}
|
||||
value={useTokensFlag()}
|
||||
featureFlag={FeatureFlag.tokens}
|
||||
label="Tokens"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variants={Object.values(TokenSafetyVariant)}
|
||||
value={useTokenSafetyFlag()}
|
||||
featureFlag={FeatureFlag.tokenSafety}
|
||||
label="Token Safety"
|
||||
/>
|
||||
<SaveButton onClick={() => window.location.reload()}>Save Settings</SaveButton>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { getConnection } from 'connection/utils'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { CHAIN_IDS_TO_NAMES, SupportedChainId } from 'constants/chains'
|
||||
import useParsedQueryString from 'hooks/useParsedQueryString'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import useSelectChain from 'hooks/useSelectChain'
|
||||
import useSyncChainQuery from 'hooks/useSyncChainQuery'
|
||||
import { darken } from 'polished'
|
||||
import { ParsedQs } from 'qs'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useRef } from 'react'
|
||||
import { AlertTriangle, ArrowDownCircle, ChevronDown } from 'react-feather'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { useCloseModal, useModalIsOpen, useOpenModal, useToggleModal } from 'state/application/hooks'
|
||||
import { addPopup, ApplicationModal } from 'state/application/reducer'
|
||||
import { updateConnectionError } from 'state/connection/reducer'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||
import { replaceURLParam } from 'utils/routes'
|
||||
import { isChainAllowed, switchChain } from 'utils/switchChain'
|
||||
import { isChainAllowed } from 'utils/switchChain'
|
||||
import { isMobile } from 'utils/userAgent'
|
||||
|
||||
const ActiveRowLinkList = styled.div`
|
||||
@@ -278,24 +272,6 @@ function Row({
|
||||
return rowContent
|
||||
}
|
||||
|
||||
const getParsedChainId = (parsedQs?: ParsedQs) => {
|
||||
const chain = parsedQs?.chain
|
||||
if (!chain || typeof chain !== 'string') return
|
||||
|
||||
return getChainIdFromName(chain)
|
||||
}
|
||||
|
||||
const getChainIdFromName = (name: string) => {
|
||||
const entry = Object.entries(CHAIN_IDS_TO_NAMES).find(([_, n]) => n === name)
|
||||
const chainId = entry?.[0]
|
||||
return chainId ? parseInt(chainId) : undefined
|
||||
}
|
||||
|
||||
const getChainNameFromId = (id: string | number) => {
|
||||
// casting here may not be right but fine to return undefined if it's not a supported chain ID
|
||||
return CHAIN_IDS_TO_NAMES[id as SupportedChainId] || ''
|
||||
}
|
||||
|
||||
const NETWORK_SELECTOR_CHAINS = [
|
||||
SupportedChainId.MAINNET,
|
||||
SupportedChainId.POLYGON,
|
||||
@@ -305,24 +281,7 @@ const NETWORK_SELECTOR_CHAINS = [
|
||||
]
|
||||
|
||||
export default function NetworkSelector() {
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const { chainId, provider, connector, isActive } = useWeb3React()
|
||||
const [previousChainId, setPreviousChainId] = useState<number | undefined>(undefined)
|
||||
|
||||
// Can't use `usePrevious` because `chainId` can be undefined while activating.
|
||||
useEffect(() => {
|
||||
if (chainId && chainId !== previousChainId) {
|
||||
setPreviousChainId(chainId)
|
||||
}
|
||||
}, [chainId, previousChainId])
|
||||
|
||||
const parsedQs = useParsedQueryString()
|
||||
const urlChainId = getParsedChainId(parsedQs)
|
||||
const previousUrlChainId = usePrevious(urlChainId)
|
||||
|
||||
const navigate = useNavigate()
|
||||
const { search } = useLocation()
|
||||
const { chainId, provider, connector } = useWeb3React()
|
||||
|
||||
const node = useRef<HTMLDivElement>(null)
|
||||
const isOpen = useModalIsOpen(ApplicationModal.NETWORK_SELECTOR)
|
||||
@@ -332,62 +291,8 @@ export default function NetworkSelector() {
|
||||
|
||||
const info = getChainInfo(chainId)
|
||||
|
||||
const replaceURLChainParam = useCallback(() => {
|
||||
if (chainId) {
|
||||
navigate({ search: replaceURLParam(search, 'chain', getChainNameFromId(chainId)) }, { replace: true })
|
||||
}
|
||||
}, [chainId, search, navigate])
|
||||
|
||||
const onSelectChain = useCallback(
|
||||
async (targetChain: SupportedChainId, skipClose?: boolean) => {
|
||||
if (!connector) return
|
||||
|
||||
const connectionType = getConnection(connector).type
|
||||
|
||||
try {
|
||||
dispatch(updateConnectionError({ connectionType, error: undefined }))
|
||||
await switchChain(connector, targetChain)
|
||||
} catch (error) {
|
||||
console.error('Failed to switch networks', error)
|
||||
|
||||
dispatch(updateConnectionError({ connectionType, error: error.message }))
|
||||
dispatch(addPopup({ content: { failedSwitchNetwork: targetChain }, key: `failed-network-switch` }))
|
||||
|
||||
// If we activate a chain and it fails, reset the query param to the current chainId
|
||||
replaceURLChainParam()
|
||||
}
|
||||
|
||||
if (!skipClose) {
|
||||
closeModal()
|
||||
}
|
||||
},
|
||||
[connector, closeModal, dispatch, replaceURLChainParam]
|
||||
)
|
||||
|
||||
// If there is no chain query param, set it to the current chain
|
||||
useEffect(() => {
|
||||
const chainQueryUnpopulated = !urlChainId
|
||||
if (chainQueryUnpopulated && chainId) {
|
||||
replaceURLChainParam()
|
||||
}
|
||||
}, [chainId, urlChainId, replaceURLChainParam])
|
||||
|
||||
// If the chain changed but the query param is stale, update to the current chain
|
||||
useEffect(() => {
|
||||
const chainChanged = chainId !== previousChainId
|
||||
const chainQueryStale = urlChainId !== chainId
|
||||
if (chainChanged && chainQueryStale) {
|
||||
replaceURLChainParam()
|
||||
}
|
||||
}, [chainId, previousChainId, replaceURLChainParam, urlChainId])
|
||||
|
||||
// If the query param changed, and the chain didn't change, then activate the new chain
|
||||
useEffect(() => {
|
||||
const chainQueryManuallyUpdated = urlChainId && urlChainId !== previousUrlChainId
|
||||
if (chainQueryManuallyUpdated && isActive) {
|
||||
onSelectChain(urlChainId, true)
|
||||
}
|
||||
}, [onSelectChain, urlChainId, previousUrlChainId, isActive])
|
||||
const selectChain = useSelectChain()
|
||||
useSyncChainQuery()
|
||||
|
||||
if (!chainId || !provider) {
|
||||
return null
|
||||
@@ -425,7 +330,14 @@ export default function NetworkSelector() {
|
||||
</FlyoutHeader>
|
||||
{NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) =>
|
||||
isChainAllowed(connector, chainId) ? (
|
||||
<Row onSelectChain={onSelectChain} targetChain={chainId} key={chainId} />
|
||||
<Row
|
||||
onSelectChain={async (targetChainId: SupportedChainId) => {
|
||||
await selectChain(targetChainId)
|
||||
closeModal()
|
||||
}}
|
||||
targetChain={chainId}
|
||||
key={chainId}
|
||||
/>
|
||||
) : null
|
||||
)}
|
||||
</FlyoutMenuContents>
|
||||
|
||||
@@ -5,12 +5,11 @@ import { getChainInfo } from 'constants/chainInfo'
|
||||
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
||||
import useGasPrice from 'hooks/useGasPrice'
|
||||
import useMachineTimeMs from 'hooks/useMachineTime'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import JSBI from 'jsbi'
|
||||
import useBlockNumber from 'lib/hooks/useBlockNumber'
|
||||
import ms from 'ms.macro'
|
||||
import { useEffect, useState } from 'react'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import styled, { keyframes, useTheme } from 'styled-components/macro'
|
||||
import { ExternalLink, ThemedText } from 'theme'
|
||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ import useScrollPosition from '@react-hook/window-scroll'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { getChainInfoOrDefault } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens'
|
||||
import { darken } from 'polished'
|
||||
import { NavLink, useLocation } from 'react-router-dom'
|
||||
import { Text } from 'rebass'
|
||||
@@ -13,7 +12,7 @@ import { useUserHasAvailableClaim } from 'state/claim/hooks'
|
||||
import { useNativeCurrencyBalances } from 'state/connection/hooks'
|
||||
import { useUserHasSubmittedClaim } from 'state/transactions/hooks'
|
||||
import { useDarkModeManager } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
@@ -245,7 +244,7 @@ const StyledExternalLink = styled(ExternalLink)`
|
||||
`
|
||||
|
||||
export default function Header() {
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const tokensFlag = useTokensFlag()
|
||||
|
||||
const { account, chainId } = useWeb3React()
|
||||
|
||||
@@ -292,9 +291,9 @@ export default function Header() {
|
||||
<StyledNavLink id={`swap-nav-link`} to={'/swap'}>
|
||||
<Trans>Swap</Trans>
|
||||
</StyledNavLink>
|
||||
{phase0Flag === Phase0Variant.Enabled && (
|
||||
<StyledNavLink id={`explore-nav-link`} to={'/explore'}>
|
||||
<Trans>Explore</Trans>
|
||||
{tokensFlag === TokensVariant.Enabled && (
|
||||
<StyledNavLink id={`tokens-nav-link`} to={'/tokens'}>
|
||||
<Trans>Tokens</Trans>
|
||||
</StyledNavLink>
|
||||
)}
|
||||
<StyledNavLink
|
||||
|
||||
@@ -14,7 +14,7 @@ export function useDensityChartData({
|
||||
currencyB: Currency | undefined
|
||||
feeAmount: FeeAmount | undefined
|
||||
}) {
|
||||
const { isLoading, isUninitialized, isError, error, data } = usePoolActiveLiquidity(currencyA, currencyB, feeAmount)
|
||||
const { isLoading, error, data } = usePoolActiveLiquidity(currencyA, currencyB, feeAmount)
|
||||
|
||||
const formatData = useCallback(() => {
|
||||
if (!data?.length) {
|
||||
@@ -42,10 +42,8 @@ export function useDensityChartData({
|
||||
return useMemo(() => {
|
||||
return {
|
||||
isLoading,
|
||||
isUninitialized,
|
||||
isError,
|
||||
error,
|
||||
formattedData: !isLoading && !isUninitialized ? formatData() : undefined,
|
||||
formattedData: !isLoading ? formatData() : undefined,
|
||||
}
|
||||
}, [isLoading, isUninitialized, isError, error, formatData])
|
||||
}, [isLoading, error, formatData])
|
||||
}
|
||||
|
||||
@@ -6,13 +6,12 @@ import { AutoColumn, ColumnCenter } from 'components/Column'
|
||||
import Loader from 'components/Loader'
|
||||
import { format } from 'd3'
|
||||
import { useColor } from 'hooks/useColor'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { saturate } from 'polished'
|
||||
import React, { ReactNode, useCallback, useMemo } from 'react'
|
||||
import { BarChart2, CloudOff, Inbox } from 'react-feather'
|
||||
import { batch } from 'react-redux'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
import { Chart } from './Chart'
|
||||
@@ -96,7 +95,7 @@ export default function LiquidityChartRangeInput({
|
||||
|
||||
const isSorted = currencyA && currencyB && currencyA?.wrapped.sortsBefore(currencyB?.wrapped)
|
||||
|
||||
const { isLoading, isUninitialized, isError, error, formattedData } = useDensityChartData({
|
||||
const { isLoading, error, formattedData } = useDensityChartData({
|
||||
currencyA,
|
||||
currencyB,
|
||||
feeAmount,
|
||||
@@ -157,10 +156,12 @@ export default function LiquidityChartRangeInput({
|
||||
[isSorted, price, ticksAtLimit]
|
||||
)
|
||||
|
||||
if (isError) {
|
||||
if (error) {
|
||||
sendEvent('exception', { description: error.toString(), fatal: false })
|
||||
}
|
||||
|
||||
const isUninitialized = !currencyA || !currencyB || (formattedData === undefined && !isLoading)
|
||||
|
||||
return (
|
||||
<AutoColumn gap="md" style={{ minHeight: '200px' }}>
|
||||
{isUninitialized ? (
|
||||
@@ -170,7 +171,7 @@ export default function LiquidityChartRangeInput({
|
||||
/>
|
||||
) : isLoading ? (
|
||||
<InfoBox icon={<Loader size="40px" stroke={theme.deprecated_text4} />} />
|
||||
) : isError ? (
|
||||
) : error ? (
|
||||
<InfoBox
|
||||
message={<Trans>Liquidity data not available.</Trans>}
|
||||
icon={<CloudOff size={56} stroke={theme.deprecated_text4} />}
|
||||
|
||||
@@ -9,12 +9,13 @@ const rotate = keyframes`
|
||||
}
|
||||
`
|
||||
|
||||
const StyledSVG = styled.svg<{ size: string; stroke?: string }>`
|
||||
const StyledSVG = styled.svg<{ size: string; stroke?: string; redesignFlag?: boolean }>`
|
||||
animation: 2s ${rotate} linear infinite;
|
||||
height: ${({ size }) => size};
|
||||
width: ${({ size }) => size};
|
||||
path {
|
||||
stroke: ${({ stroke, theme }) => stroke ?? theme.deprecated_primary1};
|
||||
stroke: ${({ stroke, redesignFlag, theme }) =>
|
||||
redesignFlag ? theme.accentActive : stroke ?? theme.deprecated_primary1};
|
||||
}
|
||||
`
|
||||
|
||||
@@ -25,17 +26,29 @@ const StyledSVG = styled.svg<{ size: string; stroke?: string }>`
|
||||
export default function Loader({
|
||||
size = '16px',
|
||||
stroke,
|
||||
strokeWidth,
|
||||
redesignFlag,
|
||||
...rest
|
||||
}: {
|
||||
size?: string
|
||||
stroke?: string
|
||||
strokeWidth?: number
|
||||
redesignFlag?: boolean
|
||||
[k: string]: any
|
||||
}) {
|
||||
return (
|
||||
<StyledSVG viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" size={size} stroke={stroke} {...rest}>
|
||||
<StyledSVG
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
size={size}
|
||||
stroke={stroke}
|
||||
redesignFlag={redesignFlag}
|
||||
{...rest}
|
||||
>
|
||||
<path
|
||||
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 9.27455 20.9097 6.80375 19.1414 5"
|
||||
strokeWidth="2.5"
|
||||
strokeWidth={strokeWidth ?? '2.5'}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { Slash } from 'react-feather'
|
||||
import { ImageProps } from 'rebass'
|
||||
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { useTheme } from 'styled-components/macro'
|
||||
|
||||
const BAD_SRCS: { [tokenAddress: string]: true } = {}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
ChevronLeft,
|
||||
Coffee,
|
||||
FileText,
|
||||
Flag,
|
||||
Globe,
|
||||
HelpCircle,
|
||||
Info,
|
||||
@@ -291,6 +292,11 @@ export default function Menu() {
|
||||
</div>
|
||||
<FileText opacity={0.6} size={16} />
|
||||
</ToggleMenuItem>
|
||||
{(isDevelopmentEnv() || isStagingEnv()) && (
|
||||
<ToggleMenuItem onClick={openFeatureFlagsModal}>
|
||||
Feature Flags <Flag opacity={0.6} size={16} />
|
||||
</ToggleMenuItem>
|
||||
)}
|
||||
{showUNIClaimOption && (
|
||||
<UNIbutton
|
||||
onClick={openClaimModal}
|
||||
@@ -302,9 +308,6 @@ export default function Menu() {
|
||||
<Trans>Claim UNI</Trans>
|
||||
</UNIbutton>
|
||||
)}
|
||||
{(isDevelopmentEnv() || isStagingEnv()) && (
|
||||
<ToggleMenuItem onClick={openFeatureFlagsModal}>Feature Flags</ToggleMenuItem>
|
||||
)}
|
||||
</MenuFlyout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { isMobile } from '../../utils/userAgent'
|
||||
|
||||
const AnimatedDialogOverlay = animated(DialogOverlay)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const StyledDialogOverlay = styled(AnimatedDialogOverlay)`
|
||||
const StyledDialogOverlay = styled(AnimatedDialogOverlay)<{ redesignFlag?: boolean }>`
|
||||
&[data-reach-dialog-overlay] {
|
||||
z-index: 2;
|
||||
background-color: transparent;
|
||||
@@ -19,7 +19,7 @@ const StyledDialogOverlay = styled(AnimatedDialogOverlay)`
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: ${({ theme }) => theme.deprecated_modalBG};
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundScrim : theme.deprecated_modalBG)};
|
||||
}
|
||||
`
|
||||
|
||||
@@ -84,6 +84,7 @@ interface ModalProps {
|
||||
maxHeight?: number
|
||||
initialFocusRef?: React.RefObject<any>
|
||||
children?: React.ReactNode
|
||||
redesignFlag?: boolean
|
||||
}
|
||||
|
||||
export default function Modal({
|
||||
@@ -93,6 +94,7 @@ export default function Modal({
|
||||
maxHeight = 90,
|
||||
initialFocusRef,
|
||||
children,
|
||||
redesignFlag,
|
||||
}: ModalProps) {
|
||||
const fadeTransition = useTransition(isOpen, null, {
|
||||
config: { duration: 200 },
|
||||
@@ -124,6 +126,7 @@ export default function Modal({
|
||||
onDismiss={onDismiss}
|
||||
initialFocusRef={initialFocusRef}
|
||||
unstable_lockFocusAcrossFrames={false}
|
||||
redesignFlag={redesignFlag}
|
||||
>
|
||||
<StyledDialogContent
|
||||
{...(isMobile
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { useContext } from 'react'
|
||||
import { ArrowUpCircle } from 'react-feather'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import { CloseIcon, CustomLightSpinner, ThemedText } from '../../theme'
|
||||
@@ -49,7 +48,7 @@ export function SubmittedView({
|
||||
onDismiss: () => void
|
||||
hash: string | undefined
|
||||
}) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
const { chainId } = useWeb3React()
|
||||
|
||||
return (
|
||||
|
||||
49
src/components/NavBar/ChainSwitcher.css.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
import { sprinkles } from '../../nft/css/sprinkles.css'
|
||||
|
||||
export const ChainSwitcher = style([
|
||||
sprinkles({
|
||||
background: 'lightGrayContainer',
|
||||
borderRadius: '8',
|
||||
paddingY: '8',
|
||||
paddingX: '12',
|
||||
cursor: 'pointer',
|
||||
border: 'none',
|
||||
}),
|
||||
])
|
||||
|
||||
export const ChainSwitcherRow = style([
|
||||
sprinkles({
|
||||
border: 'none',
|
||||
color: 'blackBlue',
|
||||
justifyContent: 'space-between',
|
||||
paddingX: '16',
|
||||
paddingY: '12',
|
||||
cursor: 'pointer',
|
||||
}),
|
||||
{
|
||||
lineHeight: '24px',
|
||||
width: '308px',
|
||||
},
|
||||
])
|
||||
|
||||
export const Image = style([
|
||||
sprinkles({
|
||||
width: '28',
|
||||
height: '28',
|
||||
}),
|
||||
])
|
||||
|
||||
export const Icon = style([
|
||||
Image,
|
||||
sprinkles({
|
||||
marginRight: '12',
|
||||
}),
|
||||
])
|
||||
|
||||
export const Indicator = style([
|
||||
sprinkles({
|
||||
marginLeft: '8',
|
||||
}),
|
||||
])
|
||||
108
src/components/NavBar/ChainSwitcher.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import useSelectChain from 'hooks/useSelectChain'
|
||||
import useSyncChainQuery from 'hooks/useSyncChainQuery'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import { NewChevronDownIcon, NewChevronUpIcon } from 'nft/components/icons'
|
||||
import { CheckMarkIcon } from 'nft/components/icons'
|
||||
import { subhead } from 'nft/css/common.css'
|
||||
import { ReactNode, useReducer, useRef } from 'react'
|
||||
import { isChainAllowed } from 'utils/switchChain'
|
||||
|
||||
import * as styles from './ChainSwitcher.css'
|
||||
import { NavDropdown } from './NavDropdown'
|
||||
|
||||
const ChainRow = ({
|
||||
targetChain,
|
||||
onSelectChain,
|
||||
}: {
|
||||
targetChain: SupportedChainId
|
||||
onSelectChain: (targetChain: number) => void
|
||||
}) => {
|
||||
const { chainId } = useWeb3React()
|
||||
const active = chainId === targetChain
|
||||
const { label, logoUrl } = getChainInfo(targetChain)
|
||||
|
||||
return (
|
||||
<Row
|
||||
as="button"
|
||||
background={active ? 'lightGrayContainer' : 'none'}
|
||||
className={`${styles.ChainSwitcherRow} ${subhead}`}
|
||||
onClick={() => onSelectChain(targetChain)}
|
||||
>
|
||||
<ChainDetails>
|
||||
<img src={logoUrl} alt={label} className={styles.Icon} />
|
||||
{label}
|
||||
</ChainDetails>
|
||||
{active && <CheckMarkIcon width={20} height={20} />}
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
const ChainDetails = ({ children }: { children: ReactNode }) => <Row>{children}</Row>
|
||||
|
||||
const NETWORK_SELECTOR_CHAINS = [
|
||||
SupportedChainId.MAINNET,
|
||||
SupportedChainId.POLYGON,
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.CELO,
|
||||
]
|
||||
|
||||
interface ChainSwitcherProps {
|
||||
isMobile?: boolean
|
||||
}
|
||||
|
||||
export const ChainSwitcher = ({ isMobile }: ChainSwitcherProps) => {
|
||||
const { chainId, connector } = useWeb3React()
|
||||
const [isOpen, toggleOpen] = useReducer((s) => !s, false)
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
useOnClickOutside(ref, isOpen ? toggleOpen : undefined)
|
||||
|
||||
const info = chainId ? getChainInfo(chainId) : undefined
|
||||
|
||||
const selectChain = useSelectChain()
|
||||
useSyncChainQuery()
|
||||
|
||||
if (!chainId || !info) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Box position="relative" ref={ref}>
|
||||
<Row as="button" gap="8" className={styles.ChainSwitcher} onClick={toggleOpen}>
|
||||
<img src={info.logoUrl} alt={info.label} className={styles.Image} />
|
||||
<Box as="span" className={subhead} color="explicitWhite" style={{ lineHeight: '20px' }}>
|
||||
{info.label}
|
||||
</Box>
|
||||
{isOpen ? (
|
||||
<NewChevronUpIcon width={16} height={16} color="darkGray" />
|
||||
) : (
|
||||
<NewChevronDownIcon width={16} height={16} color="darkGray" />
|
||||
)}
|
||||
</Row>
|
||||
{isOpen && (
|
||||
<NavDropdown top={60} leftAligned={isMobile}>
|
||||
<Column gap="4">
|
||||
{NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) =>
|
||||
isChainAllowed(connector, chainId) ? (
|
||||
<ChainRow
|
||||
onSelectChain={async (targetChainId: SupportedChainId) => {
|
||||
await selectChain(targetChainId)
|
||||
toggleOpen()
|
||||
}}
|
||||
targetChain={chainId}
|
||||
key={chainId}
|
||||
/>
|
||||
) : null
|
||||
)}
|
||||
</Column>
|
||||
</NavDropdown>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
50
src/components/NavBar/MenuDropdown.css.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
import { sprinkles, themeVars } from '../../nft/css/sprinkles.css'
|
||||
|
||||
export const MenuRow = style([
|
||||
sprinkles({
|
||||
color: 'blackBlue',
|
||||
paddingY: '12',
|
||||
width: 'max',
|
||||
marginRight: '52',
|
||||
}),
|
||||
{
|
||||
lineHeight: '24px',
|
||||
textDecoration: 'none',
|
||||
},
|
||||
])
|
||||
|
||||
export const PrimaryText = style([
|
||||
{
|
||||
lineHeight: '24px',
|
||||
},
|
||||
])
|
||||
|
||||
export const SecondaryText = style([
|
||||
sprinkles({
|
||||
paddingY: '8',
|
||||
color: 'darkGray',
|
||||
}),
|
||||
{
|
||||
lineHeight: '20px',
|
||||
},
|
||||
])
|
||||
|
||||
export const Separator = style([
|
||||
sprinkles({
|
||||
height: '0',
|
||||
}),
|
||||
{
|
||||
borderTop: 'solid',
|
||||
borderColor: themeVars.colors.medGray,
|
||||
borderWidth: '1px',
|
||||
},
|
||||
])
|
||||
|
||||
export const IconRow = style([
|
||||
sprinkles({
|
||||
paddingX: '16',
|
||||
paddingY: '8',
|
||||
}),
|
||||
])
|
||||
178
src/components/NavBar/MenuDropdown.tsx
Normal file
@@ -0,0 +1,178 @@
|
||||
import FeatureFlagModal from 'components/FeatureFlagModal/FeatureFlagModal'
|
||||
import { PrivacyPolicyModal } from 'components/PrivacyPolicy'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import {
|
||||
BarChartIcon,
|
||||
DiscordIconMenu,
|
||||
EllipsisIcon,
|
||||
GithubIconMenu,
|
||||
GovernanceIcon,
|
||||
TwitterIconMenu,
|
||||
} from 'nft/components/icons'
|
||||
import { body, bodySmall } from 'nft/css/common.css'
|
||||
import { themeVars } from 'nft/css/sprinkles.css'
|
||||
import { ReactNode, useReducer, useRef } from 'react'
|
||||
import { NavLink, NavLinkProps } from 'react-router-dom'
|
||||
import { isDevelopmentEnv, isStagingEnv } from 'utils/env'
|
||||
|
||||
import { useToggleModal } from '../../state/application/hooks'
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import * as styles from './MenuDropdown.css'
|
||||
import { NavDropdown } from './NavDropdown'
|
||||
import { NavIcon } from './NavIcon'
|
||||
|
||||
const PrimaryMenuRow = ({
|
||||
to,
|
||||
href,
|
||||
close,
|
||||
children,
|
||||
}: {
|
||||
to?: NavLinkProps['to']
|
||||
href?: string
|
||||
close?: () => void
|
||||
children: ReactNode
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{to ? (
|
||||
<NavLink to={to} className={styles.MenuRow}>
|
||||
<Row onClick={close}>{children}</Row>
|
||||
</NavLink>
|
||||
) : (
|
||||
<Row as="a" href={href} target={'_blank'} rel={'noopener noreferrer'} className={styles.MenuRow}>
|
||||
{children}
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const PrimaryMenuRowText = ({ children }: { children: ReactNode }) => {
|
||||
return <Box className={`${styles.PrimaryText} ${body}`}>{children}</Box>
|
||||
}
|
||||
|
||||
PrimaryMenuRow.Text = PrimaryMenuRowText
|
||||
|
||||
const SecondaryLinkedText = ({
|
||||
href,
|
||||
onClick,
|
||||
children,
|
||||
}: {
|
||||
href?: string
|
||||
onClick?: () => void
|
||||
children: ReactNode
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
as={href ? 'a' : 'div'}
|
||||
href={href ?? undefined}
|
||||
target={href ? '_blank' : undefined}
|
||||
rel={href ? 'noopener noreferrer' : undefined}
|
||||
className={`${styles.SecondaryText} ${bodySmall}`}
|
||||
onClick={onClick}
|
||||
cursor="pointer"
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const Separator = () => {
|
||||
return <Box className={styles.Separator} />
|
||||
}
|
||||
|
||||
const IconRow = ({ children }: { children: ReactNode }) => {
|
||||
return <Row className={styles.IconRow}>{children}</Row>
|
||||
}
|
||||
|
||||
const Icon = ({ href, children }: { href?: string; children: ReactNode }) => {
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
as={href ? 'a' : 'div'}
|
||||
href={href ?? undefined}
|
||||
target={href ? '_blank' : undefined}
|
||||
rel={href ? 'noopener noreferrer' : undefined}
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
color="blackBlue"
|
||||
background="none"
|
||||
border="none"
|
||||
justifyContent="center"
|
||||
textAlign="center"
|
||||
marginRight="12"
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const MenuDropdown = () => {
|
||||
const [isOpen, toggleOpen] = useReducer((s) => !s, false)
|
||||
const togglePrivacyPolicy = useToggleModal(ApplicationModal.PRIVACY_POLICY)
|
||||
const openFeatureFlagsModal = useToggleModal(ApplicationModal.FEATURE_FLAGS)
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
useOnClickOutside(ref, isOpen ? toggleOpen : undefined)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box position="relative" ref={ref}>
|
||||
<NavIcon onClick={toggleOpen}>
|
||||
<EllipsisIcon width={28} height={28} />
|
||||
</NavIcon>
|
||||
|
||||
{isOpen && (
|
||||
<NavDropdown top={60}>
|
||||
<Column gap="12">
|
||||
<Column paddingX="16" gap="4">
|
||||
<PrimaryMenuRow to="/vote" close={toggleOpen}>
|
||||
<Icon>
|
||||
<GovernanceIcon width={24} height={24} />
|
||||
</Icon>
|
||||
<PrimaryMenuRow.Text>Vote in governance</PrimaryMenuRow.Text>
|
||||
</PrimaryMenuRow>
|
||||
<PrimaryMenuRow href="https://info.uniswap.org/#/">
|
||||
<Icon>
|
||||
<BarChartIcon width={24} height={24} />
|
||||
</Icon>
|
||||
<PrimaryMenuRow.Text>View token analytics ↗</PrimaryMenuRow.Text>
|
||||
</PrimaryMenuRow>
|
||||
</Column>
|
||||
<Separator />
|
||||
<Column paddingX="16" gap="4">
|
||||
<SecondaryLinkedText href="https://help.uniswap.org/en/">Help center ↗</SecondaryLinkedText>
|
||||
<SecondaryLinkedText href="https://docs.uniswap.org/">Documentation ↗</SecondaryLinkedText>
|
||||
<SecondaryLinkedText
|
||||
onClick={() => {
|
||||
toggleOpen()
|
||||
togglePrivacyPolicy()
|
||||
}}
|
||||
>{`Legal & Privacy`}</SecondaryLinkedText>
|
||||
{(isDevelopmentEnv() || isStagingEnv()) && (
|
||||
<SecondaryLinkedText onClick={openFeatureFlagsModal}>{`Feature Flags`}</SecondaryLinkedText>
|
||||
)}
|
||||
</Column>
|
||||
<IconRow>
|
||||
<Icon href="https://discord.com/invite/FCfyBSbCU5">
|
||||
<DiscordIconMenu width={24} height={24} color={themeVars.colors.darkGray} />
|
||||
</Icon>
|
||||
<Icon href="https://twitter.com/Uniswap">
|
||||
<TwitterIconMenu width={24} height={24} color={themeVars.colors.darkGray} />
|
||||
</Icon>
|
||||
<Icon href="https://github.com/Uniswap">
|
||||
<GithubIconMenu width={24} height={24} color={themeVars.colors.darkGray} />
|
||||
</Icon>
|
||||
</IconRow>
|
||||
</Column>
|
||||
</NavDropdown>
|
||||
)}
|
||||
</Box>
|
||||
<PrivacyPolicyModal />
|
||||
<FeatureFlagModal />
|
||||
</>
|
||||
)
|
||||
}
|
||||
121
src/components/NavBar/MobileSidebar.css.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
import { subhead } from 'nft/css/common.css'
|
||||
|
||||
import { sprinkles } from '../../nft/css/sprinkles.css'
|
||||
|
||||
export const sidebar = style([
|
||||
sprinkles({
|
||||
display: 'flex',
|
||||
position: 'fixed',
|
||||
background: 'white',
|
||||
height: 'full',
|
||||
top: '0',
|
||||
left: '0',
|
||||
right: '0',
|
||||
bottom: '0',
|
||||
paddingBottom: '16',
|
||||
justifyContent: 'space-between',
|
||||
}),
|
||||
{
|
||||
zIndex: 20,
|
||||
},
|
||||
])
|
||||
|
||||
export const icon = style([
|
||||
sprinkles({
|
||||
width: '32',
|
||||
height: '32',
|
||||
}),
|
||||
])
|
||||
|
||||
export const iconContainer = style([
|
||||
sprinkles({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
color: 'darkGray',
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
justifyContent: 'flex-end',
|
||||
textAlign: 'center',
|
||||
cursor: 'pointer',
|
||||
padding: '6',
|
||||
}),
|
||||
])
|
||||
|
||||
export const linkRow = style([
|
||||
subhead,
|
||||
sprinkles({
|
||||
color: 'blackBlue',
|
||||
width: 'full',
|
||||
paddingLeft: '16',
|
||||
paddingY: '12',
|
||||
cursor: 'pointer',
|
||||
}),
|
||||
{
|
||||
lineHeight: '24px',
|
||||
textDecoration: 'none',
|
||||
},
|
||||
])
|
||||
|
||||
export const activeLinkRow = style([
|
||||
linkRow,
|
||||
sprinkles({
|
||||
background: 'lightGrayButton',
|
||||
}),
|
||||
])
|
||||
|
||||
export const separator = style([
|
||||
sprinkles({
|
||||
height: '0',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'medGray',
|
||||
borderWidth: '1px',
|
||||
marginY: '8',
|
||||
marginX: '16',
|
||||
}),
|
||||
])
|
||||
|
||||
export const extraLinkRow = style([
|
||||
subhead,
|
||||
sprinkles({
|
||||
width: 'full',
|
||||
color: 'blackBlue',
|
||||
paddingY: '12',
|
||||
paddingLeft: '16',
|
||||
cursor: 'pointer',
|
||||
}),
|
||||
{
|
||||
lineHeight: '24px',
|
||||
textDecoration: 'none',
|
||||
},
|
||||
])
|
||||
|
||||
export const bottomExternalLinks = style([
|
||||
sprinkles({
|
||||
gap: '4',
|
||||
paddingX: '4',
|
||||
width: 'max',
|
||||
flexWrap: 'wrap',
|
||||
}),
|
||||
])
|
||||
|
||||
export const bottomJointExternalLinksContainer = style([
|
||||
sprinkles({
|
||||
paddingX: '8',
|
||||
paddingY: '4',
|
||||
color: 'darkGray',
|
||||
fontWeight: 'medium',
|
||||
fontSize: '12',
|
||||
}),
|
||||
{
|
||||
lineHeight: '20px',
|
||||
},
|
||||
])
|
||||
|
||||
export const IconRow = style([
|
||||
sprinkles({
|
||||
gap: '12',
|
||||
width: 'max',
|
||||
}),
|
||||
])
|
||||
233
src/components/NavBar/MobileSidebar.tsx
Normal file
@@ -0,0 +1,233 @@
|
||||
import FeatureFlagModal from 'components/FeatureFlagModal/FeatureFlagModal'
|
||||
import { PrivacyPolicyModal } from 'components/PrivacyPolicy'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Portal } from 'nft/components/common/Portal'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import {
|
||||
BarChartIconMobile,
|
||||
BulletIcon,
|
||||
CloseIcon,
|
||||
DiscordIconMenuMobile,
|
||||
GithubIconMenuMobile,
|
||||
GovernanceIconMobile,
|
||||
HamburgerIcon,
|
||||
TwitterIconMenuMobile,
|
||||
} from 'nft/components/icons'
|
||||
import { themeVars } from 'nft/css/sprinkles.css'
|
||||
import { ReactNode, useReducer } from 'react'
|
||||
import { NavLink, NavLinkProps, useLocation } from 'react-router-dom'
|
||||
import { useToggleModal, useTogglePrivacyPolicy } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import { isDevelopmentEnv, isStagingEnv } from 'utils/env'
|
||||
|
||||
import * as styles from './MobileSidebar.css'
|
||||
import { NavIcon } from './NavIcon'
|
||||
|
||||
interface NavLinkRowProps {
|
||||
href: string
|
||||
id?: NavLinkProps['id']
|
||||
isActive?: boolean
|
||||
close: () => void
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const NavLinkRow = ({ href, id, isActive, close, children }: NavLinkRowProps) => {
|
||||
return (
|
||||
<NavLink to={href} className={isActive ? styles.activeLinkRow : styles.linkRow} id={id} onClick={close}>
|
||||
{children}
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
|
||||
const ExtraLinkRow = ({
|
||||
to,
|
||||
href,
|
||||
close,
|
||||
children,
|
||||
}: {
|
||||
to?: NavLinkProps['to']
|
||||
href?: string
|
||||
close: () => void
|
||||
children: ReactNode
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{to ? (
|
||||
<NavLink to={to} className={styles.extraLinkRow}>
|
||||
<Row gap="12" onClick={close}>
|
||||
{children}
|
||||
</Row>
|
||||
</NavLink>
|
||||
) : (
|
||||
<Row
|
||||
as="a"
|
||||
href={href}
|
||||
target={'_blank'}
|
||||
rel={'noopener noreferrer'}
|
||||
gap="12"
|
||||
onClick={close}
|
||||
className={styles.extraLinkRow}
|
||||
>
|
||||
{children}
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const BottomExternalLink = ({
|
||||
href,
|
||||
onClick,
|
||||
children,
|
||||
}: {
|
||||
href?: string
|
||||
onClick?: () => void
|
||||
children: ReactNode
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
as={href ? 'a' : 'div'}
|
||||
href={href ?? undefined}
|
||||
target={href ? '_blank' : undefined}
|
||||
rel={href ? 'noopener noreferrer' : undefined}
|
||||
className={`${styles.bottomJointExternalLinksContainer}`}
|
||||
onClick={onClick}
|
||||
cursor="pointer"
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const Icon = ({ href, children }: { href?: string; children: ReactNode }) => {
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
as={href ? 'a' : 'div'}
|
||||
href={href ?? undefined}
|
||||
target={href ? '_blank' : undefined}
|
||||
rel={href ? 'noopener noreferrer' : undefined}
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
color="blackBlue"
|
||||
background="none"
|
||||
border="none"
|
||||
justifyContent="center"
|
||||
textAlign="center"
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const IconRow = ({ children }: { children: ReactNode }) => {
|
||||
return <Row className={styles.IconRow}>{children}</Row>
|
||||
}
|
||||
|
||||
const Seperator = () => {
|
||||
return <Box className={styles.separator} />
|
||||
}
|
||||
|
||||
export const MobileSideBar = () => {
|
||||
const [isOpen, toggleOpen] = useReducer((s) => !s, false)
|
||||
const togglePrivacyPolicy = useTogglePrivacyPolicy()
|
||||
const openFeatureFlagsModal = useToggleModal(ApplicationModal.FEATURE_FLAGS)
|
||||
const { pathname } = useLocation()
|
||||
const isPoolActive =
|
||||
pathname.startsWith('/pool') ||
|
||||
pathname.startsWith('/add') ||
|
||||
pathname.startsWith('/remove') ||
|
||||
pathname.startsWith('/increase') ||
|
||||
pathname.startsWith('/find')
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavIcon onClick={toggleOpen}>
|
||||
<HamburgerIcon width={28} height={28} />
|
||||
</NavIcon>
|
||||
{isOpen && (
|
||||
<Portal>
|
||||
<Column className={styles.sidebar}>
|
||||
<Column>
|
||||
<Row justifyContent="flex-end" marginTop="14" marginBottom="20" marginRight="8">
|
||||
<Box as="button" onClick={toggleOpen} className={styles.iconContainer}>
|
||||
<CloseIcon className={styles.icon} />
|
||||
</Box>
|
||||
</Row>
|
||||
<Column gap="4">
|
||||
<NavLinkRow href="/swap" close={toggleOpen} isActive={pathname.startsWith('/swap')}>
|
||||
Swap
|
||||
</NavLinkRow>
|
||||
<NavLinkRow href="/tokens" close={toggleOpen} isActive={pathname.startsWith('/tokens')}>
|
||||
Tokens
|
||||
</NavLinkRow>
|
||||
<NavLinkRow href="/pool" id={'pool-nav-link'} isActive={isPoolActive} close={toggleOpen}>
|
||||
Pool
|
||||
</NavLinkRow>
|
||||
</Column>
|
||||
<Seperator />
|
||||
<Column gap="4">
|
||||
<ExtraLinkRow to="/vote" close={toggleOpen}>
|
||||
<Icon>
|
||||
<GovernanceIconMobile width={24} height={24} />
|
||||
</Icon>
|
||||
Vote in governance
|
||||
</ExtraLinkRow>
|
||||
<ExtraLinkRow href="https://info.uniswap.org/#/" close={toggleOpen}>
|
||||
<Icon>
|
||||
<BarChartIconMobile width={24} height={24} />
|
||||
</Icon>
|
||||
View token analytics ↗
|
||||
</ExtraLinkRow>
|
||||
</Column>
|
||||
</Column>
|
||||
<Column>
|
||||
<Row justifyContent="center" marginBottom="12" flexWrap="wrap">
|
||||
<Row className={styles.bottomExternalLinks}>
|
||||
<BottomExternalLink href="https://help.uniswap.org/en/" onClick={toggleOpen}>
|
||||
Help center ↗
|
||||
</BottomExternalLink>
|
||||
<BulletIcon />
|
||||
<BottomExternalLink href="https://docs.uniswap.org/" onClick={toggleOpen}>
|
||||
Documentation ↗
|
||||
</BottomExternalLink>
|
||||
<BulletIcon />
|
||||
<BottomExternalLink
|
||||
onClick={() => {
|
||||
toggleOpen()
|
||||
togglePrivacyPolicy()
|
||||
}}
|
||||
>
|
||||
{`Legal & Privacy`}
|
||||
</BottomExternalLink>
|
||||
</Row>
|
||||
{(isDevelopmentEnv() || isStagingEnv()) && (
|
||||
<>
|
||||
<BulletIcon />
|
||||
<BottomExternalLink onClick={openFeatureFlagsModal}>{`Feature Flags`}</BottomExternalLink>
|
||||
</>
|
||||
)}
|
||||
</Row>
|
||||
<Row justifyContent="center">
|
||||
<IconRow>
|
||||
<Icon href="https://discord.com/invite/FCfyBSbCU5">
|
||||
<DiscordIconMenuMobile width={32} height={32} color={themeVars.colors.darkGray} />
|
||||
</Icon>
|
||||
<Icon href="https://twitter.com/Uniswap">
|
||||
<TwitterIconMenuMobile width={32} height={32} color={themeVars.colors.darkGray} />
|
||||
</Icon>
|
||||
<Icon href="https://github.com/Uniswap">
|
||||
<GithubIconMenuMobile width={32} height={32} color={themeVars.colors.darkGray} />
|
||||
</Icon>
|
||||
</IconRow>
|
||||
</Row>
|
||||
</Column>
|
||||
</Column>
|
||||
</Portal>
|
||||
)}
|
||||
<PrivacyPolicyModal />
|
||||
<FeatureFlagModal />
|
||||
</>
|
||||
)
|
||||
}
|
||||
19
src/components/NavBar/NavDropdown.css.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
import { sprinkles } from '../../nft/css/sprinkles.css'
|
||||
|
||||
export const NavDropdown = style([
|
||||
sprinkles({
|
||||
position: 'absolute',
|
||||
background: 'white95',
|
||||
borderRadius: '12',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'medGray',
|
||||
paddingY: '20',
|
||||
borderWidth: '1px',
|
||||
}),
|
||||
{
|
||||
boxShadow: '0px 4px 12px 0px #00000026',
|
||||
zIndex: 10,
|
||||
},
|
||||
])
|
||||
37
src/components/NavBar/NavDropdown.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
import * as styles from './NavDropdown.css'
|
||||
|
||||
interface NavDropdownProps {
|
||||
top: number
|
||||
right?: number
|
||||
leftAligned?: boolean
|
||||
horizontalPadding?: boolean
|
||||
centerHorizontally?: boolean
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export const NavDropdown = ({
|
||||
top,
|
||||
centerHorizontally,
|
||||
leftAligned,
|
||||
horizontalPadding,
|
||||
children,
|
||||
}: NavDropdownProps) => {
|
||||
return (
|
||||
<Box
|
||||
paddingX={horizontalPadding ? '16' : undefined}
|
||||
style={{
|
||||
top: `${top}px`,
|
||||
left: centerHorizontally ? '50%' : leftAligned ? '0px' : 'auto',
|
||||
right: centerHorizontally || leftAligned ? 'auto' : '10px',
|
||||
transform: centerHorizontally ? 'translateX(-50%)' : 'unset',
|
||||
zIndex: 3,
|
||||
}}
|
||||
className={styles.NavDropdown}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
25
src/components/NavBar/NavIcon.css.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
import { sprinkles, themeVars } from '../../nft/css/sprinkles.css'
|
||||
|
||||
export const navIcon = style([
|
||||
sprinkles({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
color: 'blackBlue',
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
justifyContent: 'center',
|
||||
textAlign: 'center',
|
||||
cursor: 'pointer',
|
||||
padding: '8',
|
||||
borderRadius: '8',
|
||||
}),
|
||||
{
|
||||
':hover': {
|
||||
background: themeVars.colors.lightGrayContainer,
|
||||
},
|
||||
zIndex: 2,
|
||||
},
|
||||
])
|
||||
17
src/components/NavBar/NavIcon.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
import * as styles from './NavIcon.css'
|
||||
|
||||
interface NavIconProps {
|
||||
children: ReactNode
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
export const NavIcon = ({ children, onClick }: NavIconProps) => {
|
||||
return (
|
||||
<Box as="button" className={styles.navIcon} onClick={onClick}>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
137
src/components/NavBar/Navbar.css.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
import { subhead } from '../../nft/css/common.css'
|
||||
import { sprinkles } from '../../nft/css/sprinkles.css'
|
||||
|
||||
export const nav = style([
|
||||
sprinkles({
|
||||
paddingX: '20',
|
||||
paddingY: '12',
|
||||
width: 'full',
|
||||
height: '72',
|
||||
zIndex: '2',
|
||||
background: 'white08',
|
||||
}),
|
||||
{
|
||||
backdropFilter: 'blur(24px)',
|
||||
},
|
||||
])
|
||||
|
||||
export const logoContainer = style([
|
||||
sprinkles({
|
||||
display: 'flex',
|
||||
marginRight: { mobile: '12', desktopXl: '20' },
|
||||
alignItems: 'center',
|
||||
}),
|
||||
])
|
||||
|
||||
export const logo = style([
|
||||
sprinkles({
|
||||
display: 'block',
|
||||
color: 'blackBlue',
|
||||
}),
|
||||
])
|
||||
|
||||
export const baseContainer = style([
|
||||
sprinkles({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
])
|
||||
|
||||
export const baseMobileContainer = style([
|
||||
sprinkles({
|
||||
display: 'flex',
|
||||
width: 'full',
|
||||
alignItems: 'center',
|
||||
marginY: '2',
|
||||
}),
|
||||
])
|
||||
|
||||
export const baseSideContainer = style([
|
||||
baseContainer,
|
||||
sprinkles({
|
||||
width: 'full',
|
||||
flex: '1',
|
||||
flexShrink: '2',
|
||||
}),
|
||||
])
|
||||
|
||||
export const leftSideContainer = style([
|
||||
baseSideContainer,
|
||||
sprinkles({
|
||||
justifyContent: 'flex-start',
|
||||
}),
|
||||
])
|
||||
|
||||
export const leftSideMobileContainer = style([
|
||||
baseMobileContainer,
|
||||
sprinkles({
|
||||
justifyContent: 'flex-start',
|
||||
}),
|
||||
])
|
||||
|
||||
export const middleContainer = style([
|
||||
baseContainer,
|
||||
sprinkles({
|
||||
flex: '1',
|
||||
flexShrink: '1',
|
||||
justifyContent: 'center',
|
||||
}),
|
||||
])
|
||||
|
||||
export const rightSideContainer = style([
|
||||
baseSideContainer,
|
||||
sprinkles({
|
||||
justifyContent: 'flex-end',
|
||||
}),
|
||||
])
|
||||
|
||||
const baseMenuItem = style([
|
||||
subhead,
|
||||
sprinkles({
|
||||
paddingY: '8',
|
||||
paddingX: '16',
|
||||
marginY: '4',
|
||||
borderRadius: '12',
|
||||
}),
|
||||
{
|
||||
lineHeight: '24px',
|
||||
textDecoration: 'none',
|
||||
},
|
||||
])
|
||||
|
||||
export const menuItem = style([
|
||||
baseMenuItem,
|
||||
sprinkles({
|
||||
color: 'darkGray',
|
||||
}),
|
||||
])
|
||||
|
||||
export const rightSideMobileContainer = style([
|
||||
baseMobileContainer,
|
||||
sprinkles({
|
||||
justifyContent: 'flex-end',
|
||||
}),
|
||||
])
|
||||
|
||||
export const activeMenuItem = style([
|
||||
baseMenuItem,
|
||||
sprinkles({
|
||||
color: 'blackBlue',
|
||||
}),
|
||||
])
|
||||
|
||||
export const mobileWalletContainer = style([
|
||||
sprinkles({
|
||||
position: 'fixed',
|
||||
display: 'flex',
|
||||
bottom: '0',
|
||||
right: '1/2',
|
||||
marginY: '0',
|
||||
marginX: 'auto',
|
||||
}),
|
||||
{
|
||||
transform: 'translate(50%,-50%)',
|
||||
},
|
||||
])
|
||||
108
src/components/NavBar/Navbar.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import Web3Status from 'components/Web3Status'
|
||||
import { useWindowSize } from 'hooks/useWindowSize'
|
||||
import { ReactNode } from 'react'
|
||||
import { NavLink, NavLinkProps, useLocation } from 'react-router-dom'
|
||||
|
||||
import { Box } from '../../nft/components/Box'
|
||||
import { Row } from '../../nft/components/Flex'
|
||||
import { UniIcon, UniIconMobile } from '../../nft/components/icons'
|
||||
import { breakpoints } from '../../nft/css/sprinkles.css'
|
||||
import { ChainSwitcher } from './ChainSwitcher'
|
||||
import { MenuDropdown } from './MenuDropdown'
|
||||
import { MobileSideBar } from './MobileSidebar'
|
||||
import * as styles from './Navbar.css'
|
||||
|
||||
interface MenuItemProps {
|
||||
href: string
|
||||
id?: NavLinkProps['id']
|
||||
isActive?: boolean
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const MenuItem = ({ href, id, isActive, children }: MenuItemProps) => {
|
||||
return (
|
||||
<NavLink
|
||||
to={href}
|
||||
className={isActive ? styles.activeMenuItem : styles.menuItem}
|
||||
id={id}
|
||||
style={{ textDecoration: 'none' }}
|
||||
>
|
||||
{children}
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
|
||||
const MobileNavbar = () => {
|
||||
return (
|
||||
<>
|
||||
<nav className={styles.nav}>
|
||||
<Box display="flex" height="full" flexWrap="nowrap" alignItems="stretch">
|
||||
<Box className={styles.leftSideMobileContainer}>
|
||||
<Box as="a" href="#/swap" className={styles.logoContainer}>
|
||||
<UniIconMobile width="44" height="44" className={styles.logo} />
|
||||
</Box>
|
||||
<ChainSwitcher isMobile={true} />
|
||||
</Box>
|
||||
<Box className={styles.rightSideMobileContainer}>
|
||||
<Row gap="16">
|
||||
{/* TODO add Searchbar */}
|
||||
<MobileSideBar />
|
||||
</Row>
|
||||
</Box>
|
||||
</Box>
|
||||
</nav>
|
||||
<Box className={styles.mobileWalletContainer}>
|
||||
<Web3Status />
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const Navbar = () => {
|
||||
const { width: windowWidth } = useWindowSize()
|
||||
const { pathname } = useLocation()
|
||||
|
||||
if (windowWidth && windowWidth < breakpoints.desktopXl) {
|
||||
return <MobileNavbar />
|
||||
}
|
||||
|
||||
const isPoolActive =
|
||||
pathname.startsWith('/pool') ||
|
||||
pathname.startsWith('/add') ||
|
||||
pathname.startsWith('/remove') ||
|
||||
pathname.startsWith('/increase') ||
|
||||
pathname.startsWith('/find')
|
||||
|
||||
return (
|
||||
<nav className={styles.nav}>
|
||||
<Box display="flex" height="full" flexWrap="nowrap" alignItems="stretch">
|
||||
<Box className={styles.leftSideContainer}>
|
||||
<Box as="a" href="#/swap" className={styles.logoContainer}>
|
||||
<UniIcon width="48" height="48" className={styles.logo} />
|
||||
</Box>
|
||||
<Row gap="8">
|
||||
<MenuItem href="/swap" isActive={pathname.startsWith('/swap')}>
|
||||
Swap
|
||||
</MenuItem>
|
||||
<MenuItem href="/tokens" isActive={pathname.startsWith('/explore')}>
|
||||
Tokens
|
||||
</MenuItem>
|
||||
<MenuItem href="/pool" id={'pool-nav-link'} isActive={isPoolActive}>
|
||||
Pool
|
||||
</MenuItem>
|
||||
</Row>
|
||||
</Box>
|
||||
<Box className={styles.middleContainer}>{/* TODO add Searchbar */}</Box>
|
||||
<Box className={styles.rightSideContainer}>
|
||||
<Row gap="12">
|
||||
<MenuDropdown />
|
||||
<ChainSwitcher />
|
||||
<Web3Status />
|
||||
</Row>
|
||||
</Box>
|
||||
</Box>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar
|
||||
3
src/components/NavBar/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import Navbar from './Navbar'
|
||||
|
||||
export default Navbar
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { ReactNode } from 'react'
|
||||
import { ArrowLeft } from 'react-feather'
|
||||
import { Link as HistoryLink, useLocation } from 'react-router-dom'
|
||||
@@ -8,7 +7,7 @@ import { Box } from 'rebass'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { resetMintState } from 'state/mint/actions'
|
||||
import { resetMintState as resetMintV3State } from 'state/mint/v3/actions'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import Row, { RowBetween } from '../Row'
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { escapeRegExp } from '../../utils'
|
||||
|
||||
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string; phase0Flag: boolean }>`
|
||||
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string; redesignFlag: boolean }>`
|
||||
color: ${({ error, theme }) => (error ? theme.deprecated_red1 : theme.deprecated_text1)};
|
||||
width: 0;
|
||||
position: relative;
|
||||
font-weight: ${({ phase0Flag }) => (phase0Flag ? 400 : 500)};
|
||||
font-weight: ${({ redesignFlag }) => (redesignFlag ? 400 : 500)};
|
||||
outline: none;
|
||||
border: none;
|
||||
flex: 1 1 auto;
|
||||
background-color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.none : theme.deprecated_bg1)};
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? 'transparent' : theme.deprecated_bg1)};
|
||||
font-size: ${({ fontSize }) => fontSize ?? '28px'};
|
||||
text-align: ${({ align }) => align && align};
|
||||
white-space: nowrap;
|
||||
@@ -36,7 +36,7 @@ const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: s
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.textSecondary : theme.deprecated_text4)};
|
||||
color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.textSecondary : theme.deprecated_text4)};
|
||||
}
|
||||
`
|
||||
|
||||
@@ -56,8 +56,8 @@ export const Input = React.memo(function InnerInput({
|
||||
align?: 'right' | 'left'
|
||||
prependSymbol?: string | undefined
|
||||
} & Omit<React.HTMLProps<HTMLInputElement>, 'ref' | 'onChange' | 'as'>) {
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
const enforcer = (nextUserInput: string) => {
|
||||
if (nextUserInput === '' || inputRegex.test(escapeRegExp(nextUserInput))) {
|
||||
onUserInput(nextUserInput)
|
||||
@@ -68,7 +68,7 @@ export const Input = React.memo(function InnerInput({
|
||||
<StyledInput
|
||||
{...rest}
|
||||
value={prependSymbol && value ? prependSymbol + value : value}
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
onChange={(event) => {
|
||||
if (prependSymbol) {
|
||||
const value = event.target.value
|
||||
@@ -91,7 +91,7 @@ export const Input = React.memo(function InnerInput({
|
||||
// text-specific options
|
||||
type="text"
|
||||
pattern="^[0-9]*[.,]?[0-9]*$"
|
||||
placeholder={placeholder || (phase0FlagEnabled ? '0' : '0.0')}
|
||||
placeholder={placeholder || (redesignFlagEnabled ? '0' : '0.0')}
|
||||
minLength={1}
|
||||
maxLength={79}
|
||||
spellCheck="false"
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { useContext } from 'react'
|
||||
import { AlertCircle } from 'react-feather'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
@@ -15,7 +14,7 @@ const RowNoFlex = styled(AutoRow)`
|
||||
|
||||
export default function FailedNetworkSwitchPopup({ chainId }: { chainId: SupportedChainId }) {
|
||||
const chainInfo = getChainInfo(chainId)
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<RowNoFlex>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useCallback, useContext, useEffect } from 'react'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
import { animated } from 'react-spring'
|
||||
import { useSpring } from 'react-spring/web'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { useRemovePopup } from '../../state/application/hooks'
|
||||
import { PopupContent } from '../../state/application/reducer'
|
||||
@@ -70,7 +70,7 @@ export default function PopupItem({
|
||||
}
|
||||
}, [removeAfterMs, removeThisPopup])
|
||||
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
let popupContent
|
||||
if ('txn' in content) {
|
||||
|
||||
@@ -6,11 +6,10 @@ import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
||||
import { useEffect } from 'react'
|
||||
import { MessageCircle, X } from 'react-feather'
|
||||
import { useShowSurveyPopup } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ExternalLink, ThemedText, Z_INDEX } from 'theme'
|
||||
|
||||
import BGImage from '../../assets/images/survey-orb.svg'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
|
||||
const Wrapper = styled(AutoColumn)`
|
||||
background: #edeef2;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { useContext } from 'react'
|
||||
import { AlertCircle, CheckCircle } from 'react-feather'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { useTransaction } from '../../state/transactions/hooks'
|
||||
import { ThemedText } from '../../theme'
|
||||
@@ -19,7 +18,7 @@ export default function TransactionPopup({ hash }: { hash: string }) {
|
||||
const { chainId } = useWeb3React()
|
||||
|
||||
const tx = useTransaction(hash)
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
if (!tx) return null
|
||||
const success = Boolean(tx.receipt && tx.receipt.status === 1)
|
||||
|
||||
@@ -10,9 +10,9 @@ import { Break } from 'components/earn/styled'
|
||||
import RateToggle from 'components/RateToggle'
|
||||
import { RowBetween, RowFixed } from 'components/Row'
|
||||
import JSBI from 'jsbi'
|
||||
import { ReactNode, useCallback, useContext, useState } from 'react'
|
||||
import { ReactNode, useCallback, useState } from 'react'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
import { ThemeContext } from 'styled-components/macro'
|
||||
import { useTheme } from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
import { formatTickPrice } from 'utils/formatTickPrice'
|
||||
import { unwrappedToken } from 'utils/unwrappedToken'
|
||||
@@ -30,7 +30,7 @@ export const PositionPreview = ({
|
||||
baseCurrencyDefault?: Currency | undefined
|
||||
ticksAtLimit: { [bound: string]: boolean | undefined }
|
||||
}) => {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
const currency0 = unwrappedToken(position.pool.token0)
|
||||
const currency1 = unwrappedToken(position.pool.token1)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { useContext } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
@@ -54,7 +52,7 @@ interface ProgressCirclesProps {
|
||||
* @param steps array of booleans where true means step is complete
|
||||
*/
|
||||
export default function ProgressCircles({ steps, disabled = false, ...rest }: ProgressCirclesProps) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<Wrapper justify={'center'} {...rest}>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { ReactNode, useCallback, useState } from 'react'
|
||||
import { HelpCircle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import Tooltip from '../Tooltip'
|
||||
|
||||
const QuestionWrapper = styled.div<{ phase0Flag: boolean }>`
|
||||
const QuestionWrapper = styled.div<{ redesignFlag: boolean }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -18,8 +18,8 @@ const QuestionWrapper = styled.div<{ phase0Flag: boolean }>`
|
||||
cursor: default;
|
||||
border-radius: 36px;
|
||||
font-size: 12px;
|
||||
border-radius: ${({ phase0Flag }) => phase0Flag && '12px'};
|
||||
color: ${({ theme, phase0Flag }) => !phase0Flag && theme.deprecated_text2};
|
||||
border-radius: ${({ redesignFlag }) => redesignFlag && '12px'};
|
||||
color: ${({ theme, redesignFlag }) => !redesignFlag && theme.deprecated_text2};
|
||||
|
||||
:hover,
|
||||
:focus {
|
||||
@@ -27,12 +27,12 @@ const QuestionWrapper = styled.div<{ phase0Flag: boolean }>`
|
||||
}
|
||||
`
|
||||
|
||||
const QuestionMark = styled.span<{ phase0Flag?: boolean }>`
|
||||
const QuestionMark = styled.span<{ redesignFlag?: boolean }>`
|
||||
font-size: 14px;
|
||||
margin-left: ${({ phase0Flag }) => phase0Flag && '8px'};
|
||||
align-items: ${({ phase0Flag }) => phase0Flag && 'center'};
|
||||
color: ${({ theme, phase0Flag }) => phase0Flag && theme.textSecondary};
|
||||
margin-top: ${({ phase0Flag }) => phase0Flag && '2.5px'};
|
||||
margin-left: ${({ redesignFlag }) => redesignFlag && '8px'};
|
||||
align-items: ${({ redesignFlag }) => redesignFlag && 'center'};
|
||||
color: ${({ theme, redesignFlag }) => redesignFlag && theme.textSecondary};
|
||||
margin-top: ${({ redesignFlag }) => redesignFlag && '2.5px'};
|
||||
`
|
||||
|
||||
export default function QuestionHelper({ text }: { text: ReactNode; size?: number }) {
|
||||
@@ -40,14 +40,14 @@ export default function QuestionHelper({ text }: { text: ReactNode; size?: numbe
|
||||
|
||||
const open = useCallback(() => setShow(true), [setShow])
|
||||
const close = useCallback(() => setShow(false), [setShow])
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
return (
|
||||
<span style={{ marginLeft: 4, display: 'flex', alignItems: 'center' }}>
|
||||
<Tooltip text={text} show={show}>
|
||||
<QuestionWrapper onClick={open} onMouseEnter={open} onMouseLeave={close} phase0Flag={phase0FlagEnabled}>
|
||||
<QuestionMark phase0Flag={phase0FlagEnabled}>
|
||||
{phase0FlagEnabled ? <HelpCircle size={16}></HelpCircle> : '?'}
|
||||
<QuestionWrapper onClick={open} onMouseEnter={open} onMouseLeave={close} redesignFlag={redesignFlagEnabled}>
|
||||
<QuestionMark redesignFlag={redesignFlagEnabled}>
|
||||
{redesignFlagEnabled ? <HelpCircle size={16}></HelpCircle> : '?'}
|
||||
</QuestionMark>
|
||||
</QuestionWrapper>
|
||||
</Tooltip>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { AutoColumn } from 'components/Column'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import { AutoRow } from 'components/Row'
|
||||
import { COMMON_BASES } from 'constants/routing'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
|
||||
import { Text } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
@@ -17,21 +18,33 @@ const MobileWrapper = styled(AutoColumn)`
|
||||
`};
|
||||
`
|
||||
|
||||
const BaseWrapper = styled.div<{ disable?: boolean }>`
|
||||
border: 1px solid ${({ theme, disable }) => (disable ? 'transparent' : theme.deprecated_bg3)};
|
||||
border-radius: 10px;
|
||||
const BaseWrapper = styled.div<{ disable?: boolean; redesignFlag?: boolean }>`
|
||||
border: 1px solid
|
||||
${({ theme, disable, redesignFlag }) =>
|
||||
disable
|
||||
? redesignFlag
|
||||
? theme.accentAction
|
||||
: 'transparent'
|
||||
: redesignFlag
|
||||
? theme.backgroundOutline
|
||||
: theme.deprecated_bg3};
|
||||
border-radius: ${({ redesignFlag }) => (redesignFlag ? '16px' : '10px')};
|
||||
display: flex;
|
||||
padding: 6px;
|
||||
padding-right: 12px;
|
||||
|
||||
align-items: center;
|
||||
:hover {
|
||||
cursor: ${({ disable }) => !disable && 'pointer'};
|
||||
background-color: ${({ theme, disable }) => !disable && theme.deprecated_bg2};
|
||||
background-color: ${({ theme, disable, redesignFlag }) =>
|
||||
(redesignFlag && theme.hoverDefault) || (!disable && theme.deprecated_bg2)};
|
||||
}
|
||||
|
||||
color: ${({ theme, disable }) => disable && theme.deprecated_text3};
|
||||
background-color: ${({ theme, disable }) => disable && theme.deprecated_bg3};
|
||||
filter: ${({ disable }) => disable && 'grayscale(1)'};
|
||||
color: ${({ theme, disable, redesignFlag }) =>
|
||||
disable && (redesignFlag ? theme.accentAction : theme.deprecated_text3)};
|
||||
background-color: ${({ theme, disable, redesignFlag }) =>
|
||||
disable && (redesignFlag ? theme.accentActionSoft : theme.deprecated_bg3)};
|
||||
filter: ${({ disable, redesignFlag }) => disable && !redesignFlag && 'grayscale(1)'};
|
||||
`
|
||||
|
||||
const formatAnalyticsEventProperties = (currency: Currency, searchQuery: string, isAddressSearch: string | false) => ({
|
||||
@@ -60,6 +73,8 @@ export default function CommonBases({
|
||||
isAddressSearch: string | false
|
||||
}) {
|
||||
const bases = typeof chainId !== 'undefined' ? COMMON_BASES[chainId] ?? [] : []
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
return bases.length > 0 ? (
|
||||
<MobileWrapper gap="md">
|
||||
@@ -80,6 +95,7 @@ export default function CommonBases({
|
||||
onKeyPress={(e) => !isSelected && e.key === 'Enter' && onSelect(currency)}
|
||||
onClick={() => !isSelected && onSelect(currency)}
|
||||
disable={isSelected}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
key={currencyId(currency)}
|
||||
>
|
||||
<CurrencyLogoFromList currency={currency} />
|
||||
|
||||
@@ -7,12 +7,13 @@ import { LightGreyCard } from 'components/Card'
|
||||
import QuestionHelper from 'components/QuestionHelper'
|
||||
import TokenSafetyIcon from 'components/TokenSafety/TokenSafetyIcon'
|
||||
import { checkWarning } from 'constants/tokenSafety'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { TokenSafetyVariant, useTokenSafetyFlag } from 'featureFlags/flags/tokenSafety'
|
||||
import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'
|
||||
import { Check } from 'react-feather'
|
||||
import { FixedSizeList } from 'react-window'
|
||||
import { Text } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import TokenListLogo from '../../../assets/svg/tokenlist.svg'
|
||||
import { useIsUserAddedToken } from '../../../hooks/Tokens'
|
||||
@@ -33,6 +34,13 @@ function currencyKey(currency: Currency): string {
|
||||
return currency.isToken ? currency.address : 'ETHER'
|
||||
}
|
||||
|
||||
const CheckIcon = styled(Check)`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-left: 4px;
|
||||
color: ${({ theme }) => theme.accentAction};
|
||||
`
|
||||
|
||||
const StyledBalanceText = styled(Text)`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -134,7 +142,9 @@ function CurrencyRow({
|
||||
const customAdded = useIsUserAddedToken(currency)
|
||||
const balance = useCurrencyBalance(account ?? undefined, currency)
|
||||
const warning = currency.isNative ? null : checkWarning(currency.address)
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
const tokenSafetyFlag = useTokenSafetyFlag()
|
||||
|
||||
// only show add or remove buttons if not on selected list
|
||||
return (
|
||||
@@ -146,6 +156,7 @@ function CurrencyRow({
|
||||
>
|
||||
<MenuItem
|
||||
tabIndex={0}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
style={style}
|
||||
className={`token-item-${key}`}
|
||||
onKeyPress={(e) => (!isSelected && e.key === 'Enter' ? onSelect() : null)}
|
||||
@@ -160,7 +171,7 @@ function CurrencyRow({
|
||||
<Row>
|
||||
<CurrencyName title={currency.name}>{currency.name}</CurrencyName>
|
||||
|
||||
{phase0Flag === Phase0Variant.Enabled && <TokenSafetyIcon warning={warning} />}
|
||||
{tokenSafetyFlag === TokenSafetyVariant.Enabled && <TokenSafetyIcon warning={warning} />}
|
||||
</Row>
|
||||
<ThemedText.DeprecatedDarkGray ml="0px" fontSize={'12px'} fontWeight={300}>
|
||||
{!currency.isNative && !isOnSelectedList && customAdded ? (
|
||||
@@ -175,10 +186,18 @@ function CurrencyRow({
|
||||
<TokenTags currency={currency} />
|
||||
</RowFixed>
|
||||
</Column>
|
||||
{showCurrencyAmount && (
|
||||
{showCurrencyAmount ? (
|
||||
<RowFixed style={{ justifySelf: 'flex-end' }}>
|
||||
{balance ? <Balance balance={balance} /> : account ? <Loader /> : null}
|
||||
{redesignFlagEnabled && isSelected && <CheckIcon />}
|
||||
</RowFixed>
|
||||
) : (
|
||||
redesignFlagEnabled &&
|
||||
isSelected && (
|
||||
<RowFixed style={{ justifySelf: 'flex-end' }}>
|
||||
<CheckIcon />
|
||||
</RowFixed>
|
||||
)
|
||||
)}
|
||||
</MenuItem>
|
||||
</TraceEvent>
|
||||
|
||||
@@ -5,9 +5,9 @@ import { useWeb3React } from '@web3-react/core'
|
||||
import { EventName, ModalName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import { sendEvent } from 'components/analytics'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import useDebounce from 'hooks/useDebounce'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
||||
import { getTokenFilter } from 'lib/hooks/useTokenList/filtering'
|
||||
@@ -18,7 +18,7 @@ import AutoSizer from 'react-virtualized-auto-sizer'
|
||||
import { FixedSizeList } from 'react-window'
|
||||
import { Text } from 'rebass'
|
||||
import { useAllTokenBalances } from 'state/connection/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
|
||||
import { ButtonText, CloseIcon, IconWrapper, ThemedText } from '../../theme'
|
||||
@@ -30,7 +30,8 @@ import CurrencyList from './CurrencyList'
|
||||
import ImportRow from './ImportRow'
|
||||
import { PaddedColumn, SearchInput, Separator } from './styleds'
|
||||
|
||||
const ContentWrapper = styled(Column)`
|
||||
const ContentWrapper = styled(Column)<{ redesignFlag?: boolean }>`
|
||||
background-color: ${({ theme, redesignFlag }) => redesignFlag && theme.backgroundSurface};
|
||||
width: 100%;
|
||||
flex: 1 1;
|
||||
position: relative;
|
||||
@@ -73,6 +74,9 @@ export function CurrencySearch({
|
||||
showImportView,
|
||||
setImportToken,
|
||||
}: CurrencySearchProps) {
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
const { chainId } = useWeb3React()
|
||||
const theme = useTheme()
|
||||
|
||||
@@ -191,7 +195,7 @@ export function CurrencySearch({
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ContentWrapper>
|
||||
<ContentWrapper redesignFlag={redesignFlagEnabled}>
|
||||
<Trace name={EventName.TOKEN_SELECTOR_OPENED} modal={ModalName.TOKEN_SELECTOR} shouldLogImpression>
|
||||
<PaddedColumn gap="16px">
|
||||
<RowBetween>
|
||||
@@ -206,6 +210,7 @@ export function CurrencySearch({
|
||||
id="token-search-input"
|
||||
placeholder={t`Search name or paste address`}
|
||||
autoComplete="off"
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
value={searchQuery}
|
||||
ref={inputRef as RefObject<HTMLInputElement>}
|
||||
onChange={handleInput}
|
||||
@@ -222,7 +227,7 @@ export function CurrencySearch({
|
||||
/>
|
||||
)}
|
||||
</PaddedColumn>
|
||||
<Separator />
|
||||
<Separator redesignFlag={redesignFlagEnabled} />
|
||||
{searchToken && !searchTokenIsAdded ? (
|
||||
<Column style={{ padding: '20px 0', height: '100%' }}>
|
||||
<ImportRow token={searchToken} showImportView={showImportView} setImportToken={setImportToken} />
|
||||
@@ -256,20 +261,26 @@ export function CurrencySearch({
|
||||
</ThemedText.DeprecatedMain>
|
||||
</Column>
|
||||
)}
|
||||
<Footer>
|
||||
<Row justify="center">
|
||||
<ButtonText onClick={showManageView} color={theme.deprecated_primary1} className="list-token-manage-button">
|
||||
<RowFixed>
|
||||
<IconWrapper size="16px" marginRight="6px" stroke={theme.deprecated_primaryText1}>
|
||||
<Edit />
|
||||
</IconWrapper>
|
||||
<ThemedText.DeprecatedMain color={theme.deprecated_primaryText1}>
|
||||
<Trans>Manage Token Lists</Trans>
|
||||
</ThemedText.DeprecatedMain>
|
||||
</RowFixed>
|
||||
</ButtonText>
|
||||
</Row>
|
||||
</Footer>
|
||||
{!redesignFlagEnabled && (
|
||||
<Footer>
|
||||
<Row justify="center">
|
||||
<ButtonText
|
||||
onClick={showManageView}
|
||||
color={theme.deprecated_primary1}
|
||||
className="list-token-manage-button"
|
||||
>
|
||||
<RowFixed>
|
||||
<IconWrapper size="16px" marginRight="6px" stroke={theme.deprecated_primaryText1}>
|
||||
<Edit />
|
||||
</IconWrapper>
|
||||
<ThemedText.DeprecatedMain color={theme.deprecated_primaryText1}>
|
||||
<Trans>Manage Token Lists</Trans>
|
||||
</ThemedText.DeprecatedMain>
|
||||
</RowFixed>
|
||||
</ButtonText>
|
||||
</Row>
|
||||
</Footer>
|
||||
)}
|
||||
</Trace>
|
||||
</ContentWrapper>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Currency, Token } from '@uniswap/sdk-core'
|
||||
import { TokenList } from '@uniswap/token-lists'
|
||||
import TokenSafety from 'components/TokenSafety'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { TokenSafetyVariant, useTokenSafetyFlag } from 'featureFlags/flags/tokenSafety'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo'
|
||||
@@ -75,7 +75,7 @@ export default function CurrencySearchModal({
|
||||
[setModalView, prevView]
|
||||
)
|
||||
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const tokenSafetyFlag = useTokenSafetyFlag()
|
||||
|
||||
// change min height if not searching
|
||||
let minHeight: number | undefined = 80
|
||||
@@ -102,7 +102,7 @@ export default function CurrencySearchModal({
|
||||
if (importToken) {
|
||||
minHeight = undefined
|
||||
content =
|
||||
phase0Flag === Phase0Variant.Enabled ? (
|
||||
tokenSafetyFlag === TokenSafetyVariant.Enabled ? (
|
||||
<TokenSafety
|
||||
tokenAddress={importToken.address}
|
||||
onContinue={() => handleCurrencySelect(importToken)}
|
||||
|
||||
@@ -8,14 +8,13 @@ import ListLogo from 'components/ListLogo'
|
||||
import { AutoRow, RowBetween, RowFixed } from 'components/Row'
|
||||
import { SectionBreak } from 'components/swap/styleds'
|
||||
import { useFetchListCallback } from 'hooks/useFetchListCallback'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { transparentize } from 'polished'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { AlertTriangle, ArrowLeft } from 'react-feather'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { enableList, removeList } from 'state/lists/actions'
|
||||
import { useAllLists } from 'state/lists/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { CloseIcon, ThemedText } from 'theme'
|
||||
|
||||
import { ExternalLink } from '../../theme'
|
||||
|
||||
@@ -6,10 +6,9 @@ import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import ListLogo from 'components/ListLogo'
|
||||
import { AutoRow, RowFixed } from 'components/Row'
|
||||
import { useIsTokenActive, useIsUserAddedToken } from 'hooks/Tokens'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { CSSProperties } from 'react'
|
||||
import { CheckCircle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
|
||||
|
||||
@@ -8,10 +8,9 @@ import { AutoColumn } from 'components/Column'
|
||||
import { RowBetween } from 'components/Row'
|
||||
import { SectionBreak } from 'components/swap/styleds'
|
||||
import { useUnsupportedTokens } from 'hooks/Tokens'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { AlertCircle, ArrowLeft } from 'react-feather'
|
||||
import { useAddUserToken } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { CloseIcon, ThemedText } from 'theme'
|
||||
|
||||
import BlockedToken from './BlockedToken'
|
||||
|
||||
@@ -12,11 +12,10 @@ import { ChangeEvent, memo, useCallback, useEffect, useMemo, useRef, useState }
|
||||
import { CheckCircle, Settings } from 'react-feather'
|
||||
import { usePopper } from 'react-popper'
|
||||
import { useAppDispatch, useAppSelector } from 'state/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { useFetchListCallback } from '../../hooks/useFetchListCallback'
|
||||
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import useToggle from '../../hooks/useToggle'
|
||||
import { acceptListUpdate, disableList, enableList, removeList } from '../../state/lists/actions'
|
||||
import { useActiveListUrls, useAllLists, useIsListActive } from '../../state/lists/hooks'
|
||||
|
||||
@@ -8,11 +8,10 @@ import Row, { RowBetween, RowFixed } from 'components/Row'
|
||||
import { useToken } from 'hooks/Tokens'
|
||||
import { ChangeEvent, RefObject, useCallback, useMemo, useRef, useState } from 'react'
|
||||
import { useRemoveUserAddedToken, useUserAddedTokens } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ButtonText, ExternalLink, ExternalLinkIcon, ThemedText, TrashIcon } from 'theme'
|
||||
import { isAddress } from 'utils'
|
||||
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { CurrencyModalView } from './CurrencySearchModal'
|
||||
import ImportRow from './ImportRow'
|
||||
|
||||
@@ -21,7 +21,7 @@ export const PaddedColumn = styled(AutoColumn)`
|
||||
padding: 20px;
|
||||
`
|
||||
|
||||
export const MenuItem = styled(RowBetween)`
|
||||
export const MenuItem = styled(RowBetween)<{ redesignFlag?: boolean }>`
|
||||
padding: 4px 20px;
|
||||
height: 56px;
|
||||
display: grid;
|
||||
@@ -30,42 +30,47 @@ export const MenuItem = styled(RowBetween)`
|
||||
cursor: ${({ disabled }) => !disabled && 'pointer'};
|
||||
pointer-events: ${({ disabled }) => disabled && 'none'};
|
||||
:hover {
|
||||
background-color: ${({ theme, disabled }) => !disabled && theme.deprecated_bg2};
|
||||
background-color: ${({ theme, disabled, redesignFlag }) =>
|
||||
(redesignFlag && theme.hoverDefault) || (!disabled && theme.deprecated_bg2)};
|
||||
}
|
||||
opacity: ${({ disabled, selected }) => (disabled || selected ? 0.5 : 1)};
|
||||
`
|
||||
|
||||
export const SearchInput = styled.input`
|
||||
export const SearchInput = styled.input<{ redesignFlag?: boolean }>`
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
height: ${({ redesignFlag }) => redesignFlag && '40px'};
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
background: none;
|
||||
background-color: ${({ theme, redesignFlag }) => redesignFlag && theme.backgroundModule};
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 20px;
|
||||
border-radius: ${({ redesignFlag }) => (redesignFlag ? '12px' : '20px')};
|
||||
color: ${({ theme }) => theme.deprecated_text1};
|
||||
border-style: solid;
|
||||
border: 1px solid ${({ theme }) => theme.deprecated_bg3};
|
||||
border: 1px solid ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundOutline : theme.deprecated_bg3)};
|
||||
-webkit-appearance: none;
|
||||
|
||||
font-size: 18px;
|
||||
font-size: ${({ redesignFlag }) => (redesignFlag ? '16px' : '18px')};
|
||||
|
||||
::placeholder {
|
||||
color: ${({ theme }) => theme.deprecated_text3};
|
||||
color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.textTertiary : theme.deprecated_text3)};
|
||||
font-size: ${({ redesignFlag }) => redesignFlag && '16px'};
|
||||
}
|
||||
transition: border 100ms;
|
||||
:focus {
|
||||
border: 1px solid ${({ theme }) => theme.deprecated_primary1};
|
||||
border: 1px solid ${({ theme, redesignFlag }) => (redesignFlag ? 'transparent' : theme.deprecated_primary1)};
|
||||
background-color: ${({ theme, redesignFlag }) => redesignFlag && theme.accentActionSoft};
|
||||
outline: none;
|
||||
}
|
||||
`
|
||||
export const Separator = styled.div`
|
||||
export const Separator = styled.div<{ redesignFlag?: boolean }>`
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: ${({ theme }) => theme.deprecated_bg2};
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundOutline : theme.deprecated_bg2)};
|
||||
`
|
||||
|
||||
export const SeparatorDark = styled.div`
|
||||
|
||||
@@ -3,12 +3,12 @@ import { t, Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { sendEvent } from 'components/analytics'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { isSupportedChainId } from 'lib/hooks/routing/clientSideSmartOrderRouter'
|
||||
import { useContext, useRef, useState } from 'react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Settings, X } from 'react-feather'
|
||||
import { Text } from 'rebass'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
|
||||
import { useModalIsOpen, useToggleSettingsMenu } from '../../state/application/hooks'
|
||||
@@ -23,16 +23,16 @@ import { RowBetween, RowFixed } from '../Row'
|
||||
import Toggle from '../Toggle'
|
||||
import TransactionSettings from '../TransactionSettings'
|
||||
|
||||
const StyledMenuIcon = styled(Settings)<{ phase0Flag: boolean }>`
|
||||
const StyledMenuIcon = styled(Settings)<{ redesignFlag: boolean }>`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
> * {
|
||||
stroke: ${({ theme, phase0Flag }) => (phase0Flag ? theme.textSecondary : theme.deprecated_text1)};
|
||||
stroke: ${({ theme, redesignFlag }) => (redesignFlag ? theme.textSecondary : theme.deprecated_text1)};
|
||||
}
|
||||
`
|
||||
|
||||
const StyledCloseIcon = styled(X)<{ phase0Flag: boolean }>`
|
||||
const StyledCloseIcon = styled(X)<{ redesignFlag: boolean }>`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
:hover {
|
||||
@@ -40,7 +40,7 @@ const StyledCloseIcon = styled(X)<{ phase0Flag: boolean }>`
|
||||
}
|
||||
|
||||
> * {
|
||||
stroke: ${({ theme, phase0Flag }) => (phase0Flag ? theme.textSecondary : theme.deprecated_text1)};
|
||||
stroke: ${({ theme, redesignFlag }) => (redesignFlag ? theme.textSecondary : theme.deprecated_text1)};
|
||||
}
|
||||
`
|
||||
|
||||
@@ -83,10 +83,10 @@ const StyledMenu = styled.div`
|
||||
text-align: left;
|
||||
`
|
||||
|
||||
const MenuFlyout = styled.span<{ phase0Flag: boolean }>`
|
||||
const MenuFlyout = styled.span<{ redesignFlag: boolean }>`
|
||||
min-width: 20.125rem;
|
||||
background-color: ${({ theme, phase0Flag }) => (phase0Flag ? theme.backgroundSurface : theme.deprecated_bg2)};
|
||||
border: 1px solid ${({ theme, phase0Flag }) => (phase0Flag ? theme.backgroundOutline : theme.deprecated_bg3)};
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundSurface : theme.deprecated_bg2)};
|
||||
border: 1px solid ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundOutline : theme.deprecated_bg3)};
|
||||
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: 12px;
|
||||
@@ -97,7 +97,7 @@ const MenuFlyout = styled.span<{ phase0Flag: boolean }>`
|
||||
top: 2rem;
|
||||
right: 0rem;
|
||||
z-index: 100;
|
||||
color: ${({ theme, phase0Flag }) => phase0Flag && theme.textPrimary};
|
||||
color: ${({ theme, redesignFlag }) => redesignFlag && theme.textPrimary};
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
min-width: 18.125rem;
|
||||
@@ -123,14 +123,14 @@ const ModalContentWrapper = styled.div`
|
||||
|
||||
export default function SettingsTab({ placeholderSlippage }: { placeholderSlippage: Percent }) {
|
||||
const { chainId } = useWeb3React()
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
const node = useRef<HTMLDivElement>()
|
||||
const open = useModalIsOpen(ApplicationModal.SETTINGS)
|
||||
const toggle = useToggleSettingsMenu()
|
||||
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
const [expertMode, toggleExpertMode] = useExpertModeManager()
|
||||
|
||||
@@ -152,7 +152,7 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
|
||||
<Text fontWeight={500} fontSize={20}>
|
||||
<Trans>Are you sure?</Trans>
|
||||
</Text>
|
||||
<StyledCloseIcon onClick={() => setShowConfirmation(false)} phase0Flag={phase0FlagEnabled} />
|
||||
<StyledCloseIcon onClick={() => setShowConfirmation(false)} redesignFlag={redesignFlagEnabled} />
|
||||
</RowBetween>
|
||||
<Break />
|
||||
<AutoColumn gap="lg" style={{ padding: '0 2rem' }}>
|
||||
@@ -190,7 +190,7 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
|
||||
id="open-settings-dialog-button"
|
||||
aria-label={t`Transaction Settings`}
|
||||
>
|
||||
<StyledMenuIcon phase0Flag={phase0FlagEnabled} />
|
||||
<StyledMenuIcon redesignFlag={redesignFlagEnabled} />
|
||||
{expertMode ? (
|
||||
<EmojiWrapper>
|
||||
<span role="img" aria-label="wizard-icon">
|
||||
@@ -200,10 +200,10 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
|
||||
) : null}
|
||||
</StyledMenuButton>
|
||||
{open && (
|
||||
<MenuFlyout phase0Flag={phase0FlagEnabled}>
|
||||
<MenuFlyout redesignFlag={redesignFlagEnabled}>
|
||||
<AutoColumn gap="md" style={{ padding: '1rem' }}>
|
||||
<Text fontWeight={600} fontSize={14}>
|
||||
<Trans>{phase0FlagEnabled ? 'Settings' : 'Transaction Settings'}</Trans>
|
||||
<Trans>{redesignFlagEnabled ? 'Settings' : 'Transaction Settings'}</Trans>
|
||||
</Text>
|
||||
<TransactionSettings placeholderSlippage={placeholderSlippage} />
|
||||
<Text fontWeight={600} fontSize={14}>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { darken } from 'polished'
|
||||
import { useState } from 'react'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
|
||||
const Wrapper = styled.button<{ isActive?: boolean; activeElement?: boolean; phase0Flag: boolean }>`
|
||||
const Wrapper = styled.button<{ isActive?: boolean; activeElement?: boolean; redesignFlag: boolean }>`
|
||||
align-items: center;
|
||||
background: ${({ isActive, theme, phase0Flag }) =>
|
||||
phase0Flag && isActive ? theme.accentActionSoft : theme.deprecated_bg1};
|
||||
background: ${({ isActive, theme, redesignFlag }) =>
|
||||
redesignFlag && isActive ? theme.accentActionSoft : theme.deprecated_bg1};
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
@@ -73,8 +73,8 @@ interface ToggleProps {
|
||||
|
||||
export default function Toggle({ id, bgColor, isActive, toggle }: ToggleProps) {
|
||||
const [isInitialToggleLoad, setIsInitialToggleLoad] = useState(true)
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
const switchToggle = () => {
|
||||
toggle()
|
||||
@@ -82,7 +82,7 @@ export default function Toggle({ id, bgColor, isActive, toggle }: ToggleProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrapper id={id} isActive={isActive} onClick={switchToggle} phase0Flag={phase0FlagEnabled}>
|
||||
<Wrapper id={id} isActive={isActive} onClick={switchToggle} redesignFlag={redesignFlagEnabled}>
|
||||
<ToggleElement isActive={isActive} bgColor={bgColor} isInitialToggleLoad={isInitialToggleLoad} />
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
@@ -9,15 +9,14 @@ import styled, { useTheme } from 'styled-components/macro'
|
||||
import NetworkBalance from './NetworkBalance'
|
||||
|
||||
const BalancesCard = styled.div`
|
||||
width: 284px;
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
line-height: 16px;
|
||||
padding: 20px;
|
||||
background-color: ${({ theme }) => theme.backgroundSurface};
|
||||
border-radius: 12px;
|
||||
border: 1px solid ${({ theme }) => theme.backgroundOutline};
|
||||
border-radius: 16px;
|
||||
`
|
||||
const ErrorState = styled.div`
|
||||
display: flex;
|
||||
@@ -1,7 +1,7 @@
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { ChartWrapper, DeltaContainer, TokenPrice } from '../../Charts/PriceChart'
|
||||
import { LoadingBubble } from '../loading'
|
||||
import { DeltaContainer, TokenPrice } from './PriceChart'
|
||||
import {
|
||||
AboutHeader,
|
||||
AboutSection,
|
||||
@@ -18,6 +18,11 @@ import {
|
||||
TopArea,
|
||||
} from './TokenDetail'
|
||||
|
||||
const LoadingChartContainer = styled(ChartContainer)`
|
||||
height: 336px;
|
||||
overflow: hidden;
|
||||
`
|
||||
|
||||
/* Loading state bubbles */
|
||||
const LoadingDetailBubble = styled(LoadingBubble)`
|
||||
height: 16px;
|
||||
@@ -71,6 +76,15 @@ const Space = styled.div<{ heightSize: number }>`
|
||||
height: ${({ heightSize }) => `${heightSize}px`};
|
||||
`
|
||||
|
||||
function Wave() {
|
||||
const theme = useTheme()
|
||||
return (
|
||||
<svg width="416" height="160" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0 80 Q 104 10, 208 80 T 416 80" stroke={theme.backgroundOutline} fill="transparent" strokeWidth="2" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
/* Loading State: row component with loading bubbles */
|
||||
export default function LoadingTokenDetail() {
|
||||
return (
|
||||
@@ -85,35 +99,23 @@ export default function LoadingTokenDetail() {
|
||||
<TitleLoadingBubble />
|
||||
</TokenNameCell>
|
||||
</TokenInfoContainer>
|
||||
<ChartContainer>
|
||||
<ChartWrapper>
|
||||
<ChartHeader>
|
||||
<TokenPrice>
|
||||
<PriceLoadingBubble />
|
||||
</TokenPrice>
|
||||
<DeltaContainer>
|
||||
<Space heightSize={20} />
|
||||
</DeltaContainer>
|
||||
</ChartHeader>
|
||||
<TokenPrice>
|
||||
<PriceLoadingBubble />
|
||||
</TokenPrice>
|
||||
<DeltaContainer>
|
||||
<Space heightSize={20} />
|
||||
</DeltaContainer>
|
||||
<LoadingChartContainer>
|
||||
<div>
|
||||
<ChartAnimation>
|
||||
<svg width="416" height="160" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0 80 Q 104 10, 208 80 T 416 80" stroke="#2e3138" fill="transparent" strokeWidth="2" />
|
||||
</svg>
|
||||
<svg width="416" height="160" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0 80 Q 104 10, 208 80 T 416 80" stroke="#2e3138" fill="transparent" strokeWidth="2" />
|
||||
</svg>
|
||||
<svg width="416" height="160" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0 80 Q 104 10, 208 80 T 416 80" stroke="#2e3138" fill="transparent" strokeWidth="2" />
|
||||
</svg>
|
||||
<svg width="416" height="160" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0 80 Q 104 10, 208 80 T 416 80" stroke="#2e3138" fill="transparent" strokeWidth="2" />
|
||||
</svg>
|
||||
<svg width="416" height="160" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0 80 Q 104 10, 208 80 T 416 80" stroke="#2e3138" fill="transparent" strokeWidth="2" />
|
||||
</svg>
|
||||
<Wave />
|
||||
<Wave />
|
||||
<Wave />
|
||||
<Wave />
|
||||
<Wave />
|
||||
</ChartAnimation>
|
||||
</ChartWrapper>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</LoadingChartContainer>
|
||||
<Space heightSize={32} />
|
||||
</ChartHeader>
|
||||
<AboutSection>
|
||||
@@ -1,5 +1,4 @@
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
const Balance = styled.div`
|
||||
width: 100%;
|
||||
@@ -3,15 +3,15 @@ import { localPoint } from '@visx/event'
|
||||
import { EventType } from '@visx/event/lib/types'
|
||||
import { GlyphCircle } from '@visx/glyph'
|
||||
import { Line } from '@visx/shape'
|
||||
import { filterTimeAtom } from 'components/Explore/state'
|
||||
import { filterTimeAtom } from 'components/Tokens/state'
|
||||
import { bisect, curveBasis, NumberValue, scaleLinear } from 'd3'
|
||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { TimePeriod } from 'hooks/useTopTokens'
|
||||
import { TimePeriod } from 'hooks/useExplorePageQuery'
|
||||
import { useAtom } from 'jotai'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { ArrowDownRight, ArrowUpRight } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { OPACITY_HOVER } from 'theme'
|
||||
import {
|
||||
dayHourFormatter,
|
||||
hourFormatter,
|
||||
@@ -22,8 +22,8 @@ import {
|
||||
weekFormatter,
|
||||
} from 'utils/formatChartTimes'
|
||||
|
||||
import data from './data.json'
|
||||
import LineChart from './LineChart'
|
||||
import data from '../../Charts/data.json'
|
||||
import LineChart from '../../Charts/LineChart'
|
||||
|
||||
// TODO: This should be combined with the logic in TimeSelector.
|
||||
const TIME_DISPLAYS: [TimePeriod, string][] = [
|
||||
@@ -32,7 +32,7 @@ const TIME_DISPLAYS: [TimePeriod, string][] = [
|
||||
[TimePeriod.week, '1W'],
|
||||
[TimePeriod.month, '1M'],
|
||||
[TimePeriod.year, '1Y'],
|
||||
[TimePeriod.all, 'ALL'],
|
||||
[TimePeriod.all, 'All'],
|
||||
]
|
||||
|
||||
type PricePoint = { value: number; timestamp: number }
|
||||
@@ -64,11 +64,6 @@ function getDelta(start: number, current: number) {
|
||||
return [formattedDelta, <StyledDownArrow size={16} key="arrow-down" />]
|
||||
}
|
||||
|
||||
export const ChartWrapper = styled.div`
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
`
|
||||
|
||||
export const ChartHeader = styled.div`
|
||||
position: absolute;
|
||||
`
|
||||
@@ -111,6 +106,9 @@ const TimeButton = styled.button<{ active: boolean }>`
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: ${({ theme, active }) => (active ? theme.textPrimary : theme.textSecondary)};
|
||||
:hover {
|
||||
${({ active }) => !active && `opacity: ${OPACITY_HOVER};`}
|
||||
}
|
||||
`
|
||||
|
||||
function getTicks(startTimestamp: number, endTimestamp: number, numTicks = 5) {
|
||||
@@ -142,7 +140,7 @@ function tickFormat(
|
||||
}
|
||||
}
|
||||
|
||||
const margin = { top: 86, bottom: 32, crosshair: 72 }
|
||||
const margin = { top: 86, bottom: 48, crosshair: 72 }
|
||||
const timeOptionsHeight = 44
|
||||
const crosshairDateOverhang = 80
|
||||
|
||||
@@ -208,7 +206,7 @@ export function PriceChart({ width, height }: PriceChartProps) {
|
||||
const crosshairAtEdge = !!selected.xCoordinate && selected.xCoordinate > crosshairEdgeMax
|
||||
|
||||
return (
|
||||
<ChartWrapper>
|
||||
<>
|
||||
<ChartHeader>
|
||||
<TokenPrice>${selected.pricePoint.value.toFixed(2)}</TokenPrice>
|
||||
<DeltaContainer>
|
||||
@@ -227,24 +225,24 @@ export function PriceChart({ width, height }: PriceChartProps) {
|
||||
width={graphWidth}
|
||||
height={graphHeight}
|
||||
>
|
||||
<AxisBottom
|
||||
scale={timeScale}
|
||||
stroke={theme.backgroundOutline}
|
||||
tickFormat={tickFormatter}
|
||||
tickStroke={theme.backgroundOutline}
|
||||
tickLength={4}
|
||||
tickTransform={'translate(0 -5)'}
|
||||
tickValues={ticks}
|
||||
top={graphHeight - 1}
|
||||
tickLabelProps={() => ({
|
||||
fill: theme.textSecondary,
|
||||
fontSize: 12,
|
||||
textAnchor: 'middle',
|
||||
transform: 'translate(0 -24)',
|
||||
})}
|
||||
/>
|
||||
{selected.xCoordinate !== null && (
|
||||
{selected.xCoordinate !== null ? (
|
||||
<g>
|
||||
<AxisBottom
|
||||
scale={timeScale}
|
||||
stroke={theme.backgroundOutline}
|
||||
tickFormat={tickFormatter}
|
||||
tickStroke={theme.backgroundOutline}
|
||||
tickLength={4}
|
||||
tickTransform={'translate(0 -5)'}
|
||||
tickValues={ticks}
|
||||
top={graphHeight - 1}
|
||||
tickLabelProps={() => ({
|
||||
fill: theme.textSecondary,
|
||||
fontSize: 12,
|
||||
textAnchor: 'middle',
|
||||
transform: 'translate(0 -24)',
|
||||
})}
|
||||
/>
|
||||
<text
|
||||
x={selected.xCoordinate + (crosshairAtEdge ? -4 : 4)}
|
||||
y={margin.crosshair + 10}
|
||||
@@ -271,6 +269,8 @@ export function PriceChart({ width, height }: PriceChartProps) {
|
||||
strokeWidth={2}
|
||||
/>
|
||||
</g>
|
||||
) : (
|
||||
<AxisBottom scale={timeScale} stroke={theme.backgroundOutline} top={graphHeight - 1} hideTicks />
|
||||
)}
|
||||
<rect
|
||||
x={0}
|
||||
@@ -293,7 +293,7 @@ export function PriceChart({ width, height }: PriceChartProps) {
|
||||
))}
|
||||
</TimeOptionsContainer>
|
||||
</TimeOptionsWrapper>
|
||||
</ChartWrapper>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
112
src/components/Tokens/TokenDetails/ShareButton.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import { useRef } from 'react'
|
||||
import { Twitter } from 'react-feather'
|
||||
import { useModalIsOpen, useToggleModal } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ClickableStyle, CopyHelperRefType, OPACITY_CLICK, Z_INDEX } from 'theme'
|
||||
import { colors } from 'theme/colors'
|
||||
import { opacify } from 'theme/utils'
|
||||
|
||||
import { ReactComponent as ShareIcon } from '../../../assets/svg/share.svg'
|
||||
import { CopyHelper } from '../../../theme'
|
||||
|
||||
const TWITTER_WIDTH = 560
|
||||
const TWITTER_HEIGHT = 480
|
||||
|
||||
const ShareButtonDisplay = styled.div`
|
||||
display: flex;
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const Share = styled(ShareIcon)<{ open: boolean }>`
|
||||
stroke: ${({ theme }) => theme.textSecondary};
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
${ClickableStyle}
|
||||
${({ open }) => open && `opacity: ${OPACITY_CLICK} !important`};
|
||||
`
|
||||
|
||||
const ShareActions = styled.div`
|
||||
position: absolute;
|
||||
z-index: ${Z_INDEX.dropdown};
|
||||
width: 240px;
|
||||
top: 36px;
|
||||
right: 0px;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding: 8px;
|
||||
background-color: ${({ theme }) => theme.backgroundSurface};
|
||||
border: 0.5px solid ${({ theme }) => theme.backgroundOutline};
|
||||
box-shadow: ${({ theme }) => theme.flyoutDropShadow};
|
||||
border-radius: 12px;
|
||||
`
|
||||
const ShareAction = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
gap: 12px;
|
||||
height: 40px;
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
cursor: pointer;
|
||||
:hover {
|
||||
background-color: ${({ theme }) => opacify(10, theme.darkMode ? colors.gray200 : colors.gray300)};
|
||||
}
|
||||
`
|
||||
|
||||
interface TokenInfo {
|
||||
tokenName: string
|
||||
tokenSymbol: string
|
||||
}
|
||||
|
||||
export default function ShareButton(tokenInfo: TokenInfo) {
|
||||
const theme = useTheme()
|
||||
const node = useRef<HTMLDivElement | null>(null)
|
||||
const open = useModalIsOpen(ApplicationModal.SHARE)
|
||||
const toggleShare = useToggleModal(ApplicationModal.SHARE)
|
||||
useOnClickOutside(node, open ? toggleShare : undefined)
|
||||
const positionX = (window.screen.width - TWITTER_WIDTH) / 2
|
||||
const positionY = (window.screen.height - TWITTER_HEIGHT) / 2
|
||||
|
||||
const shareTweet = () => {
|
||||
toggleShare()
|
||||
window.open(
|
||||
`https://twitter.com/intent/tweet?text=Check%20out%20${tokenInfo.tokenName}%20(${tokenInfo.tokenSymbol})%20https://app.uniswap.org/%23/tokens/${tokenInfo.tokenSymbol}%20via%20@uniswap`,
|
||||
'newwindow',
|
||||
`left=${positionX}, top=${positionY}, width=${TWITTER_WIDTH}, height=${TWITTER_HEIGHT}`
|
||||
)
|
||||
}
|
||||
|
||||
const copyHelperRef = useRef<CopyHelperRefType>(null)
|
||||
|
||||
return (
|
||||
<ShareButtonDisplay ref={node}>
|
||||
<Share onClick={toggleShare} aria-label={`ShareOptions`} open={open} />
|
||||
{open && (
|
||||
<ShareActions>
|
||||
<ShareAction onClick={() => copyHelperRef.current?.forceCopy()}>
|
||||
<CopyHelper
|
||||
link
|
||||
color={theme.textPrimary}
|
||||
iconPosition="left"
|
||||
toCopy={window.location.href}
|
||||
ref={copyHelperRef}
|
||||
>
|
||||
Copy Link
|
||||
</CopyHelper>
|
||||
</ShareAction>
|
||||
|
||||
<ShareAction onClick={shareTweet}>
|
||||
<Twitter color={theme.textPrimary} size={20} strokeWidth={1.5} />
|
||||
Share to Twitter
|
||||
</ShareAction>
|
||||
</ShareActions>
|
||||
)}
|
||||
</ShareButtonDisplay>
|
||||
)
|
||||
}
|
||||
@@ -1,21 +1,20 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { ParentSize } from '@visx/responsive'
|
||||
import PriceChart from 'components/Charts/PriceChart'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import PriceChart from 'components/Tokens/TokenDetails/PriceChart'
|
||||
import { VerifiedIcon } from 'components/TokenSafety/TokenSafetyIcon'
|
||||
import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { checkWarning } from 'constants/tokenSafety'
|
||||
import { useCurrency, useIsUserAddedToken, useToken } from 'hooks/Tokens'
|
||||
import { useAtomValue } from 'jotai/utils'
|
||||
import { darken } from 'polished'
|
||||
import { useCallback } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { ArrowLeft, Copy, Heart } from 'react-feather'
|
||||
import { ArrowLeft, Heart } from 'react-feather'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ClickableStyle, CopyContractAddress } from 'theme'
|
||||
|
||||
import { MOBILE_MEDIA_BREAKPOINT } from '../constants'
|
||||
import { favoritesAtom, useToggleFavorite } from '../state'
|
||||
import { ClickFavorited } from '../TokenTable/TokenRow'
|
||||
import Resource from './Resource'
|
||||
@@ -62,10 +61,6 @@ const ContractAddress = styled.button`
|
||||
border: none;
|
||||
padding: 0px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: ${({ theme }) => darken(0.1, theme.textPrimary)};
|
||||
}
|
||||
`
|
||||
export const ContractAddressSection = styled.div`
|
||||
padding: 24px 0px;
|
||||
@@ -114,7 +109,7 @@ export const TokenNameCell = styled.div`
|
||||
`
|
||||
const TokenActions = styled.div`
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
gap: 16px;
|
||||
color: ${({ theme }) => theme.textSecondary};
|
||||
`
|
||||
export const TokenInfoContainer = styled.div`
|
||||
@@ -132,17 +127,6 @@ export const ResourcesContainer = styled.div`
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
`
|
||||
const FullAddress = styled.span`
|
||||
@media only screen and (max-width: ${MOBILE_MEDIA_BREAKPOINT}) {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
const TruncatedAddress = styled.span`
|
||||
display: none;
|
||||
@media only screen and (max-width: ${MOBILE_MEDIA_BREAKPOINT}) {
|
||||
display: flex;
|
||||
}
|
||||
`
|
||||
const NetworkBadge = styled.div<{ networkColor?: string; backgroundColor?: string }>`
|
||||
border-radius: 5px;
|
||||
padding: 4px 8px;
|
||||
@@ -152,9 +136,15 @@ const NetworkBadge = styled.div<{ networkColor?: string; backgroundColor?: strin
|
||||
color: ${({ theme, networkColor }) => networkColor ?? theme.textPrimary};
|
||||
background-color: ${({ theme, backgroundColor }) => backgroundColor ?? theme.backgroundSurface};
|
||||
`
|
||||
const FavoriteIcon = styled(Heart)<{ isFavorited: boolean }>`
|
||||
${ClickableStyle}
|
||||
height: 22px;
|
||||
width: 24px;
|
||||
color: ${({ isFavorited, theme }) => (isFavorited ? theme.accentAction : theme.textSecondary)};
|
||||
fill: ${({ isFavorited, theme }) => (isFavorited ? theme.accentAction : 'transparent')};
|
||||
`
|
||||
|
||||
export default function LoadedTokenDetail({ address }: { address: string }) {
|
||||
const theme = useTheme()
|
||||
const token = useToken(address)
|
||||
const currency = useCurrency(address)
|
||||
const favoriteTokens = useAtomValue<string[]>(favoritesAtom)
|
||||
@@ -184,7 +174,6 @@ export default function LoadedTokenDetail({ address }: { address: string }) {
|
||||
'Ethereum is a decentralized computing platform that uses ETH (Ether) to pay transaction fees (gas). Developers can use Ethereum to run decentralized applications (dApps) and issue new crypto assets, known as Ethereum tokens.'
|
||||
const tokenMarketCap = '23.02B'
|
||||
const tokenVolume = '1.6B'
|
||||
const truncatedTokenAddress = `${address.slice(0, 4)}...${address.slice(-3)}`
|
||||
|
||||
return (
|
||||
<TopArea>
|
||||
@@ -196,7 +185,7 @@ export default function LoadedTokenDetail({ address }: { address: string }) {
|
||||
<TokenNameCell>
|
||||
<CurrencyLogo currency={currency} size={'32px'} />
|
||||
{tokenName} <TokenSymbol>{tokenSymbol}</TokenSymbol>
|
||||
{!warning && <VerifiedIcon size="24px" />}
|
||||
{!warning && <VerifiedIcon size="20px" />}
|
||||
{networkBadgebackgroundColor && (
|
||||
<NetworkBadge networkColor={chainInfo?.color} backgroundColor={networkBadgebackgroundColor}>
|
||||
{networkLabel}
|
||||
@@ -206,11 +195,7 @@ export default function LoadedTokenDetail({ address }: { address: string }) {
|
||||
<TokenActions>
|
||||
<ShareButton tokenName={tokenName} tokenSymbol={tokenSymbol} />
|
||||
<ClickFavorited onClick={toggleFavorite}>
|
||||
<Heart
|
||||
size={15}
|
||||
color={isFavorited ? theme.accentAction : theme.textSecondary}
|
||||
fill={isFavorited ? theme.accentAction : theme.none}
|
||||
/>
|
||||
<FavoriteIcon isFavorited={isFavorited} />
|
||||
</ClickFavorited>
|
||||
</TokenActions>
|
||||
</TokenInfoContainer>
|
||||
@@ -235,7 +220,7 @@ export default function LoadedTokenDetail({ address }: { address: string }) {
|
||||
</Stat>
|
||||
<Stat>
|
||||
{/* TODO: connect to chart's selected time */}
|
||||
1h volume
|
||||
24H volume
|
||||
<StatPrice>${tokenVolume}</StatPrice>
|
||||
</Stat>
|
||||
</StatPair>
|
||||
@@ -253,10 +238,8 @@ export default function LoadedTokenDetail({ address }: { address: string }) {
|
||||
<ContractAddressSection>
|
||||
<Contract>
|
||||
Contract Address
|
||||
<ContractAddress onClick={() => navigator.clipboard.writeText(address)}>
|
||||
<FullAddress>{address}</FullAddress>
|
||||
<TruncatedAddress>{truncatedTokenAddress}</TruncatedAddress>
|
||||
<Copy size={13} color={theme.textSecondary} />
|
||||
<ContractAddress>
|
||||
<CopyContractAddress address={address} />
|
||||
</ContractAddress>
|
||||
</Contract>
|
||||
</ContractAddressSection>
|
||||
@@ -1,7 +1,6 @@
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { useAtom } from 'jotai'
|
||||
import { Heart } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { SMALL_MEDIA_BREAKPOINT } from '../constants'
|
||||
import { showFavoritesAtom } from '../state'
|
||||
@@ -38,7 +37,7 @@ export default function FavoriteButton() {
|
||||
return (
|
||||
<StyledFavoriteButton onClick={() => setShowFavorites(!showFavorites)} active={showFavorites}>
|
||||
<FavoriteButtonContent>
|
||||
<Heart size={17} color={theme.textPrimary} fill={theme.none} />
|
||||
<Heart size={17} color={theme.textPrimary} fill="transparent" />
|
||||
<FavoriteText>Favorites</FavoriteText>
|
||||
</FavoriteButtonContent>
|
||||
</StyledFavoriteButton>
|
||||
@@ -136,14 +136,14 @@ export default function NetworkFilter() {
|
||||
const toggleMenu = useToggleModal(ApplicationModal.NETWORK_FILTER)
|
||||
useOnClickOutside(node, open ? toggleMenu : undefined)
|
||||
const [activeNetwork, setNetwork] = useAtom(filterNetworkAtom)
|
||||
const { label, logoUrl } = getChainInfo(activeNetwork)
|
||||
const { label, circleLogoUrl, logoUrl } = getChainInfo(activeNetwork)
|
||||
|
||||
return (
|
||||
<StyledMenu ref={node}>
|
||||
<StyledMenuButton onClick={toggleMenu} aria-label={`networkFilter`} open={open}>
|
||||
<StyledMenuContent>
|
||||
<NetworkLabel>
|
||||
<Logo src={logoUrl} /> {label}
|
||||
<Logo src={circleLogoUrl ?? logoUrl} /> {label}
|
||||
</NetworkLabel>
|
||||
<Chevron open={open}>
|
||||
{open ? <ChevronUp size={15} viewBox="0 0 24 20" /> : <ChevronDown size={15} viewBox="0 0 24 20" />}
|
||||
@@ -161,7 +161,8 @@ export default function NetworkFilter() {
|
||||
}}
|
||||
>
|
||||
<NetworkLabel>
|
||||
<Logo src={getChainInfo(network).logoUrl} /> {getChainInfo(network).label}
|
||||
<Logo src={getChainInfo(network).circleLogoUrl ?? getChainInfo(network).logoUrl} />
|
||||
{getChainInfo(network).label}
|
||||
</NetworkLabel>
|
||||
{network === activeNetwork && (
|
||||
<CheckContainer>
|
||||
@@ -17,7 +17,7 @@ const SearchInput = styled.input<{ expanded: boolean }>`
|
||||
background-image: ${({ expanded }) => !expanded && `url(${searchIcon})`};
|
||||
background-size: 20px 20px;
|
||||
background-position: 14px center;
|
||||
background-color: ${({ theme }) => theme.none};
|
||||
background-color: 'transparent';
|
||||
border-radius: 12px;
|
||||
border: 1px solid ${({ theme }) => theme.backgroundOutline};
|
||||
height: 100%;
|
||||
@@ -38,7 +38,7 @@ const SearchInput = styled.input<{ expanded: boolean }>`
|
||||
border: none;
|
||||
}
|
||||
::placeholder {
|
||||
color: ${({ expanded, theme }) => (expanded ? theme.textTertiary : theme.none)};
|
||||
color: ${({ expanded, theme }) => (expanded ? theme.textTertiary : 'transparent')};
|
||||
}
|
||||
::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TimePeriod } from 'hooks/useExplorePageQuery'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import { TimePeriod } from 'hooks/useTopTokens'
|
||||
import { useAtom } from 'jotai'
|
||||
import { useRef } from 'react'
|
||||
import { Check, ChevronDown, ChevronUp } from 'react-feather'
|
||||
@@ -4,15 +4,15 @@ import { sendAnalyticsEvent } from 'components/AmplitudeAnalytics'
|
||||
import { EventName } from 'components/AmplitudeAnalytics/constants'
|
||||
import SparklineChart from 'components/Charts/SparklineChart'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { useCurrency, useToken } from 'hooks/Tokens'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { TimePeriod, TokenData } from 'hooks/useTopTokens'
|
||||
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
|
||||
import { useAtom } from 'jotai'
|
||||
import { useAtomValue } from 'jotai/utils'
|
||||
import { ReactNode } from 'react'
|
||||
import { ArrowDown, ArrowDownRight, ArrowUp, ArrowUpRight, Heart } from 'react-feather'
|
||||
import { Link } from 'react-router-dom'
|
||||
import styled from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { formatAmount, formatDollarAmount } from 'utils/formatDollarAmt'
|
||||
|
||||
import {
|
||||
@@ -129,7 +129,7 @@ const StyledHeaderRow = styled(StyledTokenRow)`
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: ${({ theme }) => theme.none};
|
||||
background-color: 'transparent';
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${MAX_WIDTH_MEDIA_BREAKPOINT}) {
|
||||
@@ -281,6 +281,23 @@ const SparkLineLoadingBubble = styled(LongLoadingBubble)`
|
||||
height: 4px;
|
||||
`
|
||||
|
||||
const L2NetworkLogo = styled.div<{ networkUrl?: string }>`
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
background: url(${({ networkUrl }) => networkUrl});
|
||||
background-repeat: no-repeat;
|
||||
background-size: 12px 12px;
|
||||
display: ${({ networkUrl }) => !networkUrl && 'none'};
|
||||
`
|
||||
const LogoContainer = styled.div`
|
||||
position: relative;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
`
|
||||
|
||||
/* formatting for volume with timeframe header display */
|
||||
function getHeaderDisplay(category: string, timeframe: string): string {
|
||||
if (category === Category.volume) return `${TIME_DISPLAYS[timeframe]} ${category}`
|
||||
@@ -436,6 +453,7 @@ export default function LoadedRow({
|
||||
const filterString = useAtomValue(filterStringAtom)
|
||||
const filterNetwork = useAtomValue(filterNetworkAtom)
|
||||
const filterTime = useAtomValue(filterTimeAtom) // filter time period for top tokens table
|
||||
const L2Icon = getChainInfo(filterNetwork).circleLogoUrl
|
||||
|
||||
const tokenPercentChangeInfo = (
|
||||
<>
|
||||
@@ -483,7 +501,10 @@ export default function LoadedRow({
|
||||
listNumber={tokenListIndex + 1}
|
||||
tokenInfo={
|
||||
<ClickableName>
|
||||
<CurrencyLogo currency={currency} />
|
||||
<LogoContainer>
|
||||
<CurrencyLogo currency={currency} />
|
||||
<L2NetworkLogo networkUrl={L2Icon} />
|
||||
</LogoContainer>
|
||||
<TokenInfoCell>
|
||||
<TokenName>{tokenName}</TokenName>
|
||||
<TokenSymbol>{tokenSymbol}</TokenSymbol>
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
showFavoritesAtom,
|
||||
sortCategoryAtom,
|
||||
sortDirectionAtom,
|
||||
} from 'components/Explore/state'
|
||||
} from 'components/Tokens/state'
|
||||
import { useAllTokens } from 'hooks/Tokens'
|
||||
import useTopTokens, { TimePeriod, TokenData } from 'hooks/useTopTokens'
|
||||
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
|
||||
import { useAtomValue } from 'jotai/utils'
|
||||
import { ReactNode, useCallback, useMemo } from 'react'
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
@@ -152,8 +152,13 @@ function LoadingTokenTable() {
|
||||
)
|
||||
}
|
||||
|
||||
export default function TokenTable() {
|
||||
const { data, error, loading } = useTopTokens()
|
||||
interface TokenTableProps {
|
||||
data: TokenData | null
|
||||
error: string | null
|
||||
loading: boolean
|
||||
}
|
||||
|
||||
export default function TokenTable({ data, error, loading }: TokenTableProps) {
|
||||
const showFavorites = useAtomValue<boolean>(showFavoritesAtom)
|
||||
const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom)
|
||||
const topTokenAddresses = data ? Object.keys(data) : []
|
||||
|
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 303 B |
|
Before Width: | Height: | Size: 294 B After Width: | Height: | Size: 294 B |
@@ -1,5 +1,5 @@
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { TimePeriod } from 'hooks/useTopTokens'
|
||||
import { TimePeriod } from 'hooks/useExplorePageQuery'
|
||||
import { atom, useAtom } from 'jotai'
|
||||
import { atomWithReset, atomWithStorage } from 'jotai/utils'
|
||||
import { useCallback } from 'react'
|
||||
@@ -1,5 +1,4 @@
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import styled, { keyframes, useTheme } from 'styled-components/macro'
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 90px;
|
||||
|
||||
@@ -5,11 +5,11 @@ import Badge from 'components/Badge'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { SupportedL2ChainId } from 'constants/chains'
|
||||
import useCurrencyLogoURIs from 'lib/hooks/useCurrencyLogoURIs'
|
||||
import { ReactNode, useCallback, useContext, useState } from 'react'
|
||||
import { ReactNode, useCallback, useState } from 'react'
|
||||
import { AlertCircle, AlertTriangle, ArrowUpCircle, CheckCircle } from 'react-feather'
|
||||
import { Text } from 'rebass'
|
||||
import { useIsTransactionConfirmed, useTransaction } from 'state/transactions/hooks'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { isL2ChainId } from 'utils/chains'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
@@ -95,7 +95,7 @@ function TransactionSubmittedContent({
|
||||
currencyToAdd?: Currency | undefined
|
||||
inline?: boolean // not in modal
|
||||
}) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
const { connector } = useWeb3React()
|
||||
|
||||
@@ -193,7 +193,7 @@ export function ConfirmationModalContent({
|
||||
}
|
||||
|
||||
export function TransactionErrorContent({ message, onDismiss }: { message: ReactNode; onDismiss: () => void }) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
return (
|
||||
<Wrapper>
|
||||
<Section>
|
||||
@@ -238,7 +238,7 @@ function L2Content({
|
||||
pendingText: ReactNode
|
||||
inline?: boolean // not in modal
|
||||
}) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
const transaction = useTransaction(hash)
|
||||
const confirmed = useIsTransactionConfirmed(hash)
|
||||
|
||||
@@ -3,12 +3,12 @@ import { Percent } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import ms from 'ms.macro'
|
||||
import { darken } from 'polished'
|
||||
import { useContext, useState } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
@@ -42,9 +42,9 @@ const FancyButton = styled.button`
|
||||
}
|
||||
`
|
||||
|
||||
const Option = styled(FancyButton)<{ active: boolean; phase0Flag: boolean }>`
|
||||
const Option = styled(FancyButton)<{ active: boolean; redesignFlag: boolean }>`
|
||||
margin-right: 8px;
|
||||
border-radius: ${({ phase0Flag }) => phase0Flag && '12px'};
|
||||
border-radius: ${({ redesignFlag }) => redesignFlag && '12px'};
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -52,10 +52,10 @@ const Option = styled(FancyButton)<{ active: boolean; phase0Flag: boolean }>`
|
||||
color: ${({ active, theme }) => (active ? theme.deprecated_white : theme.deprecated_text1)};
|
||||
`
|
||||
|
||||
const Input = styled.input<{ phase0Flag: boolean }>`
|
||||
const Input = styled.input<{ redesignFlag: boolean }>`
|
||||
background: ${({ theme }) => theme.deprecated_bg1};
|
||||
font-size: 16px;
|
||||
border-radius: ${({ phase0Flag }) => phase0Flag && '12px'};
|
||||
border-radius: ${({ redesignFlag }) => redesignFlag && '12px'};
|
||||
width: auto;
|
||||
outline: none;
|
||||
&::-webkit-outer-spin-button,
|
||||
@@ -66,11 +66,11 @@ const Input = styled.input<{ phase0Flag: boolean }>`
|
||||
text-align: right;
|
||||
`
|
||||
|
||||
const OptionCustom = styled(FancyButton)<{ active?: boolean; warning?: boolean; phase0Flag: boolean }>`
|
||||
const OptionCustom = styled(FancyButton)<{ active?: boolean; warning?: boolean; redesignFlag: boolean }>`
|
||||
height: 2rem;
|
||||
position: relative;
|
||||
padding: 0 0.75rem;
|
||||
border-radius: ${({ phase0Flag }) => phase0Flag && '12px'};
|
||||
border-radius: ${({ redesignFlag }) => redesignFlag && '12px'};
|
||||
flex: 1;
|
||||
border: ${({ theme, active, warning }) =>
|
||||
active
|
||||
@@ -104,9 +104,9 @@ const THREE_DAYS_IN_SECONDS = ms`3 days` / 1000
|
||||
|
||||
export default function TransactionSettings({ placeholderSlippage }: TransactionSettingsProps) {
|
||||
const { chainId } = useWeb3React()
|
||||
const theme = useContext(ThemeContext)
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const theme = useTheme()
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
const userSlippageTolerance = useUserSlippageTolerance()
|
||||
const setUserSlippageTolerance = useSetUserSlippageTolerance()
|
||||
@@ -182,7 +182,7 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
</RowFixed>
|
||||
<RowBetween>
|
||||
<Option
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
onClick={() => {
|
||||
parseSlippageInput('')
|
||||
}}
|
||||
@@ -191,7 +191,7 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
<Trans>Auto</Trans>
|
||||
</Option>
|
||||
<OptionCustom
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
active={userSlippageTolerance !== 'auto'}
|
||||
warning={!!slippageError}
|
||||
tabIndex={-1}
|
||||
@@ -205,7 +205,7 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
</SlippageEmojiContainer>
|
||||
) : null}
|
||||
<Input
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
placeholder={placeholderSlippage.toFixed(2)}
|
||||
value={
|
||||
slippageInput.length > 0
|
||||
@@ -259,10 +259,10 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
style={{ width: '80px' }}
|
||||
warning={!!deadlineError}
|
||||
tabIndex={-1}
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
>
|
||||
<Input
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
placeholder={(DEFAULT_DEADLINE_FROM_NOW / 60).toString()}
|
||||
value={
|
||||
deadlineInput.length > 0
|
||||
|
||||
@@ -1,21 +1,38 @@
|
||||
import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import React from 'react'
|
||||
import { Check } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { ExternalLink } from '../../theme'
|
||||
|
||||
const InfoCard = styled.button<{ isActive?: boolean }>`
|
||||
background-color: ${({ theme, isActive }) => (isActive ? theme.deprecated_bg3 : theme.deprecated_bg2)};
|
||||
const InfoCard = styled.button<{ isActive?: boolean; redesignFlag?: boolean }>`
|
||||
background-color: ${({ theme, isActive, redesignFlag }) =>
|
||||
redesignFlag ? theme.backgroundInteractive : isActive ? theme.deprecated_bg3 : theme.deprecated_bg2};
|
||||
padding: 1rem;
|
||||
outline: none;
|
||||
border: 1px solid;
|
||||
border-radius: 12px;
|
||||
width: 100% !important;
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 1px ${({ theme }) => theme.deprecated_primary1};
|
||||
box-shadow: ${({ theme, redesignFlag }) => !redesignFlag && `0 0 0 1px ${theme.deprecated_primary1}`};
|
||||
background-color: ${({ theme, redesignFlag }) => redesignFlag && theme.hoverState};
|
||||
}
|
||||
border-color: ${({ theme, isActive }) => (isActive ? 'transparent' : theme.deprecated_bg3)};
|
||||
border-color: ${({ theme, isActive, redesignFlag }) =>
|
||||
redesignFlag ? (isActive ? theme.accentActive : 'transparent') : isActive ? 'transparent' : theme.deprecated_bg3};
|
||||
`
|
||||
|
||||
const CheckIcon = styled(Check)`
|
||||
${({ theme }) => theme.flexColumnNoWrap};
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: ${({ theme }) => theme.accentAction};
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
align-items: flex-end;
|
||||
`};
|
||||
`
|
||||
|
||||
const OptionCard = styled(InfoCard as any)`
|
||||
@@ -33,11 +50,18 @@ const OptionCardLeft = styled.div`
|
||||
height: 100%;
|
||||
`
|
||||
|
||||
const OptionCardClickable = styled(OptionCard as any)<{ clickable?: boolean }>`
|
||||
const OptionCardClickable = styled(OptionCard as any)<{
|
||||
active?: boolean
|
||||
clickable?: boolean
|
||||
redesignFlag?: boolean
|
||||
}>`
|
||||
margin-top: 0;
|
||||
border: ${({ active, theme }) => active && `1px solid ${theme.accentActive}`};
|
||||
&:hover {
|
||||
cursor: ${({ clickable }) => (clickable ? 'pointer' : '')};
|
||||
border: ${({ clickable, theme }) => (clickable ? `1px solid ${theme.deprecated_primary1}` : ``)};
|
||||
cursor: ${({ clickable }) => clickable && 'pointer'};
|
||||
background-color: ${({ theme, redesignFlag }) => redesignFlag && theme.hoverState};
|
||||
border: ${({ clickable, redesignFlag, theme }) =>
|
||||
clickable && !redesignFlag && `1px solid ${theme.deprecated_primary1}`};
|
||||
}
|
||||
opacity: ${({ disabled }) => (disabled ? '0.5' : '1')};
|
||||
`
|
||||
@@ -63,12 +87,14 @@ const CircleWrapper = styled.div`
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const HeaderText = styled.div`
|
||||
const HeaderText = styled.div<{ redesignFlag?: boolean }>`
|
||||
${({ theme }) => theme.flexRowNoWrap};
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: ${(props) =>
|
||||
props.color === 'blue' ? ({ theme }) => theme.deprecated_primary1 : ({ theme }) => theme.deprecated_text1};
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
font-size: ${({ redesignFlag }) => (redesignFlag ? '16px' : '1rem')};
|
||||
font-weight: ${({ redesignFlag }) => (redesignFlag ? '600' : '500')};
|
||||
`
|
||||
|
||||
const SubHeader = styled.div`
|
||||
@@ -77,7 +103,7 @@ const SubHeader = styled.div`
|
||||
font-size: 12px;
|
||||
`
|
||||
|
||||
const IconWrapper = styled.div<{ size?: number | null }>`
|
||||
const IconWrapperDeprecated = styled.div<{ size?: number | null }>`
|
||||
${({ theme }) => theme.flexColumnNoWrap};
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -91,6 +117,21 @@ const IconWrapper = styled.div<{ size?: number | null }>`
|
||||
`};
|
||||
`
|
||||
|
||||
const IconWrapper = styled.div<{ size?: number | null }>`
|
||||
${({ theme }) => theme.flexColumnNoWrap};
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-right: 12px;
|
||||
& > img,
|
||||
span {
|
||||
height: ${({ size }) => (size ? size + 'px' : '28px')};
|
||||
width: ${({ size }) => (size ? size + 'px' : '28px')};
|
||||
}
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
align-items: flex-end;
|
||||
`};
|
||||
`
|
||||
|
||||
export default function Option({
|
||||
link = null,
|
||||
clickable = true,
|
||||
@@ -114,6 +155,9 @@ export default function Option({
|
||||
isActive?: boolean
|
||||
id: string
|
||||
}) {
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
const content = (
|
||||
<TraceEvent
|
||||
events={[Event.onClick]}
|
||||
@@ -121,32 +165,53 @@ export default function Option({
|
||||
properties={{ wallet_type: header }}
|
||||
element={ElementName.WALLET_TYPE_OPTION}
|
||||
>
|
||||
<OptionCardClickable
|
||||
id={id}
|
||||
onClick={onClick}
|
||||
clickable={clickable && !isActive}
|
||||
active={isActive}
|
||||
data-testid="wallet-modal-option"
|
||||
>
|
||||
<OptionCardLeft>
|
||||
<HeaderText color={color}>
|
||||
{isActive ? (
|
||||
<CircleWrapper>
|
||||
<GreenCircle>
|
||||
<div />
|
||||
</GreenCircle>
|
||||
</CircleWrapper>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
{header}
|
||||
</HeaderText>
|
||||
{subheader && <SubHeader>{subheader}</SubHeader>}
|
||||
</OptionCardLeft>
|
||||
<IconWrapper size={size}>
|
||||
<img src={icon} alt={'Icon'} />
|
||||
</IconWrapper>
|
||||
</OptionCardClickable>
|
||||
{redesignFlagEnabled ? (
|
||||
<OptionCardClickable
|
||||
id={id}
|
||||
onClick={onClick}
|
||||
clickable={clickable && !isActive}
|
||||
active={isActive}
|
||||
redesignFlag={true}
|
||||
data-testid="wallet-modal-option"
|
||||
>
|
||||
<OptionCardLeft>
|
||||
<HeaderText color={color} redesignFlag={true}>
|
||||
<IconWrapper size={size}>
|
||||
<img src={icon} alt={'Icon'} />
|
||||
</IconWrapper>
|
||||
{header}
|
||||
</HeaderText>
|
||||
{subheader && <SubHeader>{subheader}</SubHeader>}
|
||||
</OptionCardLeft>
|
||||
{isActive && <CheckIcon />}
|
||||
</OptionCardClickable>
|
||||
) : (
|
||||
<OptionCardClickable
|
||||
id={id}
|
||||
onClick={onClick}
|
||||
clickable={clickable && !isActive}
|
||||
active={isActive}
|
||||
redesignFlag={false}
|
||||
data-testid="wallet-modal-option"
|
||||
>
|
||||
<OptionCardLeft>
|
||||
<HeaderText color={color} redesignFlag={false}>
|
||||
{isActive && (
|
||||
<CircleWrapper>
|
||||
<GreenCircle>
|
||||
<div />
|
||||
</GreenCircle>
|
||||
</CircleWrapper>
|
||||
)}
|
||||
{header}
|
||||
</HeaderText>
|
||||
{subheader && <SubHeader>{subheader}</SubHeader>}
|
||||
</OptionCardLeft>
|
||||
<IconWrapperDeprecated size={size}>
|
||||
<img src={icon} alt={'Icon'} />
|
||||
</IconWrapperDeprecated>
|
||||
</OptionCardClickable>
|
||||
)}
|
||||
</TraceEvent>
|
||||
)
|
||||
if (link) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Connector } from '@web3-react/types'
|
||||
import { ButtonEmpty, ButtonPrimary } from 'components/Button'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
@@ -16,6 +18,21 @@ const PendingSection = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const WaitingToConnectSection = styled.div`
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`
|
||||
|
||||
const AlertTriangleIcon = styled(AlertTriangle)`
|
||||
width: 25%;
|
||||
height: 25%;
|
||||
stroke-width: 1;
|
||||
padding-bottom: 2rem;
|
||||
color: ${({ theme }) => theme.accentCritical};
|
||||
`
|
||||
|
||||
const LoaderContainer = styled.div`
|
||||
margin: 16px 0;
|
||||
${({ theme }) => theme.flexRowNoWrap};
|
||||
@@ -57,7 +74,58 @@ export default function PendingView({
|
||||
tryActivation: (connector: Connector) => void
|
||||
openOptions: () => void
|
||||
}) {
|
||||
return (
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
return redesignFlagEnabled ? (
|
||||
<PendingSection>
|
||||
<LoadingMessage>
|
||||
<LoadingWrapper>
|
||||
{error ? (
|
||||
<ErrorGroup>
|
||||
<AlertTriangleIcon />
|
||||
<ThemedText.MediumHeader marginBottom={12}>
|
||||
<Trans>Error connecting</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<ThemedText.BodyPrimary fontSize={16} marginBottom={36} textAlign="center">
|
||||
<Trans>
|
||||
The connection attempt failed. Please click try again and follow the steps to connect in your wallet.
|
||||
</Trans>
|
||||
</ThemedText.BodyPrimary>
|
||||
<ButtonPrimary
|
||||
$borderRadius="12px"
|
||||
redesignFlag={true}
|
||||
onClick={() => {
|
||||
tryActivation(connector)
|
||||
}}
|
||||
>
|
||||
<Trans>Try Again</Trans>
|
||||
</ButtonPrimary>
|
||||
<ButtonEmpty width="fit-content" padding="0" marginTop={20}>
|
||||
<ThemedText.Link onClick={openOptions}>
|
||||
<Trans>Back to wallet selection</Trans>
|
||||
</ThemedText.Link>
|
||||
</ButtonEmpty>
|
||||
</ErrorGroup>
|
||||
) : (
|
||||
<>
|
||||
<WaitingToConnectSection>
|
||||
<LoaderContainer style={{ padding: '16px 0px' }}>
|
||||
<Loader redesignFlag={true} strokeWidth={0.8} size="100px" />
|
||||
</LoaderContainer>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Waiting to connect</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<ThemedText.SubHeader style={{ paddingTop: '8px' }}>
|
||||
<Trans>Confirm this connection in your wallet</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
</WaitingToConnectSection>
|
||||
</>
|
||||
)}
|
||||
</LoadingWrapper>
|
||||
</LoadingMessage>
|
||||
</PendingSection>
|
||||
) : (
|
||||
<PendingSection>
|
||||
<LoadingMessage>
|
||||
<LoadingWrapper>
|
||||
|
||||
@@ -15,6 +15,7 @@ import { AutoColumn } from 'components/Column'
|
||||
import { AutoRow } from 'components/Row'
|
||||
import { ConnectionType } from 'connection'
|
||||
import { getConnection, getConnectionName, getIsCoinbaseWallet, getIsInjected, getIsMetaMask } from 'connection/utils'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { useStablecoinValue } from 'hooks/useStablecoinPrice'
|
||||
import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance'
|
||||
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
||||
@@ -59,25 +60,30 @@ const CloseColor = styled(Close)`
|
||||
}
|
||||
`
|
||||
|
||||
const Wrapper = styled.div`
|
||||
const Wrapper = styled.div<{ redesignFlag?: boolean }>`
|
||||
${({ theme }) => theme.flexColumnNoWrap}
|
||||
background-color: ${({ redesignFlag, theme }) => redesignFlag && theme.backgroundSurface};
|
||||
outline: ${({ theme, redesignFlag }) => redesignFlag && `1px solid ${theme.backgroundOutline}`};
|
||||
box-shadow: ${({ redesignFlag, theme }) => redesignFlag && theme.deepShadow};
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
const HeaderRow = styled.div`
|
||||
const HeaderRow = styled.div<{ redesignFlag?: boolean }>`
|
||||
${({ theme }) => theme.flexRowNoWrap};
|
||||
padding: 1rem 1rem;
|
||||
font-weight: 500;
|
||||
font-weight: ${({ redesignFlag }) => (redesignFlag ? '600' : '500')};
|
||||
size: ${({ redesignFlag }) => redesignFlag && '16px'};
|
||||
color: ${(props) => (props.color === 'blue' ? ({ theme }) => theme.deprecated_primary1 : 'inherit')};
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
padding: 1rem;
|
||||
`};
|
||||
`
|
||||
|
||||
const ContentWrapper = styled.div`
|
||||
background-color: ${({ theme }) => theme.deprecated_bg0};
|
||||
const ContentWrapper = styled.div<{ redesignFlag?: boolean }>`
|
||||
background-color: ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundSurface : theme.deprecated_bg0)};
|
||||
border: ${({ theme, redesignFlag }) => redesignFlag && `1px solid ${theme.backgroundOutline}`};
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
border-bottom-left-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
@@ -183,6 +189,8 @@ export default function WalletModal({
|
||||
const { connector, account, chainId } = useWeb3React()
|
||||
const [connectedWallets, addWalletToConnectedWallets] = useConnectedWallets()
|
||||
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
const [walletView, setWalletView] = useState(WALLET_VIEWS.ACCOUNT)
|
||||
const [lastActiveWalletAddress, setLastActiveWalletAddress] = useState<string | undefined>(account)
|
||||
const [shouldLogWalletBalances, setShouldLogWalletBalances] = useState(false)
|
||||
@@ -357,9 +365,7 @@ export default function WalletModal({
|
||||
}
|
||||
|
||||
let headerRow
|
||||
if (walletView === WALLET_VIEWS.PENDING) {
|
||||
headerRow = null
|
||||
} else if (walletView === WALLET_VIEWS.ACCOUNT || !!account) {
|
||||
if (walletView === WALLET_VIEWS.PENDING || walletView === WALLET_VIEWS.ACCOUNT || !!account) {
|
||||
headerRow = (
|
||||
<HeaderRow color="blue">
|
||||
<HoverText onClick={() => setWalletView(account ? WALLET_VIEWS.ACCOUNT : WALLET_VIEWS.OPTIONS)}>
|
||||
@@ -369,7 +375,7 @@ export default function WalletModal({
|
||||
)
|
||||
} else {
|
||||
headerRow = (
|
||||
<HeaderRow>
|
||||
<HeaderRow redesignFlag={redesignFlagEnabled}>
|
||||
<HoverText>
|
||||
<Trans>Connect a wallet</Trans>
|
||||
</HoverText>
|
||||
@@ -377,6 +383,39 @@ export default function WalletModal({
|
||||
)
|
||||
}
|
||||
|
||||
function getTermsOfService(redesignFlagEnabled: boolean) {
|
||||
return redesignFlagEnabled ? (
|
||||
<AutoRow style={{ flexWrap: 'nowrap', padding: '4px 16px' }}>
|
||||
<ThemedText.BodySecondary fontSize={12}>
|
||||
<Trans>
|
||||
By connecting a wallet, you agree to Uniswap Labs’{' '}
|
||||
<ExternalLink href="https://uniswap.org/terms-of-service/">Terms of Service</ExternalLink> and acknowledge
|
||||
that you have read and understand the Uniswap{' '}
|
||||
<ExternalLink href="https://uniswap.org/disclaimer/">Protocol Disclaimer</ExternalLink>.
|
||||
</Trans>
|
||||
</ThemedText.BodySecondary>
|
||||
</AutoRow>
|
||||
) : (
|
||||
<LightCard>
|
||||
<AutoRow style={{ flexWrap: 'nowrap' }}>
|
||||
<ThemedText.DeprecatedBody fontSize={12}>
|
||||
<Trans>
|
||||
By connecting a wallet, you agree to Uniswap Labs’{' '}
|
||||
<ExternalLink style={{ textDecoration: 'underline' }} href="https://uniswap.org/terms-of-service/">
|
||||
Terms of Service
|
||||
</ExternalLink>{' '}
|
||||
and acknowledge that you have read and understand the Uniswap{' '}
|
||||
<ExternalLink style={{ textDecoration: 'underline' }} href="https://uniswap.org/disclaimer/">
|
||||
Protocol Disclaimer
|
||||
</ExternalLink>
|
||||
.
|
||||
</Trans>
|
||||
</ThemedText.DeprecatedBody>
|
||||
</AutoRow>
|
||||
</LightCard>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<UpperSection>
|
||||
<CloseIcon onClick={toggleWalletModal}>
|
||||
@@ -394,28 +433,7 @@ export default function WalletModal({
|
||||
/>
|
||||
)}
|
||||
{walletView !== WALLET_VIEWS.PENDING && <OptionGrid data-testid="option-grid">{getOptions()}</OptionGrid>}
|
||||
{!pendingError && (
|
||||
<LightCard>
|
||||
<AutoRow style={{ flexWrap: 'nowrap' }}>
|
||||
<ThemedText.DeprecatedBody fontSize={12}>
|
||||
<Trans>
|
||||
By connecting a wallet, you agree to Uniswap Labs’{' '}
|
||||
<ExternalLink
|
||||
style={{ textDecoration: 'underline' }}
|
||||
href="https://uniswap.org/terms-of-service/"
|
||||
>
|
||||
Terms of Service
|
||||
</ExternalLink>{' '}
|
||||
and acknowledge that you have read and understand the Uniswap{' '}
|
||||
<ExternalLink style={{ textDecoration: 'underline' }} href="https://uniswap.org/disclaimer/">
|
||||
Protocol Disclaimer
|
||||
</ExternalLink>
|
||||
.
|
||||
</Trans>
|
||||
</ThemedText.DeprecatedBody>
|
||||
</AutoRow>
|
||||
</LightCard>
|
||||
)}
|
||||
{!pendingError && getTermsOfService(redesignFlagEnabled)}
|
||||
</AutoColumn>
|
||||
</ContentWrapper>
|
||||
</UpperSection>
|
||||
@@ -423,8 +441,14 @@ export default function WalletModal({
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={walletModalOpen} onDismiss={toggleWalletModal} minHeight={false} maxHeight={90}>
|
||||
<Wrapper>{getModalContent()}</Wrapper>
|
||||
<Modal
|
||||
isOpen={walletModalOpen}
|
||||
onDismiss={toggleWalletModal}
|
||||
minHeight={false}
|
||||
maxHeight={90}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
>
|
||||
<Wrapper redesignFlag={redesignFlagEnabled}>{getModalContent()}</Wrapper>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import { useWeb3React } from '@web3-react/core'
|
||||
import Card from 'components/Card'
|
||||
import { LoadingRows } from 'components/Loader/styled'
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
||||
import { useContext, useMemo } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
import { Separator, ThemedText } from '../../theme'
|
||||
import { computeRealizedPriceImpact } from '../../utils/prices'
|
||||
@@ -52,11 +52,11 @@ export function AdvancedSwapDetails({
|
||||
syncing = false,
|
||||
hideInfoTooltips = false,
|
||||
}: AdvancedSwapDetailsProps) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
const { chainId } = useWeb3React()
|
||||
const nativeCurrency = useNativeCurrency()
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
const { expectedOutputAmount, priceImpact } = useMemo(() => {
|
||||
return {
|
||||
@@ -109,7 +109,7 @@ export function AdvancedSwapDetails({
|
||||
</ThemedText.DeprecatedBlack>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
<Separator phase0Flag={phase0FlagEnabled} />
|
||||
<Separator redesignFlag={redesignFlagEnabled} />
|
||||
<RowBetween>
|
||||
<RowFixed style={{ marginRight: '20px' }}>
|
||||
<MouseoverTooltip
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { OutlineCard } from 'components/Card'
|
||||
import { useContext } from 'react'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { opacify } from 'theme/utils'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
@@ -21,7 +20,7 @@ interface PriceImpactWarningProps {
|
||||
}
|
||||
|
||||
export default function PriceImpactWarning({ priceImpact }: PriceImpactWarningProps) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<StyledCard>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { LoadingOpacityContainer } from 'components/Loader/styled'
|
||||
import Row, { RowBetween, RowFixed } from 'components/Row'
|
||||
import { MouseoverTooltipContent } from 'components/Tooltip'
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
|
||||
import { Phase0Variant, usePhase0Flag } from 'featureFlags/flags/phase0'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { useState } from 'react'
|
||||
import { ChevronDown, Info } from 'react-feather'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
@@ -35,20 +35,21 @@ const StyledInfoIcon = styled(Info)`
|
||||
color: ${({ theme }) => theme.deprecated_text3};
|
||||
`
|
||||
|
||||
const StyledCard = styled(OutlineCard)<{ phase0Flag: boolean }>`
|
||||
const StyledCard = styled(OutlineCard)<{ redesignFlag: boolean }>`
|
||||
padding: 12px;
|
||||
border: 1px solid ${({ theme, phase0Flag }) => (phase0Flag ? theme.backgroundOutline : theme.deprecated_bg3)};
|
||||
border: 1px solid ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundOutline : theme.deprecated_bg3)};
|
||||
`
|
||||
|
||||
const StyledHeaderRow = styled(RowBetween)<{ disabled: boolean; open: boolean; phase0Flag: boolean }>`
|
||||
padding: ${({ phase0Flag }) => (phase0Flag ? '8px 0px 0px 0px' : '4px 8px')};
|
||||
background-color: ${({ open, theme, phase0Flag }) => (open && !phase0Flag ? theme.deprecated_bg1 : theme.none)};
|
||||
const StyledHeaderRow = styled(RowBetween)<{ disabled: boolean; open: boolean; redesignFlag: boolean }>`
|
||||
padding: ${({ redesignFlag }) => (redesignFlag ? '8px 0px 0px 0px' : '4px 8px')};
|
||||
background-color: ${({ open, theme, redesignFlag }) =>
|
||||
open && !redesignFlag ? theme.deprecated_bg1 : 'transparent'};
|
||||
align-items: center;
|
||||
border-top: 1px solid ${({ theme, phase0Flag }) => (phase0Flag ? theme.backgroundOutline : theme.none)};
|
||||
margin-top: ${({ phase0Flag }) => phase0Flag && '8px'};
|
||||
border-top: 1px solid ${({ theme, redesignFlag }) => (redesignFlag ? theme.backgroundOutline : 'transparent')};
|
||||
margin-top: ${({ redesignFlag }) => redesignFlag && '8px'};
|
||||
cursor: ${({ disabled }) => (disabled ? 'initial' : 'pointer')};
|
||||
min-height: 40px;
|
||||
border-radius: ${({ phase0Flag }) => !phase0Flag && '12px'};
|
||||
border-radius: ${({ redesignFlag }) => !redesignFlag && '12px'};
|
||||
`
|
||||
|
||||
const RotatingArrow = styled(ChevronDown)<{ open?: boolean }>`
|
||||
@@ -128,8 +129,8 @@ export default function SwapDetailsDropdown({
|
||||
const theme = useTheme()
|
||||
const { chainId } = useWeb3React()
|
||||
const [showDetails, setShowDetails] = useState(false)
|
||||
const phase0Flag = usePhase0Flag()
|
||||
const phase0FlagEnabled = phase0Flag === Phase0Variant.Enabled
|
||||
const redesignFlag = useRedesignFlag()
|
||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||
|
||||
return (
|
||||
<Wrapper style={{ marginTop: '8px' }}>
|
||||
@@ -141,7 +142,7 @@ export default function SwapDetailsDropdown({
|
||||
shouldLogImpression={!showDetails}
|
||||
>
|
||||
<StyledHeaderRow
|
||||
phase0Flag={phase0FlagEnabled}
|
||||
redesignFlag={redesignFlagEnabled}
|
||||
onClick={() => setShowDetails(!showDetails)}
|
||||
disabled={!trade}
|
||||
open={showDetails}
|
||||
@@ -212,7 +213,7 @@ export default function SwapDetailsDropdown({
|
||||
<AnimatedDropdown open={showDetails}>
|
||||
<AutoColumn gap={'8px'} style={{ padding: '0', paddingBottom: '8px' }}>
|
||||
{trade ? (
|
||||
<StyledCard phase0Flag={phase0FlagEnabled}>
|
||||
<StyledCard redesignFlag={redesignFlagEnabled}>
|
||||
<AdvancedSwapDetails trade={trade} allowedSlippage={allowedSlippage} syncing={syncing} />
|
||||
</StyledCard>
|
||||
) : null}
|
||||
|
||||