mirror of
https://github.com/acid-info/logos-ordinals-dashboard.git
synced 2025-02-11 04:36:37 +00:00
feat: implement explore page
This commit is contained in:
parent
e42c224b86
commit
b896eca534
81
src/components/Explore/OperatorFilter/OperatorFilter.tsx
Normal file
81
src/components/Explore/OperatorFilter/OperatorFilter.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { Checkbox } from '@acid-info/lsd-react'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
|
interface FilterOption {
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterOptions: FilterOption[] = [
|
||||||
|
{
|
||||||
|
label: 'All',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Archetype',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Comp',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Helmet',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Jacket',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Background',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
interface OperatorFilterProps {}
|
||||||
|
|
||||||
|
const OperatorFilter: React.FC<OperatorFilterProps> = () => {
|
||||||
|
// checkbox based on filterOptions
|
||||||
|
const [checked, setChecked] = useState<number | null>(null)
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
{filterOptions.map((option, index) => (
|
||||||
|
<FilterOption key={index}>
|
||||||
|
<Checkbox
|
||||||
|
checked={index === checked}
|
||||||
|
onChange={() => setChecked(index)}
|
||||||
|
/>
|
||||||
|
<span className="label">{option.label}</span>
|
||||||
|
</FilterOption>
|
||||||
|
))}
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
display: flex;
|
||||||
|
margin-top: 74px;
|
||||||
|
align-items: start;
|
||||||
|
gap: 2px;
|
||||||
|
justify-content: start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 74px auto 0 auto;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: flex;
|
||||||
|
padding: 6px 16px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991px) {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const FilterOption = styled.div`
|
||||||
|
display: flex;
|
||||||
|
padding: 8px 23px 8px 8px;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--grey-900);
|
||||||
|
`
|
||||||
|
|
||||||
|
export default OperatorFilter
|
1
src/components/Explore/OperatorFilter/index.ts
Normal file
1
src/components/Explore/OperatorFilter/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as OperatorFilter } from './OperatorFilter'
|
105
src/components/Explore/OperatorGrid/OperatorGrid.tsx
Normal file
105
src/components/Explore/OperatorGrid/OperatorGrid.tsx
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { breakpoints } from '@/configs/ui.configs'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
interface OperatorGridProps {}
|
||||||
|
|
||||||
|
const operatorImages = [
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/1.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/2.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/3.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/4.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/5.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/6.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/7.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/1.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/2.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/3.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/4.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/5.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/6.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/7.gif',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/dashboard/mock/operators/1.gif',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const OperatorGrid: React.FC<OperatorGridProps> = () => {
|
||||||
|
return (
|
||||||
|
<StyledOperatorGrid>
|
||||||
|
{operatorImages.map((operator, index) => (
|
||||||
|
<Link href={`/explore/${index + 1}`} key={'explore-operator-' + index}>
|
||||||
|
<GridItem>
|
||||||
|
<img
|
||||||
|
key={index}
|
||||||
|
src={operator.image}
|
||||||
|
alt={`Operator ${index + 1}`}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</GridItem>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</StyledOperatorGrid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// grid: 6 responsive columns
|
||||||
|
const StyledOperatorGrid = styled.section`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(216px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
@media (max-width: ${breakpoints.md}px) {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${breakpoints.sm}px) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
object-fit: contain;
|
||||||
|
width: 216px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const GridItem = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
`
|
||||||
|
|
||||||
|
export default OperatorGrid
|
1
src/components/Explore/OperatorGrid/index.ts
Normal file
1
src/components/Explore/OperatorGrid/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as OperatorGrid } from './OperatorGrid'
|
55
src/components/Footer/Footer.tsx
Normal file
55
src/components/Footer/Footer.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import styled from '@emotion/styled'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
interface FooterProps {}
|
||||||
|
|
||||||
|
const Footer: React.FC<FooterProps> = () => {
|
||||||
|
return (
|
||||||
|
<StyledFooter>
|
||||||
|
<span className="logo">Logos Operators</span>
|
||||||
|
<nav className="footer-nav">
|
||||||
|
<a href="#terms">Terms of Use</a>
|
||||||
|
<a href="#privacy">Privacy Policy</a>
|
||||||
|
<a href="#discord">Discord</a>
|
||||||
|
<a href="#manifesto">Manifesto</a>
|
||||||
|
</nav>
|
||||||
|
<span className="copyright">
|
||||||
|
All right reserved ©{new Date().getFullYear()}
|
||||||
|
</span>
|
||||||
|
</StyledFooter>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyledFooter = styled.footer`
|
||||||
|
display: flex;
|
||||||
|
margin-top: 200px;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.footer-nav {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
display: flex;
|
||||||
|
min-width: 240px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-nav a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991px) {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default Footer
|
1
src/components/Footer/index.ts
Normal file
1
src/components/Footer/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as Footer } from './Footer'
|
@ -1,4 +1,5 @@
|
|||||||
import styled from '@emotion/styled'
|
import styled from '@emotion/styled'
|
||||||
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Navbar } from '../Navbar'
|
import { Navbar } from '../Navbar'
|
||||||
|
|
||||||
@ -7,7 +8,9 @@ interface NavbarProps {}
|
|||||||
const Header: React.FC<NavbarProps> = () => {
|
const Header: React.FC<NavbarProps> = () => {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Logo src="/assets/logo.svg" alt="Logo" />
|
<Link href="/">
|
||||||
|
<Logo src="/assets/logo.svg" alt="Logo" />
|
||||||
|
</Link>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<UserActions>
|
<UserActions>
|
||||||
<WalletButton>
|
<WalletButton>
|
||||||
|
@ -1,17 +1,44 @@
|
|||||||
import styled from '@emotion/styled'
|
import styled from '@emotion/styled'
|
||||||
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
interface NavbarProps {}
|
interface NavbarProps {}
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: 'Dashboard',
|
||||||
|
href: '/dashboard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Explore',
|
||||||
|
href: '/explore',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Leaderboard',
|
||||||
|
href: '/leaderboard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Docs',
|
||||||
|
href: '/docs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Auction',
|
||||||
|
href: '/auction',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Roles',
|
||||||
|
href: '/roles',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const Navbar: React.FC<NavbarProps> = () => {
|
const Navbar: React.FC<NavbarProps> = () => {
|
||||||
return (
|
return (
|
||||||
<Navigation>
|
<Navigation>
|
||||||
<NavItem active>Dashboard</NavItem>
|
{items.map((item, index) => (
|
||||||
<NavItem>Explore</NavItem>
|
<Link href={item.href} key={'navbar-item-' + index}>
|
||||||
<NavItem>Leaderboard</NavItem>
|
<NavItem key={index}>{item.label}</NavItem>
|
||||||
<NavItem>Docs</NavItem>
|
</Link>
|
||||||
<NavItem>Auction</NavItem>
|
))}
|
||||||
<NavItem>Roles</NavItem>
|
|
||||||
</Navigation>
|
</Navigation>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -40,8 +67,9 @@ const NavItem = styled.li<{ active?: boolean }>`
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
cursor: pointer;
|
color: rgb(var(--lsd-text-primary));
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
${(props) =>
|
${(props) =>
|
||||||
props.active &&
|
props.active &&
|
||||||
|
39
src/containers/Explore/ExploreContainer.tsx
Normal file
39
src/containers/Explore/ExploreContainer.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { OperatorFilter } from '@/components/Explore/OperatorFilter'
|
||||||
|
import { OperatorGrid } from '@/components/Explore/OperatorGrid'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
interface ExploreSectionProps {}
|
||||||
|
|
||||||
|
const ExploreSection: React.FC<ExploreSectionProps> = () => {
|
||||||
|
return (
|
||||||
|
<StyledExploreSection>
|
||||||
|
<h1 className="section-title">Operators</h1>
|
||||||
|
<OperatorFilter />
|
||||||
|
<OperatorGrid />
|
||||||
|
</StyledExploreSection>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyledExploreSection = styled.main`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: 48px;
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991px) {
|
||||||
|
padding: 0 20px;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default ExploreSection
|
1
src/containers/Explore/index.ts
Normal file
1
src/containers/Explore/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as DashboardContainer } from './ExploreContainer'
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Footer } from '@/components/Footer'
|
||||||
import { Header } from '@/components/Header/Header'
|
import { Header } from '@/components/Header/Header'
|
||||||
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
|
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
|
||||||
import styled from '@emotion/styled'
|
import styled from '@emotion/styled'
|
||||||
@ -12,6 +13,7 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = (
|
|||||||
<Container>
|
<Container>
|
||||||
<Header />
|
<Header />
|
||||||
<main>{props.children}</main>
|
<main>{props.children}</main>
|
||||||
|
<Footer />
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,35 @@
|
|||||||
|
import { Footer } from '@/components/Footer'
|
||||||
|
import { Header } from '@/components/Header/Header'
|
||||||
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
|
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
|
||||||
import styled from '@emotion/styled'
|
import styled from '@emotion/styled'
|
||||||
import { PropsWithChildren } from 'react'
|
import React, { PropsWithChildren } from 'react'
|
||||||
|
|
||||||
const Root = styled.div`
|
interface DefaultLayoutProps {}
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(16, 1fr);
|
|
||||||
gap: 0 16px;
|
|
||||||
|
|
||||||
max-width: ${uiConfigs.maxContainerWidth}px;
|
const DefaultLayout: React.FC<DefaultLayoutProps> = (
|
||||||
margin: 0 auto;
|
props: PropsWithChildren,
|
||||||
|
) => {
|
||||||
@media (max-width: ${breakpoints.md}px) {
|
|
||||||
flex-direction: column-reverse;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const Main = styled.main`
|
|
||||||
width: 100%;
|
|
||||||
grid-column: 1 / 17;
|
|
||||||
margin-top: ${uiConfigs.navbarRenderedHeight}px;
|
|
||||||
margin-bottom: 148px;
|
|
||||||
|
|
||||||
@media (max-width: ${breakpoints.md}px) {
|
|
||||||
margin-top: ${uiConfigs.navbarMobileHeight}px;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function DefaultLayout(props: PropsWithChildren) {
|
|
||||||
return (
|
return (
|
||||||
<Root>
|
<Container>
|
||||||
<Main>{props.children}</Main>
|
<Header />
|
||||||
</Root>
|
<main>{props.children}</main>
|
||||||
|
<Footer />
|
||||||
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: ${uiConfigs.maxContainerWidth}px;
|
||||||
|
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px 0;
|
||||||
|
|
||||||
|
@media (max-width: ${breakpoints.md}px) {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default DefaultLayout
|
||||||
|
35
src/layouts/ExploreLayout/Explore.layout.tsx
Normal file
35
src/layouts/ExploreLayout/Explore.layout.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Footer } from '@/components/Footer'
|
||||||
|
import { Header } from '@/components/Header/Header'
|
||||||
|
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
import React, { PropsWithChildren } from 'react'
|
||||||
|
|
||||||
|
interface ExploreLayoutProps {}
|
||||||
|
|
||||||
|
const ExploreLayout: React.FC<ExploreLayoutProps> = (
|
||||||
|
props: PropsWithChildren,
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Header />
|
||||||
|
<main>{props.children}</main>
|
||||||
|
<Footer />
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: ${uiConfigs.maxContainerWidth}px;
|
||||||
|
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px 0;
|
||||||
|
|
||||||
|
@media (max-width: ${breakpoints.md}px) {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default ExploreLayout
|
1
src/layouts/ExploreLayout/index.ts
Normal file
1
src/layouts/ExploreLayout/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as DashboardLayout } from './Explore.layout'
|
18
src/pages/explore.tsx
Normal file
18
src/pages/explore.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { SEO } from '@/components/SEO'
|
||||||
|
import ExploreContainer from '@/containers/Explore/ExploreContainer'
|
||||||
|
import ExploreLayout from '@/layouts/ExploreLayout/Explore.layout'
|
||||||
|
|
||||||
|
type PageProps = {}
|
||||||
|
|
||||||
|
export default function ExplorePage(props: PageProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SEO />
|
||||||
|
<ExploreContainer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ExplorePage.getLayout = function getLayout(page: React.ReactNode) {
|
||||||
|
return <ExploreLayout>{page}</ExploreLayout>
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user