add mngo page

This commit is contained in:
saml33 2023-02-23 15:30:51 +11:00
parent b729606f2d
commit b80c900613
17 changed files with 451 additions and 21 deletions

View File

@ -5,7 +5,7 @@ import { ReactNode } from 'react'
const Footer = () => {
const { t } = useTranslation(['footer', 'navigation'])
return (
<div className="lg:px-12 lg:pt-10 pb-4 px-6 pt-8 bg-th-bkg-2">
<div className="lg:px-12 lg:pt-10 pb-4 px-6 pt-8 bg-th-bkg-2 z-20 relative">
<div className="flex flex-col-reverse lg:flex-row">
<div className="w-full lg:w-1/4 flex flex-col items-center lg:items-start">
<a href="https://mango.markets">
@ -36,7 +36,7 @@ const Footer = () => {
<div className="w-full lg:w-3/4 flex flex-col sm:flex-row items-start justify-end sm:space-x-8 mb-8 lg:mb-0 border-b border-th-bkg-3 lg:border-b-0 pb-6 lg:pb-0">
<FooterLinkColumn title={t('navigation:about')}>
<FooterLink path="/mango-dao" title={t('navigation:mango-dao')} />
<FooterLink path="/token" title={t('navigation:token')} />
<FooterLink path="/mngo" title={t('navigation:mngo-token')} />
<FooterLink path="#" isExternal title={t('navigation:v4-stats')} />
<FooterLink path="/brand" title={t('navigation:brand')} />
</FooterLinkColumn>

View File

@ -1,6 +1,7 @@
import { CurrencyDollarIcon } from '@heroicons/react/20/solid'
import { useTranslation } from 'next-i18next'
import { ReactNode } from 'react'
import SectionWrapper from '../shared/SectionWrapper'
import HomeTopSection from './HomeTopSection'
const HomePage = () => {
@ -9,8 +10,8 @@ const HomePage = () => {
<>
{/* <div className="w-screen h-2 bg-gradient-to-r from-mango-red via-mango-yellow to-mango-green"></div> */}
<HomeTopSection />
<div className="bg-th-bkg-1 py-16 relative z-10">
<div className="px-6 lg:px-12 grid grid-cols-6 gap-x-8 gap-y-12">
<SectionWrapper>
<div className="grid grid-cols-6 gap-x-8 gap-y-12">
<IconWithText
desc={t('competitive-fees-desc')}
icon={<CurrencyDollarIcon className="h-6 w-6 text-th-fgd-2" />}
@ -42,7 +43,7 @@ const HomePage = () => {
title={t('competitive-fees')}
/>
</div>
</div>
</SectionWrapper>
</>
)
}

View File

@ -2,6 +2,7 @@ import { ReactNode } from 'react'
import Button from '../shared/Button'
import { useTranslation } from 'next-i18next'
import { CheckCircleIcon } from '@heroicons/react/20/solid'
import SectionWrapper from '../shared/SectionWrapper'
const HomeTopSection = () => {
const { t } = useTranslation(['common', 'home'])
@ -18,7 +19,7 @@ const HomeTopSection = () => {
// }, [])
return (
<div className="lg:pl-12 pl-6 py-24 relative">
<SectionWrapper>
<div className="w-full md:w-1/2 lg:w-2/5">
<h1 className="mb-6">{t('home:long-short-everything')}</h1>
<CheckBullet>{t('home:bullet-1')}</CheckBullet>
@ -43,7 +44,7 @@ const HomeTopSection = () => {
alt=""
/> */}
<div className="absolute w-1/2 h-full top-40 right-0 bg-th-button mix-blend-screen rounded-full filter blur-3xl opacity-10 animate-blob"></div>
</div>
</SectionWrapper>
)
}

View File

@ -0,0 +1,104 @@
import { useTranslation } from 'next-i18next'
import { useTheme } from 'next-themes'
import { FunctionComponent, useState } from 'react'
import { Cell, Pie, PieChart, ResponsiveContainer } from 'recharts'
import { COLORS } from '../../styles/colors'
import SectionWrapper from '../shared/SectionWrapper'
const CHART_DATA = [
{ label: 'mango-dao', desc: 'mango-dao-desc', value: 50 },
{ label: 'team', desc: 'team-desc', value: 22 },
{ label: 'public-sale', desc: 'public-sale-desc', value: 10 },
{
label: 'liquidity-incentives',
desc: 'liquidity-incentives-desc',
value: 18,
},
]
const CHART_COLORS = [
{
Mango: '#89B92A',
Light: '#60bf4f',
},
{
Mango: '#f1c84b',
Light: '#141414',
},
{
Mango: '#F84638',
Light: '#BE6A6A',
},
{
Mango: '#9189ae',
Light: '#878787',
},
]
const Distribution: FunctionComponent = () => {
const { t } = useTranslation('mngo')
const [mouseData, setMouseData] = useState(CHART_DATA[0].label)
const { theme } = useTheme()
const handleMouseMove = (coords: any) => {
if (coords) {
setMouseData(coords.label)
}
}
return (
<SectionWrapper>
<h2 className="mb-6">{t('distribution')}</h2>
<div className="flex flex-col-reverse md:flex-row items-center md:justify-between">
<div className="grid grid-cols-4 gap-6 w-full md:w-1/2">
{CHART_DATA.map((data) => {
const { label, desc, value } = data
return (
<div
className={`${
label === mouseData ? '' : 'opacity-40'
} col-span-4 sm:col-span-2 md:col-span-4 default-transition cursor-pointer w-max`}
key={`item-${label}`}
onMouseEnter={() => setMouseData(label)}
>
<h3>{`${value}% ${label}`}</h3>
<p>{desc}</p>
</div>
)
})}
</div>
<div className="w-1/2 h-[280px] lg:h-[360px] mb-8 md:mb-0">
<ResponsiveContainer>
<PieChart>
<Pie
cursor="pointer"
data={CHART_DATA}
dataKey="value"
cx="50%"
cy="50%"
outerRadius={'100%'}
innerRadius={'70%'}
minAngle={2}
startAngle={90}
endAngle={450}
onMouseMove={handleMouseMove}
>
{CHART_DATA.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={CHART_COLORS[index][theme]}
fillOpacity={mouseData === entry.label ? 1 : 0.4}
stroke={COLORS.BKG1[theme]}
strokeWidth={4}
/>
))}
</Pie>
</PieChart>
</ResponsiveContainer>
</div>
</div>
</SectionWrapper>
)
}
export default Distribution

View File

@ -0,0 +1,37 @@
import { useTranslation } from 'next-i18next'
import dynamic from 'next/dynamic'
import Button from '../shared/Button'
import SectionWrapper from '../shared/SectionWrapper'
import TokenStats from './TokenStats'
const Distribution = dynamic(() => import('./Distribution'), {
ssr: false,
})
const MngoPage = () => {
const { t } = useTranslation(['common, mngo'])
return (
<>
<SectionWrapper>
<div className="w-full flex flex-col items-center text-center">
<h1 className="mb-6">{t('mngo:powered-by-mngo')}</h1>
<p className="text-base">{t('mngo:mngo-desc')}</p>
<div className="mt-8">
<a
href="https://trade.mango.markets"
target="_blank"
rel="noopener noreferrer"
>
<Button size="large">{t('mngo:buy-mngo')}</Button>
</a>
</div>
</div>
<div className="absolute w-2/3 h-full top-40 -right-80 bg-th-down mix-blend-screen rounded-full filter blur-3xl opacity-20 animate-blob" />
<div className="absolute w-1/2 h-full top-60 left-0 bg-th-button mix-blend-screen rounded-full filter blur-3xl opacity-10 delay-1000 animate-blob" />
</SectionWrapper>
<TokenStats />
<Distribution />
</>
)
}
export default MngoPage

View File

@ -0,0 +1,88 @@
import { useQuery } from '@tanstack/react-query'
import { useTranslation } from 'next-i18next'
import { formatCurrencyValue, formatNumericValue } from '../../utils'
import SectionWrapper from '../shared/SectionWrapper'
const fetchTokenInfo = async () => {
const response = await fetch(
'https://api.coingecko.com/api/v3/coins/mango-markets?localization=false&tickers=false&developer_data=false&sparkline=false'
)
const data = await response.json()
return data
}
const TokenStats = () => {
const { t } = useTranslation('mngo')
const coingeckoMngoInfo = useQuery<{ market_data: any; name: string }, Error>(
['ip-address'],
() => fetchTokenInfo(),
{
cacheTime: 1000 * 60 * 15,
staleTime: 1000 * 60 * 5,
retry: 3,
refetchOnWindowFocus: false,
// enabled: !!coingeckoId,
}
)
return (
<SectionWrapper>
<h2 className="mb-6">{t('mngo-stats')}</h2>
{coingeckoMngoInfo?.data?.market_data ? (
<div className="border-b border-th-bkg-3 w-2/3">
<StatsRow
isCurrency
title={t('mngo:price')}
value={coingeckoMngoInfo?.data?.market_data?.current_price?.usd}
/>
<StatsRow
isCurrency
title={t('mngo:market-cap')}
value={coingeckoMngoInfo?.data?.market_data?.market_cap?.usd}
/>
<StatsRow
isCurrency
title={t('mngo:fdv')}
value={
coingeckoMngoInfo?.data?.market_data?.fully_diluted_valuation?.usd
}
/>
<StatsRow
title={t('mngo:circulating-supply')}
value={coingeckoMngoInfo?.data?.market_data?.circulating_supply}
/>
<StatsRow
title={t('mngo:total-supply')}
value={coingeckoMngoInfo?.data?.market_data?.total_supply}
/>
</div>
) : null}
</SectionWrapper>
)
}
export default TokenStats
const StatsRow = ({
title,
value,
isCurrency,
}: {
title: string
value: string | undefined
isCurrency?: boolean
}) => {
return (
<div className="flex justify-between p-6 border-t border-th-bkg-3">
<p>{title}</p>
<p className="font-mono text-th-fgd-1">
{value
? isCurrency
? formatCurrencyValue(value)
: formatNumericValue(value)
: 'N/A'}
</p>
</div>
)
}

View File

@ -21,7 +21,7 @@ const DesktopNavigation = () => {
path="/mango-dao"
title={t('navigation:mango-dao')}
/>
<NavigationItemLink path="/token" title={t('navigation:token')} />
<NavigationItemLink path="/mngo" title={t('navigation:mngo-token')} />
</NavigationItemPanel>
</NavigationItem>
<NavigationItem title={t('navigation:products')}>
@ -30,7 +30,7 @@ const DesktopNavigation = () => {
path="/mango-dao"
title={t('navigation:mango-dao')}
/>
<NavigationItemLink path="/token" title={t('navigation:token')} />
<NavigationItemLink path="/mngo" title={t('navigation:mngo-token')} />
</NavigationItemPanel>
</NavigationItem>
<NavigationItem title={t('navigation:developers')}>

View File

@ -0,0 +1,19 @@
import { ReactNode } from 'react'
const SectionWrapper = ({
children,
className,
}: {
children: ReactNode
className?: string
}) => {
return (
<div
className={`bg-th-bkg-1 lg:px-12 pl-6 py-24 relative overflow-hidden ${className}`}
>
{children}
</div>
)
}
export default SectionWrapper

View File

@ -28,6 +28,7 @@
"@sendgrid/client": "^7.4.3",
"@solana/spl-token": "^0.1.3",
"@solana/web3.js": "^1.5.0",
"@tanstack/react-query": "^4.24.10",
"gsap": "^3.7.1",
"i18next": "^22.4.10",
"immer": "^9.0.1",
@ -39,7 +40,7 @@
"react-dom": "^18.2.0",
"react-fast-marquee": "^1.2.1",
"react-i18next": "^12.1.5",
"recharts": "^2.0.10",
"recharts": "^2.4.3",
"zustand": "^3.4.1"
},
"devDependencies": {

View File

@ -3,6 +3,9 @@ import { ThemeProvider } from 'next-themes'
import '../styles/index.css'
import LayoutWrapper from '../components/layout/LayoutWrapper'
import { appWithTranslation } from 'next-i18next'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
function App({ Component, pageProps }) {
const title = 'Mango Markets'
@ -37,11 +40,13 @@ function App({ Component, pageProps }) {
<link rel="manifest" href="/manifest.json"></link>
</Head>
<ThemeProvider defaultTheme="Mango">
<LayoutWrapper>
<Component {...pageProps} />
</LayoutWrapper>
</ThemeProvider>
<QueryClientProvider client={queryClient}>
<ThemeProvider defaultTheme="Mango">
<LayoutWrapper>
<Component {...pageProps} />
</LayoutWrapper>
</ThemeProvider>
</QueryClientProvider>
</>
)
}

23
pages/mngo.tsx Normal file
View File

@ -0,0 +1,23 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { NextPage } from 'next'
import MngoPage from '../components/mngo/MngoPage'
export async function getStaticProps({ locale }: { locale: string }) {
return {
props: {
...(await serverSideTranslations(locale, [
'common',
'mngo',
'footer',
'navigation',
])),
// Will be passed to the page component as props
},
}
}
const Mngo: NextPage = () => {
return <MngoPage />
}
export default Mngo

34
styles/colors.ts Normal file
View File

@ -0,0 +1,34 @@
export const COLORS: any = {
BKG1: {
Mango: '#18181C',
Light: '#fcfcfc',
},
BKG2: {
Mango: '#282433',
Light: '#f0f0f0',
},
BKG3: {
Mango: '#332e42',
Light: '#e3e3e3',
},
BKG4: {
Mango: '#3f3851',
Light: '#d6d6d6',
},
FGD4: {
Mango: '#9189ae',
Light: '#878787',
},
UP: {
Mango: '#89B92A',
Light: '#60bf4f',
},
ACTIVE: {
Mango: '#f1c84b',
Light: '#141414',
},
DOWN: {
Mango: '#F84638',
Light: '#BE6A6A',
},
}

View File

@ -207,6 +207,11 @@ p {
@apply text-th-fgd-3;
}
.font-mono {
-webkit-font-feature-settings: 'zero' 1;
font-feature-settings: 'zero' 1;
}
li {
@apply text-sm text-th-fgd-3;
}

View File

@ -13,7 +13,10 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
"incremental": true,
"paths": {
"react": ["./node_modules/@types/react"]
}
},
"exclude": ["node_modules", ".next", "out"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"]

File diff suppressed because one or more lines are too long

91
utils/index.tsx Normal file
View File

@ -0,0 +1,91 @@
export const formatNumericValue = (
value: number | string,
decimals?: number
): string => {
const numberValue = Number(value)
let formattedValue
if (numberValue > -0.0000000001 && numberValue < 0.000000001) {
formattedValue = '0'
} else if (decimals) {
formattedValue = roundValue(numberValue, decimals)
} else if (Math.abs(numberValue) >= 1000) {
formattedValue = roundValue(numberValue, 0)
} else if (Math.abs(numberValue) >= 0.1) {
formattedValue = roundValue(numberValue, 3)
} else {
formattedValue = roundValue(numberValue, 9)
}
return formattedValue
}
export const formatCurrencyValue = (
value: number | string,
decimals?: number
): string => {
const numberValue = Number(value)
let formattedValue
if (numberValue > -0.0000000001 && numberValue < 0.000000001) {
formattedValue = '$0.00'
} else if (decimals) {
formattedValue = Intl.NumberFormat('en', {
minimumFractionDigits: decimals,
maximumFractionDigits: decimals,
style: 'currency',
currency: 'USD',
}).format(numberValue)
} else if (Math.abs(numberValue) >= 1000) {
formattedValue = usdFormatter0.format(numberValue)
} else if (Math.abs(numberValue) >= 0.1) {
formattedValue = usdFormatter2.format(numberValue)
} else {
formattedValue = usdFormatter3Sig.format(numberValue)
}
if (formattedValue === '-$0.00') return '$0.00'
return formattedValue
}
const roundValue = (value: number, decimals: number): string => {
const roundedValue = parseFloat(value.toFixed(decimals))
if (decimals === 2) return digits2.format(roundedValue)
if (decimals === 3) return digits3.format(roundedValue)
if (decimals === 4) return digits4.format(roundedValue)
if (decimals === 5) return digits5.format(roundedValue)
if (decimals === 6) return digits6.format(roundedValue)
if (decimals === 7) return digits7.format(roundedValue)
if (decimals === 8) return digits8.format(roundedValue)
if (decimals === 9) return digits9.format(roundedValue)
return roundedValue.toLocaleString(undefined, {
maximumFractionDigits: decimals,
})
}
const digits2 = new Intl.NumberFormat('en', { maximumFractionDigits: 2 })
const digits3 = new Intl.NumberFormat('en', { maximumFractionDigits: 3 })
const digits4 = new Intl.NumberFormat('en', { maximumFractionDigits: 4 })
const digits5 = new Intl.NumberFormat('en', { maximumFractionDigits: 5 })
const digits6 = new Intl.NumberFormat('en', { maximumFractionDigits: 6 })
const digits7 = new Intl.NumberFormat('en', { maximumFractionDigits: 7 })
const digits8 = new Intl.NumberFormat('en', { maximumFractionDigits: 8 })
const digits9 = new Intl.NumberFormat('en', { maximumFractionDigits: 9 })
const usdFormatter0 = Intl.NumberFormat('en', {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
style: 'currency',
currency: 'USD',
})
const usdFormatter2 = Intl.NumberFormat('en', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
style: 'currency',
currency: 'USD',
})
const usdFormatter3Sig = Intl.NumberFormat('en', {
minimumSignificantDigits: 3,
maximumSignificantDigits: 3,
style: 'currency',
currency: 'USD',
})

View File

@ -911,6 +911,19 @@
dependencies:
tslib "^2.4.0"
"@tanstack/query-core@4.24.10":
version "4.24.10"
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.24.10.tgz#758e1f5b2d7faf7316d299facd272a9f64c26299"
integrity sha512-2QywqXEAGBIUoTdgn1lAB4/C8QEqwXHj2jrCLeYTk2xVGtLiPEUD8jcMoeB2noclbiW2mMt4+Fq7fZStuz3wAQ==
"@tanstack/react-query@^4.24.10":
version "4.24.10"
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.24.10.tgz#2e1004bb1d1f55198961a21e875e2c65ec865130"
integrity sha512-FY1DixytOcNNCydPQXLxuKEV7VSST32CAuJ55BjhDNqASnMLZn+6c30yQBMrODjmWMNwzfjMZnq0Vw7C62Fwow==
dependencies:
"@tanstack/query-core" "4.24.10"
use-sync-external-store "^1.2.0"
"@testing-library/dom@^7.28.1":
version "7.31.2"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.31.2.tgz#df361db38f5212b88555068ab8119f5d841a8c4a"
@ -2414,9 +2427,9 @@ dset@^2.0.1:
integrity sha512-hlQYwNEdW7Qf8zxysy+yN1E8C/SxRst3Z9n+IvXOR35D9bPVwNHhnL8ZBeoZjvinuGrlvGg6pAMDwhmjqFDgjA==
electron-to-chromium@^1.4.284:
version "1.4.305"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.305.tgz#e4dfe3e06ab783f33171f9bde9e8ed092510fcd0"
integrity sha512-WETy6tG0CT5gm1O+xCbyapWNsCcmIvrn4NHViIGYo2AT8FV2qUCXdaB+WqYxSv/vS5mFqhBYnfZAAkVArjBmUg==
version "1.4.307"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.307.tgz#0301d9a87d95f47591550124a985a3eea6074a6f"
integrity sha512-n54V0t4LyHM2oQiAOmD3qC2peB+orUktXORSnWxqtv3uEMSoUcsq+hoMpU08VEJCNbfgBtzy169P0TcrLuq53A==
emittery@^0.7.1:
version "0.7.2"
@ -5655,7 +5668,7 @@ recharts-scale@^0.4.4:
dependencies:
decimal.js-light "^2.4.1"
recharts@^2.0.10:
recharts@^2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.4.3.tgz#23b7cd988423449b04a826baa057675b833789b1"
integrity sha512-/hkRHTQShEOKDYd2OlKLIvGA0X9v/XVO/mNeRoDHg0lgFRL2KbGzeqVnStI3mMfORUZ6Hak4JbQ+uDiin1Foqg==
@ -6653,6 +6666,11 @@ url-parse@^1.5.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
use-sync-external-store@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"