feat: welcome nft banner (#5379)
* wip * finished modal, waiting for assets * feat: use srcset for better assets optimisation * feat: bg photo * various tweaks * feat: wrap up logic * chore: use proper link * chore: bring switch back
This commit is contained in:
parent
d528b28203
commit
1a31560374
BIN
src/assets/images/welcomeModal-dark.jpg
Normal file
BIN
src/assets/images/welcomeModal-dark.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
BIN
src/assets/images/welcomeModal-dark@2x.jpg
Normal file
BIN
src/assets/images/welcomeModal-dark@2x.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 449 KiB |
BIN
src/assets/images/welcomeModal-dark@3x.jpg
Normal file
BIN
src/assets/images/welcomeModal-dark@3x.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 927 KiB |
BIN
src/assets/images/welcomeModal-light.jpg
Normal file
BIN
src/assets/images/welcomeModal-light.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
BIN
src/assets/images/welcomeModal-light@2x.jpg
Normal file
BIN
src/assets/images/welcomeModal-light@2x.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 364 KiB |
BIN
src/assets/images/welcomeModal-light@3x.jpg
Normal file
BIN
src/assets/images/welcomeModal-light@3x.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 718 KiB |
@ -8,7 +8,7 @@ import { Z_INDEX } from 'theme/zIndex'
|
|||||||
import { isMobile } from '../../utils/userAgent'
|
import { isMobile } from '../../utils/userAgent'
|
||||||
|
|
||||||
const AnimatedDialogOverlay = animated(DialogOverlay)
|
const AnimatedDialogOverlay = animated(DialogOverlay)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const StyledDialogOverlay = styled(AnimatedDialogOverlay)<{ scrollOverlay?: boolean }>`
|
const StyledDialogOverlay = styled(AnimatedDialogOverlay)<{ scrollOverlay?: boolean }>`
|
||||||
&[data-reach-dialog-overlay] {
|
&[data-reach-dialog-overlay] {
|
||||||
z-index: ${Z_INDEX.modalBackdrop};
|
z-index: ${Z_INDEX.modalBackdrop};
|
||||||
|
111
src/nft/components/explore/WelcomeModal.tsx
Normal file
111
src/nft/components/explore/WelcomeModal.tsx
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
|
||||||
|
import Modal from 'components/Modal'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { X } from 'react-feather'
|
||||||
|
import styled, { useTheme } from 'styled-components/macro'
|
||||||
|
import { ExternalLink } from 'theme/components'
|
||||||
|
import { ThemedText } from 'theme/components/text'
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
padding: 30% 24px 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
height: fit-content;
|
||||||
|
user-select: none;
|
||||||
|
`
|
||||||
|
|
||||||
|
const CloseButton = styled(X)`
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
`
|
||||||
|
|
||||||
|
const Background = styled.img`
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
`
|
||||||
|
|
||||||
|
const Content = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 1;
|
||||||
|
gap: 16px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const Title = styled(ThemedText.LargeHeader)`
|
||||||
|
@media (max-width: ${({ theme }) => theme.breakpoint.xl}px) {
|
||||||
|
font-size: 20px !important;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Paragraph = styled(ThemedText.BodySecondary)`
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
@media (max-width: ${({ theme }) => theme.breakpoint.xl}px) {
|
||||||
|
font-size: 14px !important;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const BACKGROUND_IMAGE = {
|
||||||
|
dark: {
|
||||||
|
src: require('../../../assets/images/welcomeModal-dark.jpg').default,
|
||||||
|
srcSet: `
|
||||||
|
${require('../../../assets/images/welcomeModal-dark@2x.jpg').default} 2x,
|
||||||
|
${require('../../../assets/images/welcomeModal-dark@3x.jpg').default} 3x,
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
src: require('../../../assets/images/welcomeModal-light.jpg').default,
|
||||||
|
srcSet: `
|
||||||
|
${require('../../../assets/images/welcomeModal-light@2x.jpg').default} 2x,
|
||||||
|
${require('../../../assets/images/welcomeModal-light@3x.jpg').default} 3x,
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WelcomeModal({ onDismissed }: { onDismissed: () => void }) {
|
||||||
|
const [isOpen, setIsOpen] = useState(true)
|
||||||
|
|
||||||
|
const dismiss = () => {
|
||||||
|
setIsOpen(false)
|
||||||
|
setTimeout(() => onDismissed())
|
||||||
|
}
|
||||||
|
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal isOpen={isOpen} onDismiss={dismiss} maxWidth={720}>
|
||||||
|
<Container>
|
||||||
|
<Background
|
||||||
|
{...(theme.darkMode ? BACKGROUND_IMAGE.dark : BACKGROUND_IMAGE.light)}
|
||||||
|
alt="Welcome modal background"
|
||||||
|
draggable={false}
|
||||||
|
/>
|
||||||
|
<Content>
|
||||||
|
<Title>Introducing Uniswap NFT</Title>
|
||||||
|
<Paragraph>
|
||||||
|
We’re excited to announce that Uniswap Labs has acquired Genie to build the marketplace for all digital
|
||||||
|
assets! With Uniswap NFT, you can buy and sell NFTs across all marketplaces with the full functionality of
|
||||||
|
Genie. Additonally, if you’ve used Genie in the past, then you may be eligible for a USDC airdrop. You can
|
||||||
|
connect your wallet to claim any rewards. For more details on the airdrop please read the official
|
||||||
|
announcement on the Uniswap Labs blog.{' '}
|
||||||
|
<ExternalLink
|
||||||
|
href="https://uniswap.org/blog/uniswap-nft-aggregator-announcement"
|
||||||
|
title="Uniswap NFT aggregator announcement"
|
||||||
|
>
|
||||||
|
Learn more.
|
||||||
|
</ExternalLink>
|
||||||
|
</Paragraph>
|
||||||
|
<CloseButton size={24} onClick={dismiss} />
|
||||||
|
</Content>
|
||||||
|
</Container>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
@ -2,8 +2,10 @@ import { Trace } from '@uniswap/analytics'
|
|||||||
import { PageName } from '@uniswap/analytics-events'
|
import { PageName } from '@uniswap/analytics-events'
|
||||||
import Banner from 'nft/components/explore/Banner'
|
import Banner from 'nft/components/explore/Banner'
|
||||||
import TrendingCollections from 'nft/components/explore/TrendingCollections'
|
import TrendingCollections from 'nft/components/explore/TrendingCollections'
|
||||||
|
import { WelcomeModal } from 'nft/components/explore/WelcomeModal'
|
||||||
import { useBag } from 'nft/hooks'
|
import { useBag } from 'nft/hooks'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
import { useHideNFTWelcomeModal } from 'state/user/hooks'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
|
||||||
const ExploreContainer = styled.div`
|
const ExploreContainer = styled.div`
|
||||||
@ -23,6 +25,7 @@ const ExploreContainer = styled.div`
|
|||||||
|
|
||||||
const NftExplore = () => {
|
const NftExplore = () => {
|
||||||
const setBagExpanded = useBag((state) => state.setBagExpanded)
|
const setBagExpanded = useBag((state) => state.setBagExpanded)
|
||||||
|
const [isModalHidden, hideModal] = useHideNFTWelcomeModal()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setBagExpanded({ bagExpanded: false, manualClose: false })
|
setBagExpanded({ bagExpanded: false, manualClose: false })
|
||||||
@ -35,6 +38,7 @@ const NftExplore = () => {
|
|||||||
<Banner />
|
<Banner />
|
||||||
<TrendingCollections />
|
<TrendingCollections />
|
||||||
</ExploreContainer>
|
</ExploreContainer>
|
||||||
|
{!isModalHidden && <WelcomeModal onDismissed={hideModal} />}
|
||||||
</Trace>
|
</Trace>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
addSerializedToken,
|
addSerializedToken,
|
||||||
removeSerializedToken,
|
removeSerializedToken,
|
||||||
updateHideClosedPositions,
|
updateHideClosedPositions,
|
||||||
|
updateHideNFTWelcomeModal,
|
||||||
updateShowNftPromoBanner,
|
updateShowNftPromoBanner,
|
||||||
updateShowSurveyPopup,
|
updateShowSurveyPopup,
|
||||||
updateUserClientSideRouter,
|
updateUserClientSideRouter,
|
||||||
@ -118,6 +119,15 @@ export function useShowSurveyPopup(): [boolean | undefined, (showPopup: boolean)
|
|||||||
return [showSurveyPopup, toggleShowSurveyPopup]
|
return [showSurveyPopup, toggleShowSurveyPopup]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useHideNFTWelcomeModal(): [boolean | undefined, () => void] {
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
const hideNFTWelcomeModal = useAppSelector((state) => state.user.hideNFTWelcomeModal)
|
||||||
|
const hideModal = useCallback(() => {
|
||||||
|
dispatch(updateHideNFTWelcomeModal({ hideNFTWelcomeModal: true }))
|
||||||
|
}, [dispatch])
|
||||||
|
return [hideNFTWelcomeModal, hideModal]
|
||||||
|
}
|
||||||
|
|
||||||
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
|
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ export interface UserState {
|
|||||||
showSurveyPopup: boolean | undefined
|
showSurveyPopup: boolean | undefined
|
||||||
|
|
||||||
showDonationLink: boolean
|
showDonationLink: boolean
|
||||||
|
|
||||||
|
hideNFTWelcomeModal: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
function pairKey(token0Address: string, token1Address: string) {
|
function pairKey(token0Address: string, token1Address: string) {
|
||||||
@ -78,6 +80,7 @@ export const initialState: UserState = {
|
|||||||
hideNFTPromoBanner: false,
|
hideNFTPromoBanner: false,
|
||||||
showSurveyPopup: undefined,
|
showSurveyPopup: undefined,
|
||||||
showDonationLink: true,
|
showDonationLink: true,
|
||||||
|
hideNFTWelcomeModal: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
const userSlice = createSlice({
|
const userSlice = createSlice({
|
||||||
@ -123,6 +126,9 @@ const userSlice = createSlice({
|
|||||||
updateShowDonationLink(state, action) {
|
updateShowDonationLink(state, action) {
|
||||||
state.showDonationLink = action.payload.showDonationLink
|
state.showDonationLink = action.payload.showDonationLink
|
||||||
},
|
},
|
||||||
|
updateHideNFTWelcomeModal(state, action) {
|
||||||
|
state.hideNFTWelcomeModal = action.payload.hideNFTWelcomeModal
|
||||||
|
},
|
||||||
updateShowNftPromoBanner(state, action) {
|
updateShowNftPromoBanner(state, action) {
|
||||||
state.hideNFTPromoBanner = action.payload.hideNFTPromoBanner
|
state.hideNFTPromoBanner = action.payload.hideNFTPromoBanner
|
||||||
},
|
},
|
||||||
@ -210,6 +216,7 @@ export const {
|
|||||||
updateShowDonationLink,
|
updateShowDonationLink,
|
||||||
updateShowSurveyPopup,
|
updateShowSurveyPopup,
|
||||||
updateUserClientSideRouter,
|
updateUserClientSideRouter,
|
||||||
|
updateHideNFTWelcomeModal,
|
||||||
updateUserDarkMode,
|
updateUserDarkMode,
|
||||||
updateUserDeadline,
|
updateUserDeadline,
|
||||||
updateUserExpertMode,
|
updateUserExpertMode,
|
||||||
|
Loading…
Reference in New Issue
Block a user