feat: add token explore promo banner (#4481)
* initial design * progress * add background image * add logic * update * delete unneed state * more * redux * redux * more redux * rebase main * rm unused state * rm unused export * relative link
This commit is contained in:
parent
c9e2f86e57
commit
6f3579acf1
BIN
src/assets/images/tokensPromoDark.png
Normal file
BIN
src/assets/images/tokensPromoDark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
src/assets/images/tokensPromoLight.png
Normal file
BIN
src/assets/images/tokensPromoLight.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
75
src/components/Tokens/TokensBanner.tsx
Normal file
75
src/components/Tokens/TokensBanner.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { X } from 'react-feather'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { useShowTokensPromoBanner } from 'state/user/hooks'
|
||||||
|
import styled, { useTheme } from 'styled-components/macro'
|
||||||
|
import { opacify } from 'theme/utils'
|
||||||
|
|
||||||
|
import tokensPromoDark from '../../assets/images/tokensPromoDark.png'
|
||||||
|
import tokensPromoLight from '../../assets/images/tokensPromoLight.png'
|
||||||
|
|
||||||
|
const PopupContainer = styled.div<{ show: boolean }>`
|
||||||
|
position: absolute;
|
||||||
|
display: ${({ show }) => (show ? 'flex' : 'none')};
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 12px 16px 12px 20px;
|
||||||
|
gap: 8px;
|
||||||
|
bottom: 48px;
|
||||||
|
right: 16px;
|
||||||
|
width: 320px;
|
||||||
|
height: 88px;
|
||||||
|
z-index: 5;
|
||||||
|
background-color: ${({ theme }) => (theme.darkMode ? theme.backgroundScrim : opacify(60, '#FDF0F8'))};
|
||||||
|
color: ${({ theme }) => theme.textPrimary};
|
||||||
|
border: 1px solid ${({ theme }) => theme.backgroundOutline};
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: ${({ theme }) => theme.deepShadow};
|
||||||
|
|
||||||
|
background-image: url(${({ theme }) => (theme.darkMode ? `${tokensPromoDark}` : `${tokensPromoLight}`)});
|
||||||
|
background-size: cover;
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
|
||||||
|
transition: ${({
|
||||||
|
theme: {
|
||||||
|
transition: { duration, timing },
|
||||||
|
},
|
||||||
|
}) => `${duration.slow}ms opacity ${timing.in}`};
|
||||||
|
`
|
||||||
|
const Header = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
`
|
||||||
|
const HeaderText = styled(Link)`
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
`
|
||||||
|
const Description = styled.span`
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 75%;
|
||||||
|
`
|
||||||
|
|
||||||
|
export default function TokensBanner() {
|
||||||
|
const theme = useTheme()
|
||||||
|
const [showTokensPromoBanner, setShowTokensPromoBanner] = useShowTokensPromoBanner()
|
||||||
|
|
||||||
|
const closeBanner = () => {
|
||||||
|
setShowTokensPromoBanner(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopupContainer show={showTokensPromoBanner}>
|
||||||
|
<Header>
|
||||||
|
<HeaderText to={'/#/tokens'} onClick={closeBanner}>
|
||||||
|
Explore Top Tokens
|
||||||
|
</HeaderText>
|
||||||
|
<X size={20} color={theme.textSecondary} onClick={closeBanner} style={{ cursor: 'pointer' }} />
|
||||||
|
</Header>
|
||||||
|
|
||||||
|
<Description onClick={closeBanner}>Check out the new explore tab to discover and learn more</Description>
|
||||||
|
</PopupContainer>
|
||||||
|
)
|
||||||
|
}
|
@ -10,8 +10,10 @@ import { FlyoutAlignment, NewMenu } from 'components/Menu'
|
|||||||
import PositionList from 'components/PositionList'
|
import PositionList from 'components/PositionList'
|
||||||
import { RowBetween, RowFixed } from 'components/Row'
|
import { RowBetween, RowFixed } from 'components/Row'
|
||||||
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
|
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
|
||||||
|
import TokensBanner from 'components/Tokens/TokensBanner'
|
||||||
import { isSupportedChain } from 'constants/chains'
|
import { isSupportedChain } from 'constants/chains'
|
||||||
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
|
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
|
||||||
|
import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens'
|
||||||
import { useV3Positions } from 'hooks/useV3Positions'
|
import { useV3Positions } from 'hooks/useV3Positions'
|
||||||
import { AlertTriangle, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather'
|
import { AlertTriangle, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
@ -164,8 +166,10 @@ function WrongNetworkCard() {
|
|||||||
const navBarFlag = useNavBarFlag()
|
const navBarFlag = useNavBarFlag()
|
||||||
const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled
|
const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const tokensFlag = useTokensFlag()
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{tokensFlag === TokensVariant.Enabled && <TokensBanner />}
|
||||||
<PageWrapper navBarFlag={navBarFlagEnabled}>
|
<PageWrapper navBarFlag={navBarFlagEnabled}>
|
||||||
<AutoColumn gap="lg" justify="center">
|
<AutoColumn gap="lg" justify="center">
|
||||||
<AutoColumn gap="lg" style={{ width: '100%' }}>
|
<AutoColumn gap="lg" style={{ width: '100%' }}>
|
||||||
|
@ -17,11 +17,13 @@ import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
|
|||||||
import PriceImpactWarning from 'components/swap/PriceImpactWarning'
|
import PriceImpactWarning from 'components/swap/PriceImpactWarning'
|
||||||
import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown'
|
import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown'
|
||||||
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
|
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
|
||||||
|
import TokensBanner from 'components/Tokens/TokensBanner'
|
||||||
import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal'
|
import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal'
|
||||||
import { MouseoverTooltip } from 'components/Tooltip'
|
import { MouseoverTooltip } from 'components/Tooltip'
|
||||||
import { isSupportedChain } from 'constants/chains'
|
import { isSupportedChain } from 'constants/chains'
|
||||||
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
|
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
|
||||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||||
|
import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens'
|
||||||
import { useSwapCallback } from 'hooks/useSwapCallback'
|
import { useSwapCallback } from 'hooks/useSwapCallback'
|
||||||
import useTransactionDeadline from 'hooks/useTransactionDeadline'
|
import useTransactionDeadline from 'hooks/useTransactionDeadline'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
@ -154,6 +156,7 @@ export default function Swap() {
|
|||||||
const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled
|
const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled
|
||||||
const redesignFlag = useRedesignFlag()
|
const redesignFlag = useRedesignFlag()
|
||||||
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
|
||||||
|
const tokensFlag = useTokensFlag()
|
||||||
const { account, chainId } = useWeb3React()
|
const { account, chainId } = useWeb3React()
|
||||||
const loadedUrlParams = useDefaultsFromURLSearch()
|
const loadedUrlParams = useDefaultsFromURLSearch()
|
||||||
const [newSwapQuoteNeedsLogging, setNewSwapQuoteNeedsLogging] = useState(true)
|
const [newSwapQuoteNeedsLogging, setNewSwapQuoteNeedsLogging] = useState(true)
|
||||||
@ -505,6 +508,7 @@ export default function Swap() {
|
|||||||
return (
|
return (
|
||||||
<Trace page={PageName.SWAP_PAGE} shouldLogImpression>
|
<Trace page={PageName.SWAP_PAGE} shouldLogImpression>
|
||||||
<>
|
<>
|
||||||
|
{tokensFlag === TokensVariant.Enabled && <TokensBanner />}
|
||||||
{redesignFlagEnabled ? (
|
{redesignFlagEnabled ? (
|
||||||
<TokenSafetyModal
|
<TokenSafetyModal
|
||||||
isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning}
|
isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning}
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
removeSerializedToken,
|
removeSerializedToken,
|
||||||
updateHideClosedPositions,
|
updateHideClosedPositions,
|
||||||
updateShowSurveyPopup,
|
updateShowSurveyPopup,
|
||||||
|
updateShowTokensPromoBanner,
|
||||||
updateUserClientSideRouter,
|
updateUserClientSideRouter,
|
||||||
updateUserDarkMode,
|
updateUserDarkMode,
|
||||||
updateUserDeadline,
|
updateUserDeadline,
|
||||||
@ -116,6 +117,18 @@ export function useShowSurveyPopup(): [boolean | undefined, (showPopup: boolean)
|
|||||||
return [showSurveyPopup, toggleShowSurveyPopup]
|
return [showSurveyPopup, toggleShowSurveyPopup]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useShowTokensPromoBanner(): [boolean, (showTokensBanner: boolean) => void] {
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
const showTokensPromoBanner = useAppSelector((state) => state.user.showTokensPromoBanner)
|
||||||
|
const toggleShowTokensPromoBanner = useCallback(
|
||||||
|
(showTokensBanner: boolean) => {
|
||||||
|
dispatch(updateShowTokensPromoBanner({ showTokensPromoBanner: showTokensBanner }))
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
)
|
||||||
|
return [showTokensPromoBanner, toggleShowTokensPromoBanner]
|
||||||
|
}
|
||||||
|
|
||||||
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
|
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@ export interface UserState {
|
|||||||
showSurveyPopup: boolean | undefined
|
showSurveyPopup: boolean | undefined
|
||||||
|
|
||||||
showDonationLink: boolean
|
showDonationLink: boolean
|
||||||
|
|
||||||
|
showTokensPromoBanner: boolean // show tokens promo banner for token explore
|
||||||
}
|
}
|
||||||
|
|
||||||
function pairKey(token0Address: string, token1Address: string) {
|
function pairKey(token0Address: string, token1Address: string) {
|
||||||
@ -76,6 +78,7 @@ export const initialState: UserState = {
|
|||||||
URLWarningVisible: true,
|
URLWarningVisible: true,
|
||||||
showSurveyPopup: undefined,
|
showSurveyPopup: undefined,
|
||||||
showDonationLink: true,
|
showDonationLink: true,
|
||||||
|
showTokensPromoBanner: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
const userSlice = createSlice({
|
const userSlice = createSlice({
|
||||||
@ -121,6 +124,9 @@ const userSlice = createSlice({
|
|||||||
updateShowDonationLink(state, action) {
|
updateShowDonationLink(state, action) {
|
||||||
state.showDonationLink = action.payload.showDonationLink
|
state.showDonationLink = action.payload.showDonationLink
|
||||||
},
|
},
|
||||||
|
updateShowTokensPromoBanner(state, action) {
|
||||||
|
state.showTokensPromoBanner = action.payload.showTokensPromoBanner
|
||||||
|
},
|
||||||
addSerializedToken(state, { payload: { serializedToken } }) {
|
addSerializedToken(state, { payload: { serializedToken } }) {
|
||||||
if (!state.tokens) {
|
if (!state.tokens) {
|
||||||
state.tokens = {}
|
state.tokens = {}
|
||||||
@ -210,5 +216,6 @@ export const {
|
|||||||
updateUserExpertMode,
|
updateUserExpertMode,
|
||||||
updateUserLocale,
|
updateUserLocale,
|
||||||
updateUserSlippageTolerance,
|
updateUserSlippageTolerance,
|
||||||
|
updateShowTokensPromoBanner,
|
||||||
} = userSlice.actions
|
} = userSlice.actions
|
||||||
export default userSlice.reducer
|
export default userSlice.reducer
|
||||||
|
Loading…
Reference in New Issue
Block a user