Skip to content

Commit

Permalink
Merge pull request #150 from privacy-scaling-explorations/project-sec…
Browse files Browse the repository at this point in the history
…tions-divider

project page updates
  • Loading branch information
kalidiagne authored Mar 11, 2024
2 parents 36faf39 + 0f46647 commit 92b6b90
Show file tree
Hide file tree
Showing 51 changed files with 1,229 additions and 843 deletions.
4 changes: 2 additions & 2 deletions app/[lang]/projects/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Metadata } from "next"

import ProjectFiltersBar from "@/components/project/project-filters-bar"
import ProjectList from "@/components/project/project-list"
import { ProjectList } from "@/components/project/project-list"
import { ProjectResultBar } from "@/components/project/project-result-bar"
import { useTranslation } from "@/app/i18n"

Expand Down Expand Up @@ -34,7 +34,7 @@ export default async function ProjectsPage({ params: { lang } }: any) {

<div className="w-full bg-anakiwa-100 pb-28">
<div className="container">
<div className="px-3 py-8">
<div className="py-8">
<ProjectResultBar lang={lang} />
</div>
<ProjectList lang={lang} />
Expand Down
5 changes: 3 additions & 2 deletions app/i18n/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
"fullyPSE": "Fully PSE"
},
"status": {
"archived": "Archived",
"active": "Active"
"archived": "Inactive",
"active": "Active",
"inactive": "Inactive"
},
"sortBy": "Sort by: {{option}}",
"tryItOut": "Try it out!",
Expand Down
5 changes: 3 additions & 2 deletions app/i18n/locales/it/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
},
"status": {
"archived": "Archiviato",
"active": "Attivo"
"active": "Attivo",
"inactive": "Inattivo"
},
"sortBy": "Ordina per: {{option}}",
"tryItOut": "Prova!",
Expand All @@ -63,4 +64,4 @@
"whatDoYouWantDoToday": "Cosa vuoi fare oggi?",
"showingProjects": "Mostrando {{count}} progetti",
"showingProjectsWith": "Mostrando {{count}} progetti con:"
}
}
4 changes: 2 additions & 2 deletions components/project/project-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ export default function ProjectCard({
alt={`${name} banner`}
width={1200}
height={630}
className="min-h-[160px] w-full rounded-t-lg object-cover"
className="min-h-[160px] w-full overflow-hidden rounded-t-lg border-none object-cover"
/>
{!image && (
<span className="w-full px-5 text-xl text-center font-bold text-black absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 transform">
<span className="absolute left-1/2 top-1/2 w-full -translate-x-1/2 -translate-y-1/2 px-5 text-center text-xl font-bold text-black">
{imageAlt || name}
</span>
)}
Expand Down
2 changes: 1 addition & 1 deletion components/project/project-filters-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const ThemesStatusMapping = (lang: LocaleTypes): IThemeStatus => {
icon: <Icons.checkActive />,
},
archived: {
label: t("status.archived"),
label: t("status.inactive"),
icon: <Icons.archived />,
},
}
Expand Down
159 changes: 146 additions & 13 deletions components/project/project-list.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
"use client"

import React from "react"
import React, { useCallback, useEffect, useRef, useState } from "react"
import Image from "next/image"
import NoResultIcon from "@/public/icons/no-result.svg"
import { useProjectFiltersState } from "@/state/useProjectFiltersState"
import { cva } from "class-variance-authority"

import { LangProps } from "@/types/common"
import { ProjectSection, ProjectSections } from "@/lib/types"
import { cn } from "@/lib/utils"
import { useTranslation } from "@/app/i18n/client"

import ProjectCard from "./project-card"

const sectionTitleClass = cva(
"relative font-sans text-base font-bold uppercase tracking-[3.36px] text-anakiwa-950 after:ml-8 after:absolute after:top-1/2 after:h-[1px] after:w-full after:translate-y-1/2 after:bg-anakiwa-300 after:content-['']"
)

const NoResults = ({ lang }: LangProps["params"]) => {
const { t } = useTranslation(lang, "common")

Expand All @@ -28,25 +35,151 @@ const NoResults = ({ lang }: LangProps["params"]) => {
)
}

export default function ProjectList({ lang }: LangProps["params"]) {
const ProjectSectionLabelMapping: Record<ProjectSection, string> = {
pse: "PSE projects",
grant: "Grants",
collaboration: "Collaborations",
}

export const ProjectList = ({ lang }: LangProps["params"]) => {
const { t } = useTranslation(lang, "resources-page")
const SCROLL_OFFSET = -400
const [activeId, setActiveId] = useState("")
const [isManualScroll, setIsManualScroll] = useState(false)

const { projects } = useProjectFiltersState((state) => state)

const noItems = projects?.length === 0

const sectionsRef = useRef<NodeListOf<HTMLElement> | null>(null) // sections are constant so useRef might be better here

useEffect(() => {
if (sectionsRef.current === null)
sectionsRef.current = document.querySelectorAll(`div[data-section]`)
if (!activeId) setActiveId("pse")

const handleScroll = () => {
if (isManualScroll) return

sectionsRef.current?.forEach((section: any) => {
const sectionTop = section.offsetTop - SCROLL_OFFSET
if (window.scrollY >= sectionTop && window.scrollY > 0) {
setActiveId(section.getAttribute("id"))
}
})
}

window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
}, [SCROLL_OFFSET, activeId, isManualScroll])

const scrollToId = useCallback((id: string) => {
const element = document.getElementById(id)
const top = element?.offsetTop ?? 0

if (element) {
setActiveId(id) // active clicked id
setIsManualScroll(true) // tell the window event listener to ignore this scrolling
window?.scrollTo({
behavior: "smooth",
top: (top ?? 0) - SCROLL_OFFSET,
})
}

setTimeout(() => setIsManualScroll(false), 800)
}, [])

if (noItems) return <NoResults lang={lang} />

return (
<div className="flex flex-wrap justify-center gap-6 pb-6">
{projects.map((project) => (
<ProjectCard
key={project?.id}
project={project}
lang={lang}
showBanner
showLinks
border
/>
))}
<div className="relative grid grid-cols-[1fr_200px] items-start justify-between gap-10">
<div className="flex flex-col gap-14 md:gap-20">
{ProjectSections.map((section) => {
const sectionProjects =
projects.filter(
(project) =>
project.section?.toLowerCase() === section?.toLowerCase()
) ?? []

const hasProjectsForSection = sectionProjects.length > 0

const sectionTitle =
ProjectSectionLabelMapping[section as ProjectSection]

if (!hasProjectsForSection) return null

return (
<div
key={section}
id={section}
data-section={section}
className="flex justify-between gap-10"
>
<div
className={cn(
"flex w-full flex-col",
hasProjectsForSection ? "gap-10" : "gap-2"
)}
>
<div className="overflow-hidden">
<h3 className={cn(sectionTitleClass())}>{sectionTitle}</h3>
</div>
<div className="flex flex-wrap gap-6">
{sectionProjects.map((project) => (
<ProjectCard
key={project?.id}
project={project}
lang={lang}
showBanner
showLinks
border
/>
))}
</div>
</div>
</div>
)
})}
</div>

<div
id="sidebar"
className="sticky top-20 hidden bg-white/30 p-8 md:block"
>
<div className="flex flex-col gap-4">
<h6 className="font-display text-lg font-bold text-tuatara-700">
{t("onThisPage")}
</h6>
<ul className="text-normal font-sans text-black">
{ProjectSections.map((id: ProjectSection) => {
const label = ProjectSectionLabelMapping[id]

if (!label) return null // no label for this section

const active = id === activeId

return (
<li
key={id}
onClick={(e) => {
scrollToId(id)
}}
data-id={id}
className={cn(
"flex h-8 cursor-pointer items-center border-l-2 border-l-anakiwa-200 px-3 duration-200",
{
"border-l-anakiwa-500 text-anakiwa-500 font-medium":
active,
}
)}
>
{label}
</li>
)
})}
</ul>
</div>
</div>
</div>
)
}
5 changes: 2 additions & 3 deletions data/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { summa } from "./projects/summa"
import { tlsn } from "./projects/tlsn"
import { trustedSetups } from "./projects/trusted-setups"
import { unirepProtocol } from "./projects/unirep-protocol"
import { voicedeck } from "./projects/voice-deck"
import { wax } from "./projects/wax"
import { zk3 } from "./projects/zk3"
import { ZKKit } from "./projects/zk-kit"
Expand Down Expand Up @@ -78,9 +79,7 @@ export const projects: ProjectInterface[] = [
p0tion,
jubmoji,
nfctap,
/**
* Grant projects hidden until we have grant tag
zkp2p,
zk3,
*/
voicedeck,
]
1 change: 1 addition & 0 deletions data/projects/anon-aadhaar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Anon Aadhaar is a project that allows individuals to prove their citizenship ano

export const anonAadhaar: ProjectInterface = {
id: "anon-aadhaar",
section: "pse",
projectStatus: "active",
image: "anon-aadhaar.svg",
name: "Anon Aadhaar",
Expand Down
1 change: 1 addition & 0 deletions data/projects/anon-klub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ AnonKlub is a tool designed for Ethereum developers that allows for anonymous pr

export const anonKlub: ProjectInterface = {
id: "anon-klub",
section: "pse",
projectStatus: "active",
image: "anonklub.svg",
name: "AnonKlub",
Expand Down
1 change: 1 addition & 0 deletions data/projects/bandada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Bandada is a project designed to simplify the management of privacy-preserving S

export const bandada: ProjectInterface = {
id: "bandada",
section: "pse",
projectStatus: "active",
image: "bandada.webp",
name: "Bandada",
Expand Down
3 changes: 2 additions & 1 deletion data/projects/channel-4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Channel 4 is a community-driven platform where users can submit and discover con

export const channel4: ProjectInterface = {
id: "channel-4",
projectStatus: "active",
section: "pse",
projectStatus: "archived",
image: "channel4.svg",
name: "Channel 4",
tldr: "Content discovery through community contributions, using state channels to reward users for popular posts.",
Expand Down
62 changes: 34 additions & 28 deletions data/projects/coco.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
import { ProjectInterface } from "@/lib/types";
import { ProjectInterface } from "@/lib/types"

export const Coco: ProjectInterface = {
id: "coco",
image: "coco.svg",
name: "COCO",
tldr: "Integrating Nova into the EVM involves wrapping Liam Eagen's theoretical ECIP argument in Halo 2",
description: "With Coco, groups can collaborate to curate feeds of any topic they're interested in. As you scroll through your Coco feed, rather than upvoting or downvoting posts, you'll spend WETH to predict what other group members and the group's moderators will want to see. When you're right, you'll get back your original WETH and more — but if you're wrong, you'll lose what you put in. Through this process, you help Coco filter value from noise to make sure group feeds only consist of posts that the group cares about.",
projectStatus: 'archived',
tags: {
keywords: ['prediction market', 'scaling']
},
extraLinks: {
learn:[{
label: 'Meet COCO!',
url: 'https://mirror.xyz/privacy-scaling-explorations.eth/tEf7iYa8l7ECZwN2T57yyiws7h9Uchip30CQvx-JBBQ'
}],
buildWith: [{
label: 'Smart contracts',
url: 'https://github.com/Janmajayamall/coco-contracts'
},
{
label: 'Frontend',
url: 'https://github.com/Janmajayamall/coco-frontend'
},
{
label: 'Frontend (General)',
url: 'https://github.com/Janmajayamall/coco-frontend-general'
}],
},
id: "coco",
section: "pse",
image: "coco.svg",
name: "COCO",
tldr: "Integrating Nova into the EVM involves wrapping Liam Eagen's theoretical ECIP argument in Halo 2",
description:
"With Coco, groups can collaborate to curate feeds of any topic they're interested in. As you scroll through your Coco feed, rather than upvoting or downvoting posts, you'll spend WETH to predict what other group members and the group's moderators will want to see. When you're right, you'll get back your original WETH and more — but if you're wrong, you'll lose what you put in. Through this process, you help Coco filter value from noise to make sure group feeds only consist of posts that the group cares about.",
projectStatus: "archived",
tags: {
keywords: ["prediction market", "scaling"],
},
extraLinks: {
learn: [
{
label: "Meet COCO!",
url: "https://mirror.xyz/privacy-scaling-explorations.eth/tEf7iYa8l7ECZwN2T57yyiws7h9Uchip30CQvx-JBBQ",
},
],
buildWith: [
{
label: "Smart contracts",
url: "https://github.com/Janmajayamall/coco-contracts",
},
{
label: "Frontend",
url: "https://github.com/Janmajayamall/coco-frontend",
},
{
label: "Frontend (General)",
url: "https://github.com/Janmajayamall/coco-frontend-general",
},
],
},
}
3 changes: 2 additions & 1 deletion data/projects/cryptkeeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ CryptKeeper is a browser extension that generates Semaphore and RLN proofs for w

export const cryptkeeper: ProjectInterface = {
id: "cryptkeeper",
projectStatus: "active",
section: "pse",
projectStatus: "archived",
image: "cryptkeeper.webp",
name: "CryptKeeper",
tldr: "A browser extension for secure, portable anonymous identity management across applications.",
Expand Down
Loading

0 comments on commit 92b6b90

Please sign in to comment.