Compare commits

..

43 Commits

Author SHA1 Message Date
Kaylee George
1944fe4029 fix: width of widget and network balances on token details (#4392)
* fix width

* nits

* width var

* nit

* px fix

Co-authored-by: Vignesh Mohankumar <me@vig.xyz>
2022-08-17 19:02:24 -04:00
lynn
9921736102 fix: add missing colon to end of drop shadow color (#4394)
init
2022-08-17 18:43:14 -04:00
lynn
11aa641dbc feat: wallet connect redesign (#4381)
* init

* pending and failed states

* simplify

* fixes in respond to fred nits

* update overlay
2022-08-17 18:15:53 -04:00
Kaylee George
2f3290592b feat: add L2 network label to Explore token row (#4361)
* initial

* add L2 badge

* meh

* png updates

* fix icons

* naming

* nits

* case

* rename

* rm
2022-08-17 17:35:25 -04:00
github-actions[bot]
7b3fe73474 chore(i18n): new Crowdin translations (#4378)
chore(i18n): synchronize translations from crowdin [skip ci]

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-08-17 13:27:37 -07:00
Kaylee George
4237354bb7 chore: rename Explore directory to Tokens (#4388)
* rename

* move file
2022-08-17 15:18:26 -04:00
Jack Short
f7354c9842 refactor: removes BodyWrapper padding (#4375)
* fix: removing bodywrapper padding for phase1

* reverting to previous version and adjusting padding across pages appropriately

* adjusting padding on add liquidity page

* prettier changes

* missed semicolon
2022-08-17 14:35:47 -04:00
Charles Bachmeier
1636786af8 feat: add the phase0 chain switcher (#4376)
* feat: add phase0 chain switcher

* update styles

* add chain switcher files

* remove unneeded eslint disable

* add Celo and remove unneeded null check

* remove old comment

* fix mobile routing

Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
2022-08-17 11:24:56 -07:00
aballerr
de0a716f41 chore: Usetheme hook fix (#4387)
* fixing hook


Co-authored-by: Alex Ball <alexball@UNISWAP-MAC-038.fios-router.home>
2022-08-17 17:53:46 +00:00
Zach Pomerantz
9f108c406b chore: clean up theme usage (#4335)
* chore: clean up DefaultTheme usage

* chore: simplify useTheme usage

* chore: consolidate multi-line imports
2022-08-17 16:55:58 +00:00
Vignesh Mohankumar
5346d13674 chore: rename flag explore -> tokens (#4386) 2022-08-17 16:43:21 +00:00
Charles Bachmeier
d054079eeb feat: add routing functionality to navbar (#4374)
* feat: add routingfunctionality to navbar

* update colors

* rename and pass strings directly

* rename symbol

* rename props

* better symbol name for mobile link

* more isPoolActive

Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
2022-08-17 16:31:30 +00:00
Vignesh Mohankumar
fe6324f84d feat: remove v2, v3 swap router (#4372)
* remove v3 router

* rm v2

* unused

* remove anytrade

* unused

* rm shared

* remove optimized trade

* celo fix
2022-08-17 16:05:16 +00:00
Vignesh Mohankumar
4a70eb5956 fix: rename /explore to /tokens (#4385)
* fix: rename /explore to /tokens

* name

* tokens

* oops
2022-08-17 16:05:01 +00:00
Vignesh Mohankumar
1a7b86d155 chore: remove unused exports (#4380) 2022-08-17 11:45:45 -04:00
Vignesh Mohankumar
f66f8c4d59 fix: undo polygon auto-slippage changes (#4379) 2022-08-17 11:37:54 -04:00
Jack Short
1a9c3c3632 feat: add a feature flagged blank collections page (#4371) 2022-08-17 10:42:27 -04:00
cartcrom
91f4892b0c feat: integrate relay (#4320)
* setup relay compiler
* refactored to use polling interval, fixed PR comments
* fixes, readded uninitialized state for liquidity chart
* updated cypress test
* reorganized graphql files into src/graphql
2022-08-16 20:01:12 -04:00
cartcrom
d6d0a98afe fix: chart design fixes & style updates (#4341)
* removed ticks outside of hover
* simplifying copyhelper
* finished implementing fred's feedback
* addressed PR comments
* fixed more of fred's feedback
2022-08-16 19:59:02 -04:00
Kaylee George
8efc5af2bc fix: update feature flag modal design & add headers (#4370)
* initial

* progress

* sike no progress

* design updates

* fix header

* remove colon

* add flag
2022-08-16 19:10:56 +00:00
Zach Pomerantz
104b62f4d8 feat: send web vitals (#4366) 2022-08-16 11:26:15 -07:00
Charles Bachmeier
8e9dbe31fa feat: add a feature flagged blank navbar (#4365)
* add some initial infra for blank navbar

* add blank navbar

* add new files

* use web3status

* remove unused mobile flag

* remove colors

Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
2022-08-16 17:46:50 +00:00
Jordan Frankfurt
cf0afa01c8 feat(widget): light and dark themes (#4367)
feat(widget): light and dark themes:
2022-08-16 12:20:23 -04:00
Vignesh Mohankumar
c5b67ac60b refactor: deprecate theme.none (#4362) 2022-08-16 09:05:43 -07:00
Charles Bachmeier
110c6fc08f feat: add in common nft components (#4363)
* add in common genie components

* update import and run linter

* better event type handling

* rotate 360

Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
2022-08-16 05:38:27 -07:00
Vignesh Mohankumar
f349ecdd3c chore: remove selectedWalletBackfilled (#4283)
* remove selectedWalletBackfilled

* FIX
2022-08-15 15:39:16 -07:00
lynn
57fb481da9 chore: update amplitude version (#4358)
* update amplitude version

* fix amplitude analytics index file to work with new version

* remove extraneous comment
2022-08-15 18:02:02 -04:00
Charles Bachmeier
5871e0afe1 feat: add navbar feature flag and small style update (#4364)
add navbar feature flag and small style update

Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
2022-08-15 21:34:25 +00:00
Jordan Frankfurt
281879ea98 chore: dont-send-test-data-to-test-amplitude (#4360)
* chore: dont-send-test-data-to-test-amplitude

* chore: dont-send-test-data-to-test-amplitude
2022-08-15 15:37:05 -05:00
Zach Pomerantz
b623380dd0 feat: show widget in token details (#4337)
* build: install widgets

* feat: show widget in token details

* basic integration props

* ts fix and update widget to 2.1.1

* url map

* yarn-deduplicate --strategy=highest

Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
2022-08-15 15:12:59 -05:00
Vignesh Mohankumar
7645094df6 refactor: move useSyncChainQuery to NetworkSelector (#4353) 2022-08-15 12:06:18 -07:00
Vignesh Mohankumar
733b1885ff fix: await selectChain before closing modal (#4354) 2022-08-15 12:05:55 -07:00
Vignesh Mohankumar
7adbb1e0af fix: use tokenSafety flag in Modal (#4359) 2022-08-15 18:59:30 +00:00
Jordan Frankfurt
6d5967c981 chore: add test key to .env (#4357)
add test key to .env
2022-08-15 14:29:30 -04:00
lynn
b15f2a2bb6 feat: fail gracefully when amplitude api key is not present (#4355)
init
2022-08-15 18:00:37 +00:00
Vignesh Mohankumar
3cc0a41e50 refactor: split ChainId useEffects (#4348)
* split out useOnSelectChain, useSyncChainQuery

* use chain query sync

* lint

* rename

* move variables
2022-08-15 10:20:26 -07:00
Noah Zinsmeister
4abdca9fdd fix: improve calldata formatting (#4352)
improve calldata formatting
2022-08-15 12:33:23 -04:00
lynn
99ef9366d6 feat: amplitude production sdk changes (#4312)
* init

* error change

* use isProduction vs isDevelopment to include vercel
2022-08-15 12:24:31 -04:00
github-actions[bot]
235ee5dff9 chore(i18n): new Crowdin translations (#4321)
chore(i18n): synchronize translations from crowdin [skip ci]

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-08-15 11:20:31 -04:00
lynn
20f25803d4 feat: Add favorite tokens from localstorage to /explore top tokens data query (#4351)
* init

* move to explore page level

* remove extraneous useTopTokens hook replaced by useExplorePageQuery
2022-08-15 11:13:36 -04:00
Vignesh Mohankumar
09380698fa refactor: split phase0 flag into redesign, explore, tokenSafety (#4347)
* changes so far

* more changes

* lint

* remove Phase0:
2022-08-15 10:09:26 -04:00
lynn
1d96961f25 feat: token selector design update (#4333)
* init

* selected base currency button

* add check icon

* theme background module change

* hover changes

* theme none

* additional padding

* hover default color from phil + feature flag

* checkmark style fixes
2022-08-12 17:47:36 +00:00
Vignesh Mohankumar
b38241c675 chore: remove @amplitude/experiment-js-client (#4338) 2022-08-11 18:55:16 -04:00
247 changed files with 16255 additions and 3724 deletions

1
.env
View File

@@ -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"

View File

@@ -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"

View File

@@ -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
View File

@@ -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

View File

@@ -1 +1 @@
/src/state/data/generated.ts
/src/schema/schema.graphql

View File

@@ -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

View File

@@ -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%')

View File

@@ -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
},
})

View File

@@ -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",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

3
src/assets/svg/share.svg Normal file
View 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

View File

@@ -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' && <>&nbsp;</>}
{isCopied ? '' : children}
{iconPosition === 'right' && <>&nbsp;</>}
{iconPosition === 'right' ? isCopied ? <Copied iconSize={iconSize} /> : <Icon iconSize={iconSize} /> : null}
</CopyIcon>
)
}

View File

@@ -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>
)}

View File

@@ -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)

View File

@@ -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',

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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'

View File

@@ -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>

View File

@@ -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'

View File

@@ -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>

View File

@@ -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>
</>
)
}

View File

@@ -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>
)
}

View File

@@ -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>

View File

@@ -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'

View File

@@ -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

View File

@@ -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])
}

View File

@@ -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} />}

View File

@@ -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"
/>

View File

@@ -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 } = {}

View File

@@ -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>
)
}

View File

@@ -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

View File

@@ -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 (

View 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',
}),
])

View 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>
)
}

View 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',
}),
])

View 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 />
</>
)
}

View 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',
}),
])

View 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 />
</>
)
}

View 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,
},
])

View 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>
)
}

View 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,
},
])

View 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>
)
}

View 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%)',
},
])

View 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

View File

@@ -0,0 +1,3 @@
import Navbar from './Navbar'
export default Navbar

View File

@@ -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'

View File

@@ -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"

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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}>

View File

@@ -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>

View File

@@ -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} />

View File

@@ -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>

View File

@@ -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>
)

View File

@@ -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)}

View File

@@ -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'

View File

@@ -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'

View File

@@ -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'

View File

@@ -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'

View File

@@ -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'

View File

@@ -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`

View File

@@ -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}>

View File

@@ -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>
)

View File

@@ -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;

View File

@@ -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>

View File

@@ -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%;

View File

@@ -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>
</>
)
}

View 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>
)
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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'

View File

@@ -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>

View File

@@ -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) : []

View File

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

View File

@@ -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'

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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) {

View File

@@ -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>

View File

@@ -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>
)
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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}

Some files were not shown because too many files have changed in this diff Show More