feat: implement bu page draft

This commit is contained in:
jinhojang6 2023-11-16 04:44:17 +09:00
parent d09a23418f
commit 27b5565421
31 changed files with 1226 additions and 205 deletions

BIN
public/photos/meetup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 KiB

BIN
public/photos/mock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,29 @@
import styled from '@emotion/styled'
import BUSection from '../BUSection'
type Props = {
data: any
}
const BUAbout = ({ data }: Props) => {
return (
<Container>
<BUSection
title={'About'}
description={
<>
<p>{data?.description}</p>
</>
}
/>
</Container>
)
}
const Container = styled.div`
display: flex;
flex-direction: column;
padding: 0 16px;
`
export default BUAbout

View File

@ -0,0 +1,285 @@
import { breakpoints } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import Image from 'next/image'
import Link from 'next/link'
import { businessUnitMark } from '../../../utils/bu'
import { Badge } from '../Badge'
import { Button } from '../Button'
interface Props {
data: any
}
export const BUHero = ({ data }: Props) => {
return (
<Container>
<MarkContainer>
<Mark
width={520}
height={520}
src={businessUnitMark(data?.bu)}
alt={data?.bu + '-mark'}
/>
</MarkContainer>
<BUInfo>
<Header>
<Title>
<TitleText>{data?.bu}</TitleText>
<Badge>est. {data?.est}</Badge>
</Title>
</Header>
<Content>
<table>
<thead>
<tr>
<th>Development status</th>
<th>Vertical</th>
</tr>
</thead>
<tbody>
<tr>
<td>{data?.devStatus}</td>
<td>{data?.vertical}</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Achievements</th>
<th>Founders</th>
</tr>
</thead>
<tbody>
<tr>
<td>{data?.achievements}</td>
<td>{data?.founders}</td>
</tr>
</tbody>
</table>
<Description>{data.description}</Description>
<table>
<thead>
<tr>
<th>Connect:</th>
<th>Programme lead:</th>
</tr>
</thead>
<tbody>
<tr>
<td>
{data?.connect?.map((item: any) => (
<Link
key={item.label + '-link'}
href={item.link}
target="_blank"
>
{item?.label}
</Link>
))}
</td>
<td>{data?.lead}</td>
</tr>
</tbody>
</table>
<Buttons>
<Link href={data?.website} target="_blank">
<Button
color="black"
width="162px"
height="54px"
padding="0 0 0 18px"
icon
>
Website
</Button>
</Link>
<Link href={data?.github} target="_blank">
<Button
color="grey"
width="162px"
height="54px"
padding="0 0 0 18px"
icon
>
Github
</Button>
</Link>
</Buttons>
</Content>
</BUInfo>
</Container>
)
}
const Container = styled.div`
display: flex;
width: 100%;
flex-wrap: wrap;
box-sizing: border-box;
justify-content: space-between;
`
const MarkContainer = styled.div`
box-sizing: border-box;
@media (max-width: ${breakpoints.md}px) {
display: none;
}
`
const Mark = styled(Image)`
@media (max-width: ${breakpoints.md}px) {
display: none;
}
`
const BUInfo = styled.div`
display: flex;
flex-direction: column;
width: 50%;
padding: 32px 16px 48px 16px;
box-sizing: border-box;
@media (max-width: ${breakpoints.md}px) {
width: 100%;
padding: 16px 0 16px 16px;
}
`
const Header = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
width: 100%;
padding-bottom: 32px;
box-sizing: border-box;
@media (max-width: ${breakpoints.md}px) {
padding-block: 16px;
}
`
const Title = styled.div`
display: flex;
gap: 16px;
align-items: center;
width: 100%;
@media (max-width: ${breakpoints.md}px) {
gap: 12px;
}
`
const TitleText = styled.h3`
font-size: 90px;
line-height: 103px;
text-transform: capitalize;
@media (max-width: ${breakpoints.md}px) {
font-size: 16px;
}
`
const Content = styled.div`
width: 100%;
padding-bottom: 40px;
p {
text-overflow: ellipsis;
font-size: 22px;
font-weight: 400;
line-height: 122%;
margin-top: 40px;
margin-bottom: 32px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th {
color: rgba(0, 0, 0, 0.35);
}
table td,
table th {
width: calc(100% / 2);
vertical-align: baseline;
}
tr > td > a {
font-size: 18px;
line-height: 22px;
&:not(:last-child) {
&:after {
fill: rgba(0, 0, 0, 0.35);
content: '•';
margin-inline: 8px;
text-decoration: none;
display: inline-block;
}
}
}
table thead {
border-top: 1px solid rgba(0, 0, 0, 0.18);
}
table th,
table tr {
border: none;
font-weight: 400;
text-align: left;
font-size: 18px;
line-height: 130%;
padding: 20px 0 8px 0;
}
@media (max-width: ${breakpoints.md}px) {
p {
font-size: 14px;
font-weight: 400;
line-height: 126%;
margin-top: 24px;
margin-bottom: 24px;
}
table {
margin-bottom: 16px;
}
table th,
table tr {
font-size: 14px;
padding: 16px 0 8px 0;
}
}
@media (max-width: ${breakpoints.md}px) {
padding-bottom: 16px;
button {
width: 100%;
}
}
`
const Description = styled.p`
max-width: 817px;
font-size: 22px;
line-height: 122%;
margin-top: 8px;
`
const Buttons = styled.div`
display: flex;
gap: 16px;
padding-top: 24px;
`
export default BUHero

View File

@ -0,0 +1,87 @@
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import { Tag } from '../Tag'
type Props = {
activeMenus: string[]
setActiveMenus: React.Dispatch<React.SetStateAction<string[]>>
}
const BUMenuFilter = ({ activeMenus, setActiveMenus }: Props) => {
const menus = [
'Testimonials',
'About',
'Milestones',
'Team',
'Jobs',
'Challenges',
'Media',
]
const toggleMenu = (menu: string) => {
if (activeMenus.includes(menu)) {
setActiveMenus((preveMenus) => preveMenus.filter((item) => item !== menu))
} else {
setActiveMenus((preveMenus) => [...preveMenus, menu])
}
}
return (
<Container>
<Border />
<Menus>
<Tag
active={activeMenus.length === 0}
onClick={() => setActiveMenus([])}
>
All
</Tag>
{menus.map((menu: string) => (
<Tag
active={activeMenus.includes(menu)}
key={menu + '-tag'}
onClick={() => toggleMenu(menu)}
>
{menu}
</Tag>
))}
</Menus>
<Border />
</Container>
)
}
const Container = styled.div`
display: flex;
flex-direction: column;
margin-top: calc(${uiConfigs.navbarHeight}px + 24px);
margin-bottom: 20px;
padding-inline: 16px;
`
const Menus = styled.div`
display: flex;
overflow-x: auto;
gap: 16px;
padding: 16px 0;
&::-webkit-scrollbar {
display: none;
}
@media (max-width: ${breakpoints.md}px) {
width: calc(100vw - 32px);
margin-left: -16px;
padding: 16px;
}
`
const Border = styled.hr`
background: rgba(0, 0, 0, 0.18);
border: 0;
height: 1px;
width: 100%;
margin: 0;
`
export default BUMenuFilter

View File

@ -0,0 +1,19 @@
import styled from '@emotion/styled'
type Props = {
children: React.ReactNode
}
const BUMenus = ({ children }: Props) => {
return <Container>{children}</Container>
}
const Container = styled.div`
display: flex;
flex-direction: column;
gap: 180px;
margin-bottom: 324px;
`
export default BUMenus

View File

@ -0,0 +1,77 @@
import { breakpoints } from '@/configs/ui.configs'
import styled from '@emotion/styled'
type Props = {
title: string
description: React.ReactNode
}
const BUSection = ({ title, description }: Props) => {
return (
<Container>
<TitleContainer>
<Title>{title}</Title>
</TitleContainer>
<Content>{description}</Content>
</Container>
)
}
const Container = styled.div`
display: flex;
width: 100%;
justify-content: space-between;
margin-top: 180px;
border-top: 1px solid rgba(0, 0, 0, 0.18);
box-sizing: border-box;
@media (max-width: ${breakpoints.md}px) {
margin-top: 60px;
flex-direction: column;
}
`
const Content = styled.div`
width: 100%;
padding-top: 24px;
padding-bottom: 32px;
h3 {
font-size: 36px;
font-weight: 400;
line-height: 42px;
margin-bottom: 32px;
}
p {
font-size: 22px;
font-weight: 400;
line-height: 122%;
white-space: pre-wrap;
max-width: 817px;
}
`
const TitleContainer = styled.div`
width: 100%;
padding-top: 24px;
@media (max-width: ${breakpoints.md}px) {
border-bottom: 1px solid rgba(0, 0, 0, 0.18);
}
`
const Title = styled.h3`
font-size: 52px;
font-weight: 400;
line-height: 60px;
text-transform: capitalize;
@media (max-width: ${breakpoints.md}px) {
font-size: 22px;
line-height: 122%;
padding-block: 16px;
}
`
export default BUSection

View File

@ -0,0 +1,34 @@
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import React from 'react'
const BUVideo: React.FC = () => {
return (
<Container>
<Image src="right-side.gif" alt="bu-video" />
</Container>
)
}
const Container = styled.div`
background-color: black;
background-size: 100%;
box-sizing: border-box;
width: 100%;
`
const Image = styled.img`
position: relative;
top: ${uiConfigs.navbarHeight}px;
height: 142px;
top: 0px;
width: 100%;
box-sizing: border-box;
@media (max-width: ${breakpoints.md}px) {
width: 100%;
height: 84px;
}
`
export default BUVideo

View File

@ -0,0 +1,93 @@
import styled from '@emotion/styled'
import BUSection from '../BUSection'
const media = [
{
title: 'Meetup',
imageUrl: '/photos/meetup.png',
colSpan: 2,
rowSpan: 2,
},
{
title: 'Meetup',
imageUrl: '/photos/meetup.png',
},
{
title: 'Meetup',
imageUrl: '/photos/meetup.png',
},
]
const BUTeam = () => {
return (
<Container>
<BUSection
title={'Media'}
description={
<>
<h3>
We are powering the data storage layer of the Logos Network State.
</h3>
<p>
Logos is a grassroots movement to provide trust-minimized,
corruption-resistant governing services and social institutions to
peaceful people worldwide. Learn more about our ambitious vision.
</p>
</>
}
/>
<GridContainer>
<Section>
{media.map((image, index) => (
<GridItem
key={index}
colSpan={image?.colSpan ?? 1}
rowSpan={image?.rowSpan ?? 1}
>
<img
src={image.imageUrl}
alt={image.title}
style={{ width: '100%', height: 'auto' }}
/>
<p>{image.title}</p>
</GridItem>
))}
</Section>
</GridContainer>
</Container>
)
}
const Container = styled.div`
display: flex;
flex-direction: column;
padding: 0 16px;
`
const GridContainer = styled.div`
margin-top: 140px;
padding-top: 40px;
border-top: 1px solid rgba(0, 0, 0, 0.18);
`
const Section = styled.section`
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-auto-rows: minmax(100px, auto);
gap: 16px;
`
const GridItem = styled.div<{ colSpan: number; rowSpan: number }>`
grid-column: span ${(props) => props?.colSpan || 1};
grid-row: span ${(props) => props?.rowSpan || 1};
p {
margin-top: 16px;
font-size: 18px;
font-weight: 400;
line-height: 22px;
text-transform: capitalize;
}
`
export default BUTeam

View File

@ -0,0 +1,90 @@
import styled from '@emotion/styled'
import BUSection from '../BUSection'
import ProfileCard from './ProfileCard'
const profiles = [
{
name: 'Alex Johnson',
position: 'Software Engineer',
imageUrl: '/photos/mock.png',
},
{
name: 'Samantha Bloom',
position: 'Product Manager',
imageUrl: '/photos/mock.png',
},
{
name: 'Michael Reeves',
position: 'UX Designer',
imageUrl: '/photos/mock.png',
},
{
name: 'Jessica Tan',
position: 'Data Scientist',
imageUrl: '/photos/mock.png',
},
{
name: 'Raj Patel',
position: 'DevOps Specialist',
imageUrl: '/photos/mock.png',
},
{
name: 'Alex Johnson',
position: 'Software Engineer',
imageUrl: '/photos/mock.png',
},
]
const BUTeam = () => {
return (
<Container>
<BUSection
title={'Team'}
description={
<>
<h3>
We are powering the data storage layer of the Logos Network State.
</h3>
<p>
Logos is a grassroots movement to provide trust-minimized,
corruption-resistant governing services and social institutions to
peaceful people worldwide. Learn more about our ambitious vision.
</p>
</>
}
/>
<GridContainer>
<Section>
{profiles.map((profile, index) => (
<ProfileCard
key={index}
name={profile.name}
position={profile.position}
imageUrl={profile.imageUrl}
/>
))}
</Section>
</GridContainer>
</Container>
)
}
const Container = styled.div`
display: flex;
flex-direction: column;
padding: 0 16px;
`
const GridContainer = styled.div`
margin-top: 140px;
padding-top: 40px;
border-top: 1px solid rgba(0, 0, 0, 0.18);
`
const Section = styled.section`
display: grid;
grid-template-columns: repeat(auto-fill, minmax(222px, 1fr));
gap: 16px;
`
export default BUTeam

View File

@ -0,0 +1,44 @@
import styled from '@emotion/styled'
type Props = {
name: string
position: string
imageUrl: string
}
const ProfileCard = ({ name, position, imageUrl }: Props) => (
<Card>
<ProfileImage src={imageUrl} alt={name} />
<Name>{name}</Name>
<Position>{position}</Position>
</Card>
)
const Card = styled.div`
display: flex;
flex-direction: column;
`
const ProfileImage = styled.img`
width: auto;
height: auto;
margin-bottom: 16px;
`
const Name = styled.p`
font-size: 22px;
font-weight: 400;
line-height: 26px;
text-transform: capitalize;
margin-bottom: 8px;
`
const Position = styled.p`
font-size: 18px;
font-weight: 400;
line-height: 22px;
text-transform: capitalize;
opacity: 0.5;
`
export default ProfileCard

View File

@ -0,0 +1,8 @@
export { default as BUAbout } from './About/BUAbout'
export { default as BUHero } from './BUHero'
export { default as BUMenuFilter } from './BUMenuFilter'
export { default as BUMenus } from './BUMenus'
export { default as BUSection } from './BUSection'
export { default as BUVideo } from './BUVideo'
export { default as BUMedia } from './Media/BUMedia'
export { default as BUTeam } from './Team/BUTeam'

View File

@ -0,0 +1,23 @@
import { breakpoints } from '@/configs/ui.configs'
import styled from '@emotion/styled'
export const Badge = styled.div`
display: flex;
align-items: center;
justify-content: center;
background-color: white;
color: black;
font-size: 12px;
line-height: 16px;
height: 24px;
padding: 4px 10px;
box-sizing: border-box;
cursor: pointer;
border-radius: 999px;
border: 1px solid rgba(0, 0, 0, 0.18);
@media (max-width: ${breakpoints.md}px) {
font-size: 12px;
padding: 4px 8px;
}
`

View File

@ -0,0 +1 @@
export { Badge } from './Badge'

View File

@ -1,5 +1,6 @@
import styled from '@emotion/styled'
import React from 'react'
import ArrowUpRight from '../Icons/ArrowUpRight'
interface ButtonProps {
color?: 'black' | 'white' | 'grey'
@ -8,6 +9,7 @@ interface ButtonProps {
width?: string
height?: string
children?: React.ReactNode
icon?: boolean
}
const StyledButton = styled.button<ButtonProps>`
@ -27,10 +29,16 @@ const StyledButton = styled.button<ButtonProps>`
width: ${(props) => props.width || 'auto'};
height: ${(props) => props.height || 'auto'};
white-space: nowrap;
text-align: center;
text-align: ${(props) => (props.icon ? 'left' : 'center')};
border-radius: 2px;
position: relative;
svg {
path {
stroke: ${(props) => (props.color === 'black' ? 'white' : 'black')};
}
}
&:hover {
opacity: 0.8;
}
@ -43,6 +51,7 @@ const Button: React.FC<ButtonProps> = ({
children,
width,
height,
icon = false,
...props
}) => {
return (
@ -52,11 +61,23 @@ const Button: React.FC<ButtonProps> = ({
padding={padding}
width={width}
height={height}
icon={icon}
{...props}
>
{children}
{icon && (
<IconContainer>
<ArrowUpRight />
</IconContainer>
)}
</StyledButton>
)
}
const IconContainer = styled.span`
position: absolute;
top: 7px;
right: 7px;
`
export default Button

View File

@ -2,6 +2,7 @@ import { breakpoints, uiConfigs } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import { calculatElementCount } from '../../../utils/count'
import { FilterTitle } from '../Filter'
import { Tag } from '../Tag'
type Props = {
data: any
@ -84,28 +85,6 @@ const Border = styled.hr`
margin: 0;
`
const Tag = styled.div<{ active: boolean }>`
display: flex;
align-items: center;
justify-content: center;
background-color: ${({ active }) => (active ? 'black' : 'white')};
color: ${({ active }) => (active ? 'white' : 'black')};
font-size: 14px;
line-height: 20px;
height: 28px;
border-radius: 14px;
padding: 4px 14px;
box-sizing: border-box;
text-transform: capitalize;
cursor: pointer;
border: 1px solid black;
white-space: nowrap;
@media (max-width: ${breakpoints.md}px) {
padding: 4px 10px;
}
`
const NoChallenges = styled.p`
padding-top: 24px;
font-size: 36px;

View File

@ -10,6 +10,9 @@ interface BoardChallenges {
type Props = {
challenges: BoardChallenges
activeBUs: string[]
marginTop?: string
marginBottom?: string
title?: string
}
function extractOrgName(repoIdentifier: string): string {
@ -17,13 +20,19 @@ function extractOrgName(repoIdentifier: string): string {
return orgPart.replace(/-.*/, '')
}
const ChallengeList = ({ challenges, activeBUs }: Props) => {
const ChallengeList = ({
title,
challenges,
activeBUs,
marginTop = '0',
marginBottom = '180px',
}: Props) => {
if (challenges == null) {
return <div>Something went wrong</div>
}
return (
<CustomBox>
<CustomBox marginTop={marginTop} marginBottom={marginBottom}>
{Object.entries(challenges)
.filter(([businessUnit, _]) =>
!activeBUs?.length ? true : activeBUs.includes(businessUnit),
@ -31,7 +40,7 @@ const ChallengeList = ({ challenges, activeBUs }: Props) => {
.map(([businessUnit, challengeList]) => (
<Container key={businessUnit + '-challenges'}>
<TitleContainer>
<Title>{extractOrgName(businessUnit)}</Title>
<Title>{title ?? extractOrgName(businessUnit)}</Title>
</TitleContainer>
<Challenges>
@ -53,7 +62,6 @@ const Container = styled.div`
display: flex;
width: 100%;
justify-content: space-between;
margin-top: 180px;
border-top: 1px solid rgba(0, 0, 0, 0.18);
@media (max-width: ${breakpoints.md}px) {
@ -107,8 +115,6 @@ const NoChallenges = styled.p`
// `
const CustomBox = styled(Box)`
margin-bottom: 238px;
@media (max-width: ${breakpoints.md}px) {
margin-bottom: 195px;
}

View File

@ -2,6 +2,7 @@ import { breakpoints, uiConfigs } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import { calculatElementCount } from '../../../utils/count'
import { FilterTitle } from '../Filter'
import { Tag } from '../Tag'
import { Job } from './JobItem' // adjust path accordingly
export interface BoardJobs {
@ -89,28 +90,6 @@ const Border = styled.hr`
margin: 0;
`
const Tag = styled.div<{ active: boolean }>`
display: flex;
align-items: center;
justify-content: center;
background-color: ${({ active }) => (active ? 'black' : 'white')};
color: ${({ active }) => (active ? 'white' : 'black')};
font-size: 14px;
line-height: 20px;
height: 28px;
border-radius: 14px;
padding: 4px 14px;
box-sizing: border-box;
text-transform: capitalize;
cursor: pointer;
border: 1px solid black;
white-space: nowrap;
@media (max-width: ${breakpoints.md}px) {
padding: 4px 10px;
}
`
const NoJobs = styled.p`
padding-top: 24px;
font-size: 36px;

View File

@ -1,6 +1,5 @@
import { breakpoints } from '@/configs/ui.configs'
import styled from '@emotion/styled'
// import Image from 'next/image'
import { Box } from '../Box'
import JobItem, { Job } from './JobItem'
@ -11,38 +10,24 @@ interface BoardJobs {
type Props = {
jobs: BoardJobs
activeBUs: string[]
marginTop?: string
marginBottom?: string
title?: string
}
const JobList = ({ jobs, activeBUs }: Props) => {
const JobList = ({
jobs,
activeBUs,
marginTop = '0',
marginBottom = '238px',
title,
}: Props) => {
if (jobs == null) {
return <div>Something went wrong</div>
}
// const businessUnitMark = (businessUnit: string) => {
// switch (businessUnit) {
// case 'logos':
// return '/icons/bu/logos.svg'
// case 'codex':
// return '/icons/bu/codex.svg'
// case 'status':
// return '/icons/bu/status.svg'
// case 'waku':
// return '/icons/bu/waku.svg'
// case 'nimbus':
// return '/icons/bu/nimbus.svg'
// case 'nomos':
// return '/icons/bu/nomos.svg'
// case 'vac':
// return '/icons/bu/vac.svg'
// case 'keycard':
// return ''
// default:
// return ''
// }
// }
return (
<CustomBox>
<Box marginTop={marginTop} marginBottom={marginBottom}>
{Object.entries(jobs)
.filter(([businessUnit, _]) =>
!activeBUs?.length ? true : activeBUs.includes(businessUnit),
@ -50,17 +35,8 @@ const JobList = ({ jobs, activeBUs }: Props) => {
.map(([businessUnit, jobList]) => (
<Container key={businessUnit + '-jobs'}>
<TitleContainer>
{/* {businessUnitMark(businessUnit)?.length ? (
<Mark
width={50}
height={50}
src={businessUnitMark(businessUnit)}
alt={businessUnit + '-mark'}
/>
) : null} */}
<Title>{businessUnit}</Title>
<Title>{title ?? businessUnit}</Title>
</TitleContainer>
<Jobs>
{jobList?.length ? (
jobList.map((job: any) => <JobItem key={job.id} job={job} />)
@ -70,7 +46,7 @@ const JobList = ({ jobs, activeBUs }: Props) => {
</Jobs>
</Container>
))}
</CustomBox>
</Box>
)
}
@ -125,18 +101,4 @@ const NoJobs = styled.p`
text-decoration: none;
`
// const Mark = styled(Image)`
// @media (max-width: ${breakpoints.md}px) {
// display: none;
// }
// `
const CustomBox = styled(Box)`
margin-bottom: 238px;
@media (max-width: ${breakpoints.md}px) {
margin-bottom: 195px;
}
`
export default JobList

View File

@ -7,7 +7,9 @@ import { useEffect, useState } from 'react'
export const Navbar = () => {
const [scrolled, setScrolled] = useState(false)
const router = useRouter()
const isTransparent = router.pathname === '/'
const isTransparent = router.pathname === '/' || router.pathname === '/[bu]'
const background = router.pathname === '/[bu]' ? 'transparent' : 'black'
useEffect(() => {
const handleScroll = () => {
@ -22,7 +24,11 @@ export const Navbar = () => {
}, [])
return (
<Container scrolled={scrolled} isTransparent={isTransparent}>
<Container
scrolled={scrolled}
isTransparent={isTransparent}
background={background}
>
<span>
<Link href="/">
<p>HOME</p>
@ -41,14 +47,19 @@ export const Navbar = () => {
)
}
const Container = styled.nav<{ scrolled: boolean; isTransparent: boolean }>`
const Container = styled.nav<{
scrolled: boolean
isTransparent: boolean
background: string
}>`
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
display: flex;
background: black;
background-color: ${({ isTransparent, scrolled, background }) =>
!scrolled && isTransparent ? background : scrolled ? 'black' : background};
height: ${uiConfigs.navbarHeight}px;
padding: 4px 16px;
@ -76,7 +87,6 @@ const Container = styled.nav<{ scrolled: boolean; isTransparent: boolean }>`
}
@media (max-width: ${breakpoints.md}px) {
background-color: transparent;
background-color: ${({ isTransparent, scrolled }) =>
!scrolled && isTransparent ? 'transparent' : 'black'};

View File

@ -2,6 +2,7 @@ import { breakpoints } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import Image from 'next/image'
import { useState } from 'react'
import { Badge } from '../Badge'
interface Props {
children: React.ReactNode
@ -23,7 +24,7 @@ export const PortfolioItem = ({ title, mark, est, children }: Props) => {
<Title>
<Image src={mark} width={34} height={34} alt={title + '-logo'} />
<TitleText>{title}</TitleText>
<Tag>est. {est}</Tag>
<Badge>est. {est}</Badge>
</Title>
<Toggle>
<ToggleButtonImage
@ -144,27 +145,6 @@ const TitleText = styled.h3`
}
`
const Tag = styled.div`
display: flex;
align-items: center;
justify-content: center;
background-color: white;
color: black;
font-size: 12px;
line-height: 16px;
height: 24px;
padding: 4px 10px;
box-sizing: border-box;
cursor: pointer;
border-radius: 999px;
border: 1px solid rgba(0, 0, 0, 0.18);
@media (max-width: ${breakpoints.md}px) {
font-size: 12px;
padding: 4px 8px;
}
`
const Content = styled.div`
width: 100%;
padding-bottom: 40px;

View File

@ -1,6 +1,7 @@
import { breakpoints, uiConfigs } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import { FilterTitle } from '../Filter'
import { Tag } from '../Tag'
import { ServiceType } from './ServiceItem'
type Props = {
@ -107,28 +108,6 @@ const Border = styled.hr`
margin: 0;
`
const Tag = styled.div<{ active: boolean }>`
display: flex;
align-items: center;
justify-content: center;
background-color: ${({ active }) => (active ? 'black' : 'white')};
color: ${({ active }) => (active ? 'white' : 'black')};
font-size: 14px;
line-height: 20px;
height: 28px;
border-radius: 14px;
padding: 4px 14px;
box-sizing: border-box;
text-transform: capitalize;
cursor: pointer;
border: 1px solid black;
white-space: nowrap;
@media (max-width: ${breakpoints.md}px) {
padding: 4px 10px;
}
`
const NoServices = styled.p`
padding-top: 24px;
font-size: 36px;

View File

@ -0,0 +1,24 @@
import { breakpoints } from '@/configs/ui.configs'
import styled from '@emotion/styled'
export const Tag = styled.div<{ active: boolean }>`
display: flex;
align-items: center;
justify-content: center;
background-color: ${({ active }) => (active ? 'black' : 'white')};
color: ${({ active }) => (active ? 'white' : 'black')};
font-size: 14px;
line-height: 20px;
height: 28px;
border-radius: 14px;
padding: 4px 14px;
box-sizing: border-box;
text-transform: capitalize;
cursor: pointer;
border: 1px solid black;
white-space: nowrap;
@media (max-width: ${breakpoints.md}px) {
padding: 4px 10px;
}
`

View File

@ -0,0 +1 @@
export { Tag } from './Tag'

View File

@ -1,40 +0,0 @@
import styled from '@emotion/styled'
export type TagsProps = React.ComponentProps<typeof TagsContainer> & {
tags: string[]
}
const Tags: React.FC<TagsProps> = ({ tags, className, ...props }) => {
return tags?.length > 0 ? (
<TagsContainer className={className} {...props}>
{tags.map((tag, idx) => (
<Tag key={idx}>{tag}</Tag>
))}
</TagsContainer>
) : null
}
const TagsContainer = styled.div`
display: flex;
padding: 16px 0px;
align-items: flex-start;
gap: 16px;
align-self: stretch;
border-top: 1px solid rgba(0, 0, 0, 0.18);
border-bottom: 1px solid rgba(0, 0, 0, 0.18);
margin-block: 16px;
`
const Tag = styled.div`
display: flex;
padding: 4px 12px;
justify-content: center;
align-items: center;
gap: 6px;
font-size: 14px;
border-radius: 99px;
border: 1px solid #000;
background: #fff;
`
export default Tags

View File

@ -1 +0,0 @@
export { default as Tags } from './Tags'

165
src/data/bu-data.ts Normal file
View File

@ -0,0 +1,165 @@
const BU_DATA: any = {
logos: {
hero: {
bu: 'logos',
est: '2020',
devStatus: 'In production',
vertical: 'Decentralised communications',
founders: 'Oskar Thorén',
achievements: 'Integrated with Status, Railgun, and the Graph',
description:
'Waku is a family of protocols that enable privacy-preserving communications over a P2P network for web3 applications. Consistent with IFT principles of accessibility and upholding civil liberties, Waku is modular, network agnostic, and obscures message content and metadata in transit.',
connect: [
{ link: 'https://docs.waku.org/', label: 'Docs' },
{ link: 'https://x.com/waku_org', label: 'X' },
{ link: 'https://discord.waku.org/', label: 'Discord' },
],
website: 'https://waku.org/',
github: 'https://github.com/waku-org',
lead: 'Franck Royer',
},
about: {
description: `The network facilitates human-to-human, machine-to-human, and machine-to-machine communication in both directions, giving it an enormous scope of potential applications — from internode communications to in-game messaging and everything in between. Currently, there are three Waku client implementations: nwaku (reference implementation in Nim), Go-Waku (for Go applications), and JS-Waku (for browsers).\n\nWaku v1 was a fork of the Whisper protocol, but persistent scalability issues forced an entire protocol rewrite, birthing Waku v2 in 2021. At a high level, Waku v2 implements Pub/Sub over libp2p, extending the networking frameworks capabilities to include retrieving historical messages for mostly offline devices, adaptive nodes, and bandwidth preservation for resource-restricted devices.\n\nKey to Wakus design is its modularity. When integrating Waku with an app, developers can select which protocols to implement according to their use case and users hardware availability, enabling devices with limited resources to contribute as peers in the network. The Relay protocol is the foundation of Waku and handles Pub/Sub messaging. Among the other protocols complementing Relay are Store, which enables historic message retrieval; Filter, which preserves bandwidth for nodes with limited resources; and Light Push, which allows nodes with short connections and limited bandwidth to publish messages to the Waku network.`,
},
},
waku: {
hero: {
bu: 'waku',
est: '2020',
devStatus: 'In production',
vertical: 'Decentralised communications',
founders: 'Oskar Thorén',
achievements: 'Integrated with Status, Railgun, and the Graph',
description:
'Waku is a family of protocols that enable privacy-preserving communications over a P2P network for web3 applications. Consistent with IFT principles of accessibility and upholding civil liberties, Waku is modular, network agnostic, and obscures message content and metadata in transit.',
connect: [
{ link: 'https://docs.waku.org/', label: 'Docs' },
{ link: 'https://x.com/waku_org', label: 'X' },
{ link: 'https://discord.waku.org/', label: 'Discord' },
],
website: 'https://waku.org/',
github: 'https://github.com/waku-org',
lead: 'Franck Royer',
},
about: {
description: `The network facilitates human-to-human, machine-to-human, and machine-to-machine communication in both directions, giving it an enormous scope of potential applications — from internode communications to in-game messaging and everything in between. Currently, there are three Waku client implementations: nwaku (reference implementation in Nim), Go-Waku (for Go applications), and JS-Waku (for browsers).\n\nWaku v1 was a fork of the Whisper protocol, but persistent scalability issues forced an entire protocol rewrite, birthing Waku v2 in 2021. At a high level, Waku v2 implements Pub/Sub over libp2p, extending the networking frameworks capabilities to include retrieving historical messages for mostly offline devices, adaptive nodes, and bandwidth preservation for resource-restricted devices.\n\nKey to Wakus design is its modularity. When integrating Waku with an app, developers can select which protocols to implement according to their use case and users hardware availability, enabling devices with limited resources to contribute as peers in the network. The Relay protocol is the foundation of Waku and handles Pub/Sub messaging. Among the other protocols complementing Relay are Store, which enables historic message retrieval; Filter, which preserves bandwidth for nodes with limited resources; and Light Push, which allows nodes with short connections and limited bandwidth to publish messages to the Waku network.`,
},
},
codex: {
hero: {
bu: 'codex',
est: '2020',
devStatus: 'In production',
vertical: 'Decentralised communications',
founders: 'Oskar Thorén',
achievements: 'Integrated with Status, Railgun, and the Graph',
description:
'Waku is a family of protocols that enable privacy-preserving communications over a P2P network for web3 applications. Consistent with IFT principles of accessibility and upholding civil liberties, Waku is modular, network agnostic, and obscures message content and metadata in transit.',
connect: [
{ link: 'https://docs.waku.org/', label: 'Docs' },
{ link: 'https://x.com/waku_org', label: 'X' },
{ link: 'https://discord.waku.org/', label: 'Discord' },
],
website: 'https://waku.org/',
github: 'https://github.com/waku-org',
lead: 'Franck Royer',
},
about: {
description: `The network facilitates human-to-human, machine-to-human, and machine-to-machine communication in both directions, giving it an enormous scope of potential applications — from internode communications to in-game messaging and everything in between. Currently, there are three Waku client implementations: nwaku (reference implementation in Nim), Go-Waku (for Go applications), and JS-Waku (for browsers).\n\nWaku v1 was a fork of the Whisper protocol, but persistent scalability issues forced an entire protocol rewrite, birthing Waku v2 in 2021. At a high level, Waku v2 implements Pub/Sub over libp2p, extending the networking frameworks capabilities to include retrieving historical messages for mostly offline devices, adaptive nodes, and bandwidth preservation for resource-restricted devices.\n\nKey to Wakus design is its modularity. When integrating Waku with an app, developers can select which protocols to implement according to their use case and users hardware availability, enabling devices with limited resources to contribute as peers in the network. The Relay protocol is the foundation of Waku and handles Pub/Sub messaging. Among the other protocols complementing Relay are Store, which enables historic message retrieval; Filter, which preserves bandwidth for nodes with limited resources; and Light Push, which allows nodes with short connections and limited bandwidth to publish messages to the Waku network.`,
},
},
nomos: {
hero: {
bu: 'nomos',
est: '2020',
devStatus: 'In production',
vertical: 'Decentralised communications',
founders: 'Oskar Thorén',
achievements: 'Integrated with Status, Railgun, and the Graph',
description:
'Waku is a family of protocols that enable privacy-preserving communications over a P2P network for web3 applications. Consistent with IFT principles of accessibility and upholding civil liberties, Waku is modular, network agnostic, and obscures message content and metadata in transit.',
connect: [
{ link: 'https://docs.waku.org/', label: 'Docs' },
{ link: 'https://x.com/waku_org', label: 'X' },
{ link: 'https://discord.waku.org/', label: 'Discord' },
],
website: 'https://waku.org/',
github: 'https://github.com/waku-org',
lead: 'Franck Royer',
},
about: {
description: `The network facilitates human-to-human, machine-to-human, and machine-to-machine communication in both directions, giving it an enormous scope of potential applications — from internode communications to in-game messaging and everything in between. Currently, there are three Waku client implementations: nwaku (reference implementation in Nim), Go-Waku (for Go applications), and JS-Waku (for browsers).\n\nWaku v1 was a fork of the Whisper protocol, but persistent scalability issues forced an entire protocol rewrite, birthing Waku v2 in 2021. At a high level, Waku v2 implements Pub/Sub over libp2p, extending the networking frameworks capabilities to include retrieving historical messages for mostly offline devices, adaptive nodes, and bandwidth preservation for resource-restricted devices.\n\nKey to Wakus design is its modularity. When integrating Waku with an app, developers can select which protocols to implement according to their use case and users hardware availability, enabling devices with limited resources to contribute as peers in the network. The Relay protocol is the foundation of Waku and handles Pub/Sub messaging. Among the other protocols complementing Relay are Store, which enables historic message retrieval; Filter, which preserves bandwidth for nodes with limited resources; and Light Push, which allows nodes with short connections and limited bandwidth to publish messages to the Waku network.`,
},
},
status: {
hero: {
bu: 'status',
est: '2020',
devStatus: 'In production',
vertical: 'Decentralised communications',
founders: 'Oskar Thorén',
achievements: 'Integrated with Status, Railgun, and the Graph',
description:
'Waku is a family of protocols that enable privacy-preserving communications over a P2P network for web3 applications. Consistent with IFT principles of accessibility and upholding civil liberties, Waku is modular, network agnostic, and obscures message content and metadata in transit.',
connect: [
{ link: 'https://docs.waku.org/', label: 'Docs' },
{ link: 'https://x.com/waku_org', label: 'X' },
{ link: 'https://discord.waku.org/', label: 'Discord' },
],
website: 'https://waku.org/',
github: 'https://github.com/waku-org',
lead: 'Franck Royer',
},
about: {
description: `The network facilitates human-to-human, machine-to-human, and machine-to-machine communication in both directions, giving it an enormous scope of potential applications — from internode communications to in-game messaging and everything in between. Currently, there are three Waku client implementations: nwaku (reference implementation in Nim), Go-Waku (for Go applications), and JS-Waku (for browsers).\n\nWaku v1 was a fork of the Whisper protocol, but persistent scalability issues forced an entire protocol rewrite, birthing Waku v2 in 2021. At a high level, Waku v2 implements Pub/Sub over libp2p, extending the networking frameworks capabilities to include retrieving historical messages for mostly offline devices, adaptive nodes, and bandwidth preservation for resource-restricted devices.\n\nKey to Wakus design is its modularity. When integrating Waku with an app, developers can select which protocols to implement according to their use case and users hardware availability, enabling devices with limited resources to contribute as peers in the network. The Relay protocol is the foundation of Waku and handles Pub/Sub messaging. Among the other protocols complementing Relay are Store, which enables historic message retrieval; Filter, which preserves bandwidth for nodes with limited resources; and Light Push, which allows nodes with short connections and limited bandwidth to publish messages to the Waku network.`,
},
},
keycard: {
hero: {
bu: 'keycard',
est: '2020',
devStatus: 'In production',
vertical: 'Decentralised communications',
founders: 'Oskar Thorén',
achievements: 'Integrated with Status, Railgun, and the Graph',
description:
'Waku is a family of protocols that enable privacy-preserving communications over a P2P network for web3 applications. Consistent with IFT principles of accessibility and upholding civil liberties, Waku is modular, network agnostic, and obscures message content and metadata in transit.',
connect: [
{ link: 'https://docs.waku.org/', label: 'Docs' },
{ link: 'https://x.com/waku_org', label: 'X' },
{ link: 'https://discord.waku.org/', label: 'Discord' },
],
website: 'https://waku.org/',
github: 'https://github.com/waku-org',
lead: 'Franck Royer',
},
about: {
description: `The network facilitates human-to-human, machine-to-human, and machine-to-machine communication in both directions, giving it an enormous scope of potential applications — from internode communications to in-game messaging and everything in between. Currently, there are three Waku client implementations: nwaku (reference implementation in Nim), Go-Waku (for Go applications), and JS-Waku (for browsers).\n\nWaku v1 was a fork of the Whisper protocol, but persistent scalability issues forced an entire protocol rewrite, birthing Waku v2 in 2021. At a high level, Waku v2 implements Pub/Sub over libp2p, extending the networking frameworks capabilities to include retrieving historical messages for mostly offline devices, adaptive nodes, and bandwidth preservation for resource-restricted devices.\n\nKey to Wakus design is its modularity. When integrating Waku with an app, developers can select which protocols to implement according to their use case and users hardware availability, enabling devices with limited resources to contribute as peers in the network. The Relay protocol is the foundation of Waku and handles Pub/Sub messaging. Among the other protocols complementing Relay are Store, which enables historic message retrieval; Filter, which preserves bandwidth for nodes with limited resources; and Light Push, which allows nodes with short connections and limited bandwidth to publish messages to the Waku network.`,
},
},
nimbus: {
hero: {
bu: 'nimbus',
est: '2020',
devStatus: 'In production',
vertical: 'Decentralised communications',
founders: 'Oskar Thorén',
achievements: 'Integrated with Status, Railgun, and the Graph',
description:
'Waku is a family of protocols that enable privacy-preserving communications over a P2P network for web3 applications. Consistent with IFT principles of accessibility and upholding civil liberties, Waku is modular, network agnostic, and obscures message content and metadata in transit.',
connect: [
{ link: 'https://docs.waku.org/', label: 'Docs' },
{ link: 'https://x.com/waku_org', label: 'X' },
{ link: 'https://discord.waku.org/', label: 'Discord' },
],
website: 'https://waku.org/',
github: 'https://github.com/waku-org',
lead: 'Franck Royer',
},
about: {
description: `The network facilitates human-to-human, machine-to-human, and machine-to-machine communication in both directions, giving it an enormous scope of potential applications — from internode communications to in-game messaging and everything in between. Currently, there are three Waku client implementations: nwaku (reference implementation in Nim), Go-Waku (for Go applications), and JS-Waku (for browsers).\n\nWaku v1 was a fork of the Whisper protocol, but persistent scalability issues forced an entire protocol rewrite, birthing Waku v2 in 2021. At a high level, Waku v2 implements Pub/Sub over libp2p, extending the networking frameworks capabilities to include retrieving historical messages for mostly offline devices, adaptive nodes, and bandwidth preservation for resource-restricted devices.\n\nKey to Wakus design is its modularity. When integrating Waku with an app, developers can select which protocols to implement according to their use case and users hardware availability, enabling devices with limited resources to contribute as peers in the network. The Relay protocol is the foundation of Waku and handles Pub/Sub messaging. Among the other protocols complementing Relay are Store, which enables historic message retrieval; Filter, which preserves bandwidth for nodes with limited resources; and Light Push, which allows nodes with short connections and limited bandwidth to publish messages to the Waku network.`,
},
},
}
export default BU_DATA

142
src/pages/[bu].tsx Normal file
View File

@ -0,0 +1,142 @@
import {
BUAbout,
BUHero,
BUMedia,
BUMenuFilter,
BUMenus,
BUTeam,
BUVideo,
} from '@/components/BU'
import { ChallengeList } from '@/components/Challenges'
import { JobList } from '@/components/Jobs'
import { SEO } from '@/components/SEO'
import BU_DATA from '@/data/bu-data'
import { SubPageLayout } from '@/layouts/SubPageLayout'
import { useState } from 'react'
import { JOB_BOARD_MAPPING, getJobs } from '../../utils/getJobs'
const Page = ({ bu, jobs, issues }: any) => {
const [activeMenus, setActiveMenus] = useState<string[]>([])
return (
<>
<SEO />
<BUVideo />
<div>
<BUHero data={BU_DATA[bu]?.hero} />
<BUMenuFilter
activeMenus={activeMenus}
setActiveMenus={setActiveMenus}
/>
<BUMenus>
{activeMenus.length === 0 || activeMenus.includes('About') ? (
<BUAbout data={BU_DATA[bu]?.about} />
) : null}
{activeMenus.length === 0 || activeMenus.includes('Team') ? (
<BUTeam />
) : null}
{activeMenus.length === 0 || activeMenus.includes('Jobs') ? (
<JobList
title="Jobs"
jobs={jobs}
activeBUs={[bu]}
marginTop="0"
marginBottom="0"
/>
) : null}
{activeMenus.length === 0 || activeMenus.includes('Challenges') ? (
<ChallengeList
title="Challenges"
challenges={issues}
activeBUs={[]}
marginTop="0"
marginBottom="0"
/>
) : null}
{activeMenus.length === 0 || activeMenus.includes('Media') ? (
<BUMedia />
) : null}
</BUMenus>
</div>
</>
)
}
Page.getLayout = function getLayout(page: React.ReactNode) {
return <SubPageLayout>{page}</SubPageLayout>
}
export async function getStaticPaths() {
const paths: any = []
const BUs = [
'waku',
'codex',
'nomos',
'status',
'keycard',
'keycard',
'logos',
'nimbus',
]
for (const bu of BUs) {
paths.push({ params: { bu } })
}
return {
paths,
fallback: false,
}
}
export async function getStaticProps({ params }: any) {
const { bu } = params
let jobs: any = []
let issues = {}
const site = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'
try {
if (Object.keys(JOB_BOARD_MAPPING).includes(bu)) {
jobs = await getJobs([bu], '')
}
if (bu === 'waku') {
const res = await fetch(`${site}/api/challenges`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify([{ owner: 'waku-org', repo: 'bounties' }]),
})
if (!res.ok) {
throw new Error(`Failed to fetch issues, status: ${res.status}`)
}
issues = await res.json()
}
return {
props: {
bu,
jobs,
issues,
},
revalidate: 3600,
}
} catch (error) {
return {
props: {
jobs: [],
issues: {},
},
revalidate: 3600,
}
}
}
export default Page

View File

@ -6,6 +6,7 @@ import { Portfolio, PortfolioItem } from '@/components/Portfolio'
import { Team, Member } from '@/components/Team'
import { Mission } from '@/components/Mission'
import { HomeFooter } from '@/components/Footer'
import Link from 'next/link'
<SEO />
@ -35,7 +36,7 @@ import { HomeFooter } from '@/components/Footer'
A movement supporting the development of the decentralised web. Logos technologies lay the foundations for a freer internet upon which communities can evolve into network states. Each protocol in the Logos stack seeks to empower its users while upholding civil liberties and fundamental freedoms.
<Button width="150px" height="40px" color="grey">Learn more</Button>
<Link href="/logos"><Button width="150px" height="40px" color="grey">Learn more</Button></Link>
</PortfolioItem>
<PortfolioItem mark="/icons/bu/waku.svg" title="Waku" est={2020}>
@ -49,7 +50,7 @@ import { HomeFooter } from '@/components/Footer'
A family of generalised P2P communications protocols. The messaging layer of the Logos stack. Waku is private, censorship resistant, modular, and scalable by design. This combination of features makes Waku suitable to run in a wide range of environments, including phones and browsers, while upholding its users' rights to private communications.
<Button width="150px" height="40px" color="grey">Learn more</Button>
<Link href="/waku"><Button width="150px" height="40px" color="grey">Learn more</Button></Link>
</PortfolioItem>
<PortfolioItem mark="/icons/bu/codex.svg" title="Codex" est={2020}>
@ -63,7 +64,7 @@ import { HomeFooter } from '@/components/Footer'
A decentralised storage engine with strong censorship resistance and retrievability guarantees. The data archiving layer of the Logos stack. Codex leverages a novel combination of cutting-edge features, including erasure coding, a lazy repair system, ZK-based remote auditing, and incentivisation mechanisms to ensure reliability, data durability, efficiency, and cost effectiveness.
<Button width="150px" height="40px" color="grey">Learn more</Button>
<Link href="/codex"><Button width="150px" height="40px" color="grey">Learn more</Button></Link>
</PortfolioItem>
<PortfolioItem mark="/icons/bu/nomos.svg" title="Nomos" est={2020}>
@ -77,7 +78,7 @@ import { HomeFooter } from '@/components/Footer'
A sovereign, modular, zk-encrypted network of blockchains. The trustless agreements layer of the Logos stack. The forthcoming Nomos network will provide a common infrastructure layer upon which communities and aspiring network states can build social, governance, and financial services that uphold their community members' fundamental rights and values.
<Button width="150px" height="40px" color="grey">Learn more</Button>
<Link href="/nomos"><Button width="150px" height="40px" color="grey">Learn more</Button></Link>
</PortfolioItem>
<PortfolioItem mark="/icons/bu/status.svg" title="Status" est={2020}>
@ -91,7 +92,7 @@ import { HomeFooter } from '@/components/Footer'
A blockchain-based super app that combines private messaging, a wallet, a DApp browser, and tools for web3 community management. Status aims to be a truly decentralised communication tool and, since its founding in 2017, has been progressively removing reliance on centralised infrastructure. The application leverages Waku and other technologies developed under the IFT umbrella.
<Button width="150px" height="40px" color="grey">Learn more</Button>
<Link href="/status"><Button width="150px" height="40px" color="grey">Learn more</Button></Link>
</PortfolioItem>
<PortfolioItem mark="/icons/bu/keycard.svg" title="Keycard" est={2020}>
@ -105,7 +106,7 @@ import { HomeFooter } from '@/components/Footer'
A discreet, convenient, affordable hardware security solution for crypto assets. Taking the form of a credit card, Keycard offers comparable crypto security at a fraction of the cost of others in the hardware wallet niche. Keycard is in production, and the team is working on a full hardware wallet, which will be entirely open-source and compatible with existing Keycards while offering a familiar user experience.
<Button width="150px" height="40px" color="grey">Learn more</Button>
<Link href="/status"><Button width="150px" height="40px" color="grey">Learn more</Button></Link>
</PortfolioItem>
<PortfolioItem mark="/icons/bu/nimbus.svg" title="Nimbus" est={2020}>
@ -121,7 +122,7 @@ import { HomeFooter } from '@/components/Footer'
Nimbus' mission is to make staking accessible, thus promoting maximum network decentralisation. The Nimbus consensus client is in production, and an execution client is in development. By offering lightweight implementations for both consensus and execution layers, Nimbus simplifies operating an Ethereum node for hobbyists and institutional stakers alike.
<Button width="150px" height="40px" color="grey">Learn more</Button>
<Link href="/nimbus"><Button width="150px" height="40px" color="grey">Learn more</Button></Link>
</PortfolioItem>
</Portfolio>
<Mission title="Mission">

22
utils/bu.ts Normal file
View File

@ -0,0 +1,22 @@
export const businessUnitMark = (businessUnit: string) => {
switch (businessUnit) {
case 'logos':
return '/icons/bu/logos.svg'
case 'codex':
return '/icons/bu/codex.svg'
case 'status':
return '/icons/bu/status.svg'
case 'waku':
return '/icons/bu/waku.svg'
case 'nimbus':
return '/icons/bu/nimbus.svg'
case 'nomos':
return '/icons/bu/nomos.svg'
case 'vac':
return '/icons/bu/vac.svg'
case 'keycard':
return ''
default:
return ''
}
}

View File

@ -1,4 +1,4 @@
const boardMappings: any = {
export const JOB_BOARD_MAPPING: any = {
// acidtest: "testacidinfo",
// logos: 'logos',
status: 'status72',
@ -30,10 +30,11 @@ export async function getJobs(boardsArg: string[], titleFilter: string) {
for (let board of boards) {
if (board === 'all') {
const promises = Object.entries(boardMappings).map(([key, boardName]) =>
fetchJobsForBoard(boardName as string).then((jobs) => ({
[key]: jobs,
})),
const promises = Object.entries(JOB_BOARD_MAPPING).map(
([key, boardName]) =>
fetchJobsForBoard(boardName as string).then((jobs) => ({
[key]: jobs,
})),
)
const allResults: { [key: string]: any } = {}
const results = await Promise.all(promises)
@ -42,7 +43,7 @@ export async function getJobs(boardsArg: string[], titleFilter: string) {
})
return allResults
} else {
const results = await fetchJobsForBoard(boardMappings[board])
const results = await fetchJobsForBoard(JOB_BOARD_MAPPING[board])
return { [board]: results }
}
}