diff --git a/src/assets/icons/VersusIcon.tsx b/src/assets/icons/VersusIcon.tsx new file mode 100644 index 0000000..c356312 --- /dev/null +++ b/src/assets/icons/VersusIcon.tsx @@ -0,0 +1,71 @@ +import * as React from "react" +import { SVGProps } from "react" +const SvgComponent = (props: SVGProps) => ( + + + + + + + + + + + + + + + + + + + +) +export default SvgComponent diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 87ec865..b514d30 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -33,3 +33,4 @@ export { default as RestartIcon } from './RestartIcon'; export { default as DownloadIcon } from './DownloadIcon'; export { default as XIcon } from './XIcon' export { default as TelegramIcon } from './TelegramIcon' +export { default as VersusIcon } from './VersusIcon' diff --git a/src/assets/images/landing-hero-left-widget-mobile-image.png b/src/assets/images/landing-hero-left-widget-mobile-image.png new file mode 100644 index 0000000..a2a51e9 Binary files /dev/null and b/src/assets/images/landing-hero-left-widget-mobile-image.png differ diff --git a/src/assets/images/landing-hero-right-widget-mobile-image.png b/src/assets/images/landing-hero-right-widget-mobile-image.png new file mode 100644 index 0000000..d9f6c0c Binary files /dev/null and b/src/assets/images/landing-hero-right-widget-mobile-image.png differ diff --git a/src/components/Dice/animations.ts b/src/components/Dice/animations.ts index 1738a9e..7e3bf05 100644 --- a/src/components/Dice/animations.ts +++ b/src/components/Dice/animations.ts @@ -23,4 +23,22 @@ export function useRoll(diceRef: any,) { }, [trigger]); return triggerRoll; +} + +export function useAutoRoll(diceRef: any,) { + function roll() { + const tl = gsap.timeline(); + tl.to("g#all-sides", { + repeatDelay: 1.5, + repeat: -1, + ease: Power3.easeInOut, + y: "-500", + }) + } + useLayoutEffect(()=> { + const ctx = gsap.context(() => { + roll(); + }, diceRef); + return () => ctx.revert(); + }); } \ No newline at end of file diff --git a/src/components/Dice/index.tsx b/src/components/Dice/index.tsx index c9d906a..a995b25 100644 --- a/src/components/Dice/index.tsx +++ b/src/components/Dice/index.tsx @@ -1,11 +1,21 @@ +import { SVGProps } from 'react'; import { DiceContainer } from './types'; import WegaDice from './images/WegaDice'; import "twin.macro"; -export const Dice: React.FC<{ diceRef: any }> = ({ diceRef }: { diceRef: any }) => { +type DiceProps = { + diceRef: any; + svgProps?: SVGProps; +} & React.Attributes & React.AllHTMLAttributes + +export const Dice: React.FC = ({ + diceRef, + svgProps, + ...props +}: DiceProps) => { return ( - - + + ) } diff --git a/src/components/LandingHeroPlayerCard/index.tsx b/src/components/LandingHeroPlayerCard/index.tsx index d202c73..533300e 100644 --- a/src/components/LandingHeroPlayerCard/index.tsx +++ b/src/components/LandingHeroPlayerCard/index.tsx @@ -3,6 +3,8 @@ import leftAvatarSource from '../../assets/images/hero-left-player-image.png'; import rightAvatarSource from '../../assets/images/hero-right-player-image.png'; import leftWidget from '../../assets/images/hero-left-widget.png'; import rightWidget from '../../assets/images/hero-right-widget.png'; +import rightWidgetImage from '../../assets/images/landing-hero-right-widget-mobile-image.png'; +import leftWidgetImage from '../../assets/images/landing-hero-left-widget-mobile-image.png'; import { PlayerCardContainer, @@ -29,7 +31,33 @@ export const LeftPlayerCard = () => { left-wager - Launch the app to start + {/* Launch the app to start */} + + ) +} +export const LeftPlayerCardMobile = () => { + return ( + +
+ #392 + BAYC + 38.1 ETH + (~73.00 USD) +
+ left-wager +
+ ) +} +export const RightPlayerCardMobile = () => { + return ( + + left-wager +
+ #392 + Noun + 38.0 ETH + (~73.200 USD) +
) } @@ -51,7 +79,7 @@ export const RightPlayerCard = () => { right-wager - Awaiting opponent + {/* Awaiting opponent */} ) } diff --git a/src/components/LandingPageHero/index.tsx b/src/components/LandingPageHero/index.tsx new file mode 100644 index 0000000..fb5e1f2 --- /dev/null +++ b/src/components/LandingPageHero/index.tsx @@ -0,0 +1,28 @@ +import { useRef } from 'react'; +import { PlayGameContainer } from "../LandingPageHeroSection/types"; +import { Dice } from "../Dice"; +import { useRoll, useAutoRoll } from "../Dice/animations"; +import { LeftPlayerCard, RightPlayerCard } from "../LandingHeroPlayerCard"; +import Button from "../Button"; +import { SectionHeader } from '../../common/Section/types'; +import 'twin.macro'; + +const LandingPageHero = () => { + const diceRef = useRef(null); + const triggerDice = useRoll(diceRef); + useAutoRoll(diceRef); + + return ( <> + +
+ + + +
+ +
+ Play multiple P2P betting games with your NFTs. ) +} +export default LandingPageHero; \ No newline at end of file diff --git a/src/components/LandingPageHeroMobile/index.tsx b/src/components/LandingPageHeroMobile/index.tsx new file mode 100644 index 0000000..3c12bc5 --- /dev/null +++ b/src/components/LandingPageHeroMobile/index.tsx @@ -0,0 +1,29 @@ +import { useRef } from 'react'; +import { Dice } from "../Dice"; +import { useAutoRoll } from "../Dice/animations"; +import { LeftPlayerCardMobile, RightPlayerCardMobile} from "../LandingHeroPlayerCard"; +import Button from "../Button"; + +import { VersusIcon } from '../../assets/icons'; +import 'twin.macro'; + +const LandingPageHeroMobile = () => { + const diceRef = useRef(null); + useAutoRoll(diceRef); + + return ( +
+ +
+ + +
+ + +
+ ) +} +export default LandingPageHeroMobile; \ No newline at end of file diff --git a/src/components/LandingPageHeroSection/index.tsx b/src/components/LandingPageHeroSection/index.tsx index eedafd3..d1e716d 100644 --- a/src/components/LandingPageHeroSection/index.tsx +++ b/src/components/LandingPageHeroSection/index.tsx @@ -1,19 +1,10 @@ -import { useRef } from 'react'; import Section from "../../common/Section" -import { SectionHeaderContainer, SectionHeaderTitleLarge, SectionHeader } from "../../common/Section/types" -import { PlayGameContainer } from './types' -import { LeftPlayerCard, RightPlayerCard } from '../LandingHeroPlayerCard'; +import { SectionHeaderContainer, SectionHeaderTitleLarge } from "../../common/Section/types" import { FloatingOrbs } from '../../common/FloatingOrbs'; -import Button from "../Button"; -import { Dice } from "../Dice"; -import { useRoll } from "../Dice/animations"; -import { useMediaQuery } from '../../hooks'; +import LandingPageHero from '../LandingPageHero'; import 'twin.macro'; const LandingPageHeroSection = () => { - const diceRef = useRef(null); - const triggerDice = useRoll(diceRef); - const { isMobile } = useMediaQuery(); return ( <> @@ -23,21 +14,11 @@ const LandingPageHeroSection = () => { hdr={ - {isMobile ? "Your NFTs’ Playground" : "Your NFTs’ Favourite Playground"}. + {"Your NFTs’ Favourite Playground"}. }> - -
- - - -
- -
- Play multiple P2P betting games with your NFTs. + ) diff --git a/src/components/LandingPageHeroSectionMobile/index.tsx b/src/components/LandingPageHeroSectionMobile/index.tsx new file mode 100644 index 0000000..f110ef1 --- /dev/null +++ b/src/components/LandingPageHeroSectionMobile/index.tsx @@ -0,0 +1,27 @@ +import Section from "../../common/Section" +import { SectionHeaderContainer, SectionHeaderTitleLarge, SectionHeader } from "../../common/Section/types" +import { FloatingOrbs } from '../../common/FloatingOrbs'; +import 'twin.macro'; +import LandingPageHeroMobile from "../LandingPageHeroMobile"; + +const LandingPageHeroSectionMobile = () => { + return ( + <> + +
+ + {"Your NFTs’ Playground"}. + + Play multiple P2P betting games with your NFTs. + + }> + +
+ + ) +} +export default LandingPageHeroSectionMobile; \ No newline at end of file diff --git a/src/components/MainContainer/index.tsx b/src/components/MainContainer/index.tsx index 6c6025d..58ffcba 100644 --- a/src/components/MainContainer/index.tsx +++ b/src/components/MainContainer/index.tsx @@ -3,7 +3,7 @@ import 'twin.macro'; const MainContainer: React.FC = ({ children, ...rest }: MainPropsContainerProps) => { return ( -
+
{children}
) diff --git a/src/components/cards/NFTCard.tsx b/src/components/cards/NFTCard.tsx new file mode 100644 index 0000000..c648d33 --- /dev/null +++ b/src/components/cards/NFTCard.tsx @@ -0,0 +1,60 @@ +import { + NFTProps, + CardWrapper, + RequestProps +} from './types'; +import { SVGComponent } from '../svg'; +import { Link } from 'react-router-dom'; +import { TransactionState } from '../../listing' + +export type NFTCardProps = { + listButton?: boolean; + tradeButton?: boolean; + offersButton?: boolean; + listed?: boolean; + isOfferMaker?: boolean; + nft: NFTProps, + request?: RequestProps; +} + +const NFTCard: React.FC = ({ + offersButton, + isOfferMaker, + listButton, + request, + listed, + tradeButton, + nft, +}) => { + return ( + +
+ + { /* add banner that shows if an nft is listed or unlisted */} +
+
+
{nft.nftName}
+
price: {nft.ethPrice} ETH
+
+ { + listButton && !listed && +
+ + + +
+ } + { + tradeButton && request && request.state === TransactionState.OPEN && + + + + } +
+ ) +} +export default NFTCard; diff --git a/src/components/cards/NFTOrRequestCard.tsx b/src/components/cards/NFTOrRequestCard.tsx new file mode 100644 index 0000000..12abdb8 --- /dev/null +++ b/src/components/cards/NFTOrRequestCard.tsx @@ -0,0 +1,68 @@ +import {type NFTProps, RequestProps, NFTCardProps, NFTCardWrapper } from '../cards' +import {Link} from 'react-router-dom' +import {TransactionState} from '../../listing' +import {SVGComponent} from '../svg'; +import { + useAccount +} from 'wagmi'; +import { + parseIntFromBignumber +} from '../../../utils' + +const NFTOrRequestCard = (props: NFTProps | RequestProps) => { + + const { + tradeButton, + withdrawButton, + offersButton, + listButton, + depositButton, + } = props as NFTCardProps; + + const { address } = useAccount(); + const rProps = props as RequestProps; + const mProps = props as NFTProps; + + return ( + +
+ +
+
+
{props.nftName}
+
price: {mProps.ethPrice} ETH
+
+ { + (offersButton || withdrawButton || tradeButton || listButton || depositButton) && +
+ { + offersButton && rProps.ownerAgainst?.toLowerCase() === address?.toLowerCase() && + + + + } + { + tradeButton && rProps && Number(rProps?.state) === TransactionState.OPEN && + + + + } + { + listButton && mProps && + + + + } +
+ } +
+ ) +} + +export default NFTOrRequestCard; \ No newline at end of file diff --git a/src/components/cards/OfferActionsNFTRectangle.tsx b/src/components/cards/OfferActionsNFTRectangle.tsx new file mode 100644 index 0000000..1ff3143 --- /dev/null +++ b/src/components/cards/OfferActionsNFTRectangle.tsx @@ -0,0 +1,36 @@ +import { SVGComponent } from '../svg'; +import { OfferBarNFTNameOrPriceETH } from '../../offers/types'; +import { + NFTProps, + OfferActionNFTRectangleGradientWrapper, + OfferActionNFTRectangleBigNFTDetailWrapper, + OfferActionsNFTRectangleBigNFTName, + OfferActionsNFTRectangleBigCollectionName, + OfferActionsNFTRectangleBigOwner, + OfferActionsNFTRectangleTraits, +} from './types'; +import {miniWalletAddress} from '../../../utils' + + +interface OfferActionsNFTRectangleProps { + yours?: boolean; + nft: NFTProps; +} + +const OfferActionsNFTRectangle: React.FC = (props) => { + return props ? ( + + + + {props.nft.nftName} + Price: {props.nft.ethPrice} ETH + Collection: {miniWalletAddress(props.nft.nftAddress as `0x${string}`)} + Owner: {miniWalletAddress(props.nft.owner as `0x${string}`)} + Traits: + + + ) + : <> +} + +export default OfferActionsNFTRectangle; diff --git a/src/components/cards/RectangleNFTCard.tsx b/src/components/cards/RectangleNFTCard.tsx new file mode 100644 index 0000000..593cfc4 --- /dev/null +++ b/src/components/cards/RectangleNFTCard.tsx @@ -0,0 +1,26 @@ +import { RectangleNFTCardWrapper, RectangleNFTCardProps } from './types'; +import { SVGComponent } from '../../common/svg'; +import { RequestProps, NFTProps } from '../../common/cards'; +import { shortenHexString } from '../../../utils' + +const RectangleNFTCard = (props: RectangleNFTCardProps) => { + // should display the nft select with selected squares (yours) + // theirs display the nft from listedNFTs + + return props.nft && ( + +
{props.yours ? "Your asset" : "Their asset"}
+
+ +
+
{ props.nft.nftName }
+
{ (props.nft.ethPrice && String(props.nft.ethPrice).concat(' ETH')) || '1.00 ETH'}
+
Collection: { shortenHexString(props.nft.nftAddress as `0x${string}`, 5)}
+
Owner: {props.yours ? "You" : shortenHexString(props.nft.owner as `0x${string}`, 5) }
+
+
+
+ ) +} + +export default RectangleNFTCard; diff --git a/src/components/cards/index.ts b/src/components/cards/index.ts new file mode 100644 index 0000000..08cb089 --- /dev/null +++ b/src/components/cards/index.ts @@ -0,0 +1,11 @@ +export { + RectangleNFTCardWrapper, + NFTCardWrapper, + RequestCardsContainer, + SwapIconWrapper +} from './types' +export type { RequestProps, NFTCardProps, NFTProps } from './types' +export { default as NFTOrRequestCard } from './NFTOrRequestCard' +export { default as RectangleNFTCard } from './RectangleNFTCard' +export { default as OfferActionsNFTRectangle } from './OfferActionsNFTRectangle' +export { default as NFTCard } from './NFTCard' \ No newline at end of file diff --git a/src/components/cards/types.ts b/src/components/cards/types.ts new file mode 100644 index 0000000..077fbad --- /dev/null +++ b/src/components/cards/types.ts @@ -0,0 +1,289 @@ +import styled from 'styled-components'; +import { BigNumber } from 'ethers'; +import {TransactionState} from '../../listing' +import {OfferState} from '../../trade' + +// export const Colors = { +// [TransactionState.OPEN]: '#F26D21', +// [TransactionState.APPROVED]: '#787878', +// [TransactionState.READY]: '#E62700', +// [TransactionState.CLOSED]: '#151515' +// } + +// export const BadgeText = { +// [TransactionState.OPEN]: 'OPEN', +// [TransactionState.APPROVED]: 'APPROVED', +// [TransactionState.READY]: 'READY', +// [TransactionState.CLOSED]: 'CLOSED' +// } + +export type NFTCardProps = { + tradeButton?: boolean; + withdrawButton?: boolean; + offersButton?: boolean; + listButton?: boolean; + depositButton?: boolean; + svgString?: string; + imgUrl?: string; + ethPrice: number; + transferId: string | any; +} + + +export type RequestProps = { + state: TransactionState; + nftAgainst: string | `0x${string}`; + tokenIdAgainst: number | BigNumber; + ownerAgainst: string | `0x${string}`; + nftFor: string | `0x${string}`; + tokenIdFor: number | BigNumber; + ownerFor: string | `0x${string}`; + deadline: number | BigNumber; + transactionId: string; + nftName: string; + nonce: number | BigNumber; + ts?: number; + id?: string; + offerState: OfferState; + creator?: `0x${string}`; + shouldSync?: boolean; +} & NFTCardProps + +export type NFTProps = { + tokenId: number | BigNumber; + nftAddress: string | `0x${string}`; + owner: string; + nftName: string; + approved?: boolean | undefined | Promise; + id: string; +} & NFTCardProps + +export const CardWrapper = styled.article` + background-color: #2A2A2A; + width: 22.5%; + padding: 0rem; + & header { + height: 226px; + margin-left: 0rem; + margin-right: 0rem; + padding: 0rem; + position: relative; + margin-bottom: 0rem; + & > div { + padding: 1rem; + border-radius: 5px 5px 0px 0px; + width: 100%; + height: 100%; + } + } + & > div, footer { + padding: 10px 15px; + } + & footer { + margin: 0rem; + background-color: inherit; + button { + justify-content: center; + max-width: unset; + width: 100%; + } + a { + &:hover { + text-decoration: unset; + } + } + } +` + +export const NFTCardWrapper = styled.article` + background-color: #2A2A2A; + width: 22.5%; + padding: 0rem; + & header { + height: 226px; + margin-left: 0rem; + margin-right: 0rem; + padding: 0rem; + position: relative; + margin-bottom: 0rem; + & > div { + padding: 1rem; + border-radius: 5px 5px 0px 0px; + width: 100%; + height: 100%; + } + } + & > div, footer { + padding: 10px 15px; + } + & footer { + margin: 0rem; + background-color: inherit; + button { + justify-content: center; + max-width: unset; + width: 100%; + } + a { + &:hover { + text-decoration: unset; + } + } + } +` + +export const RequestCardsContainer = styled.div` + display: flex; + flex-flow: row wrap; + gap: 2rem; + justify-content: start; + summary { + padding: 16px; + } +` + +export interface RectangleNFTCardProps { + yours: boolean; + nft: NFTProps; +} + +export const RectangleNFTCardWrapper = styled.div` + display:flex; + flex-direction:column; + text-align: left; + width: 100%; + margin-top: 1rem; + + & > h6:first-child { + margin-bottom: 0.25rem; + } + & div.information { + display:flex; + flex-direction:row; + width: 100%; + margin-bottom: 1rem; + border: 1px solid #9A9A9A; + border-radius: 10px; + padding: 12px; + background-color: #3F3F3F; + h6 { + margin: unset; + margin-bottom: 0.25rem; + } + > div:first-child { + margin-right: 0.5rem; + width: 100px; + height: 100px; + svg { + width: 100%; + } + padding: 5px; + background-color: #787878; + border-radius:5px; + } + & > div.details { + display:flex; + flex-direction: column; + padding: 2px; + } + } +` +interface SwapIconWrapperProps { + width?: string; +} + +export const SwapIconWrapper = styled.div` + --swap-icon-default-width: 40px; + width: ${({ width }) => width || "var(--swap-icon-default-width)" }; +` + +export const OfferActionNFTRectangleGradientWrapper = styled.div` +display: flex; +align-items: center; +width: 100%; +min-width: 473px; +margin: auto; +gap: 0px 20px; + +position: relative; +padding: 12px 12px; +box-sizing: border-box; + +--border: 2px; +background: #505050; +background-clip: padding-box; +border: solid var(--border) transparent; +border-radius: 1em; + +&:before { + content: ''; + position: absolute; + top: 0; right: 0; bottom: 0; left: 0; + z-index: -1; + margin: calc(-1 * var(--border)); + border-radius: inherit; + background: linear-gradient(to right, #e68572, #8246e2); +} +> div.image-wrapper { + border-radius: 5px; + background-color: rgb(120, 120, 120); + width: 200px; + height: 200px; +} +` + +export const OfferActionNFTRectangleBigNFTDetailWrapper = styled.div` + align-self: flex-start; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 15px 0px; +` + +export const OfferActionsNFTRectangleBigNFTName = styled.span` + color: #FDFDFD; + text-align: center; + leading-trim: both; + text-edge: cap; + font-family: League Spartan; + font-size: 21px; + font-style: normal; + font-weight: 400; + line-height: 19px; +` + +export const OfferActionsNFTRectangleBigCollectionName = styled.span` + color: #FDFDFD; + text-align: center; + leading-trim: both; + text-edge: cap; + font-family: League Spartan; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 15px; +` + +export const OfferActionsNFTRectangleBigOwner = styled.span` + color: #FDFDFD; + text-align: center; + leading-trim: both; + text-edge: cap; + font-family: League Spartan; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 15px; +` + +export const OfferActionsNFTRectangleTraits = styled.span` + color: #FDFDFD; + text-align: center; + leading-trim: both; + text-edge: cap; + font-family: League Spartan; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 15px; +` diff --git a/src/containers/LandingPage/index.tsx b/src/containers/LandingPage/index.tsx index 6243ac4..e5ace9e 100644 --- a/src/containers/LandingPage/index.tsx +++ b/src/containers/LandingPage/index.tsx @@ -1,18 +1,25 @@ import React from 'react' import { Helmet } from 'react-helmet-async' import LandingPageHeroSection from '../../components/LandingPageHeroSection'; +import LandingPageHeroSectionMobile from '../../components/LandingPageHeroSectionMobile'; import LandingPagePlaySection from '../../components/LandingPagePlaySection'; import LandingPageWagerTypeSection from '../../components/LandingPageWagerTypeSection'; import LandingPageOwnTheYardSection from '../../components/LandingPageOwnTheYardSection'; import MainContainer from '../../components/MainContainer'; +import { useMediaQuery } from '../../hooks'; const LandingPage = () => { + const { isMobile } = useMediaQuery(); return ( <> Wega - + { + isMobile ? + : + + } diff --git a/tailwind.config.cjs b/tailwind.config.cjs index 605ee4d..7a1ae45 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -50,8 +50,7 @@ export default { }, boxShadow: { 'wega-nav': '0rem -3.5rem 1.5rem 5rem #151515', - // box-shadow: 0rem -3.5rem 1.5rem 5rem var(--background-color); - + 'primary-button': '0px 10.74153px 16.52542px 0px rgba(0, 0, 0, 0.30)' }, animation: { 'rotate-orbs': 'rotate-orbs 10s linear 5s infinite',