diff --git a/app/[lang]/resources/page.tsx b/app/[lang]/resources/page.tsx index e6ae4d1..c961b51 100644 --- a/app/[lang]/resources/page.tsx +++ b/app/[lang]/resources/page.tsx @@ -1,6 +1,7 @@ "use client" import { useCallback, useEffect, useRef, useState } from "react" +import Image from "next/image" import Link from "next/link" import { LangProps } from "@/types/common" @@ -176,6 +177,16 @@ export default function ResourcePage({ params: { lang } }: LangProps) { + illustrations + + } actions={ {item.title} diff --git a/components/project/project-filters-bar.tsx b/components/project/project-filters-bar.tsx index b4e31ab..eae5161 100644 --- a/components/project/project-filters-bar.tsx +++ b/components/project/project-filters-bar.tsx @@ -15,6 +15,12 @@ import i18next from "i18next" import { useDebounce } from "react-use" import { IThemeStatus, IThemesButton, LangProps } from "@/types/common" +import { + ProjectSectionLabelMapping, + ProjectSections, + ProjectStatusLabelMapping, + ProjectStatusList, +} from "@/lib/types" import { cn, queryStringToObject } from "@/lib/utils" import { useTranslation } from "@/app/i18n/client" import { LocaleTypes } from "@/app/i18n/settings" @@ -30,11 +36,12 @@ import { Modal } from "../ui/modal" interface FilterWrapperProps { label: string children?: ReactNode + className?: string } -const FilterWrapper = ({ label, children }: FilterWrapperProps) => { +const FilterWrapper = ({ label, children, className }: FilterWrapperProps) => { return ( -
+
{label} {children}
@@ -190,83 +197,103 @@ export default function ProjectFiltersBar({ lang }: LangProps["params"]) { open={showModal} setOpen={setShowModal} > - {Object.entries(filters).map(([key, items]) => { - const filterLabel = - FilterLabelMapping(lang)?.[key as ProjectFilter] ?? "" - const type = FilterTypeMapping?.[key as ProjectFilter] - const hasItems = items.length > 0 +
+ {Object.entries(filters).map(([key, items]) => { + const filterLabel = + FilterLabelMapping(lang)?.[key as ProjectFilter] ?? "" + const type = FilterTypeMapping?.[key as ProjectFilter] + const hasItems = items.length > 0 - const hasActiveThemeFilters = - (activeFilters?.themes ?? [])?.length > 0 + const hasActiveThemeFilters = + (activeFilters?.themes ?? [])?.length > 0 - if (key === "themes" && !hasActiveThemeFilters) return null + if (key === "themes" && !hasActiveThemeFilters) return null - return ( - hasItems && ( - -
- {items.map((item) => { - const isActive = - activeFilters?.[key as ProjectFilter]?.includes(item) + return ( + hasItems && ( + +
+ {items.map((item) => { + const isActive = + activeFilters?.[key as ProjectFilter]?.includes(item) - if (type === "checkbox") { - return ( - - toggleFilter({ - tag: key as ProjectFilter, - value: item, - searchQuery, - }) - } - name={item} - label={item} - checked={isActive} - /> - ) - } - - if (type === "button") { - const { icon, label } = ThemesButtonMapping(lang)[item] - if (!isActive) return null - return ( -
- { + if (type === "checkbox") { + return ( + toggleFilter({ - tag: "themes", + tag: key as ProjectFilter, value: item, searchQuery, }) - }} - > -
- {icon} - - {label} - -
-
-
- ) - } + } + name={item} + label={item} + checked={isActive} + /> + ) + } - return null - })} -
-
+ if (type === "button") { + const { icon, label } = ThemesButtonMapping(lang)[item] + if (!isActive) return null + return ( +
+ { + toggleFilter({ + tag: "themes", + value: item, + searchQuery, + }) + }} + > +
+ {icon} + + {label} + +
+
+
+ ) + } + + return null + })} +
+
+ ) ) - ) - })} + })} + + {ProjectSections.map((section) => { + const label = ProjectSectionLabelMapping[section] + return + })} + + + {ProjectStatusList.map((section) => { + const label = ProjectStatusLabelMapping[section] + return + })} + +
{t("whatDoYouWantDoToday")} diff --git a/components/project/project-list.tsx b/components/project/project-list.tsx index b2d62dd..3875599 100644 --- a/components/project/project-list.tsx +++ b/components/project/project-list.tsx @@ -7,7 +7,11 @@ import { useProjectFiltersState } from "@/state/useProjectFiltersState" import { cva } from "class-variance-authority" import { LangProps } from "@/types/common" -import { ProjectSection, ProjectSections } from "@/lib/types" +import { + ProjectSection, + ProjectSectionLabelMapping, + ProjectSections, +} from "@/lib/types" import { cn } from "@/lib/utils" import { useTranslation } from "@/app/i18n/client" @@ -35,12 +39,6 @@ const NoResults = ({ lang }: LangProps["params"]) => { ) } -export const ProjectSectionLabelMapping: Record = { - pse: "PSE projects", - grant: "Grants", - collaboration: "Collaborations", -} - export const ProjectList = ({ lang }: LangProps["params"]) => { const { t } = useTranslation(lang, "resources-page") const SCROLL_OFFSET = -400 @@ -92,7 +90,7 @@ export const ProjectList = ({ lang }: LangProps["params"]) => { if (noItems) return return ( -
+
{ProjectSections.map((section) => { const sectionProjects = diff --git a/components/site-footer.tsx b/components/site-footer.tsx index 86cb2d6..b02a3d8 100644 --- a/components/site-footer.tsx +++ b/components/site-footer.tsx @@ -13,11 +13,25 @@ import { useTranslation } from "@/app/i18n/client" import { Icons } from "./icons" import { AppContent } from "./ui/app-content" -const SocialMedia = ({ label }: { label: string }) => { +const ItemLabel = ({ + label, + external = false, + icon, +}: { + label: string + external?: boolean + icon?: React.ReactNode +}) => { return ( - - {label} - +
+ {external && ( + + )} + {icon &&
{icon}
} + + {label} + +
) } @@ -32,108 +46,144 @@ export function SiteFooter({ lang }: LangProps["params"]) { return (
-
- - - {MAIN_NAV.map( - ({ title, href, external = false }: NavItem, indexKey) => ( - - {title} - - ) - )} - - - - - {t("menu.jobs")} - - - - - - - - - - - - - - - -
- -
- - - - -
- -
+
+ +
+ logo PSE + + {t("footer.description")} + +
+
+ + {MAIN_NAV.map( + ( + { title, href, external = false, onlyHeader }: NavItem, + indexKey + ) => + !onlyHeader && ( + + + + ) + )} + + + + + + + + + + + + + + + + + + } + /> + + + } + /> + + + + +
+ } + /> + - - - - -
- -
- - - - - - - {t("footer.privacyPolicy")} - - - {t("footer.termsOfUse")} - - + + + +
+ } + /> + +
+ + + + + + + + +
diff --git a/config/site.ts b/config/site.ts index f7ff5a3..3f2a0e0 100644 --- a/config/site.ts +++ b/config/site.ts @@ -16,6 +16,10 @@ export const siteConfig = { jobs: "https://jobs.lever.co/ethereumfoundation/?department=Ethereum%20Foundation&team=Privacy%20and%20Scaling%20Explorations", termOfUse: "https://ethereum.org/en/terms-of-use/", privacyPolicy: "https://ethereum.org/en/privacy-policy/", + activity: + "https://pse-team.notion.site/50dcf22c5191485e93406a902ae9e93b?v=453023f8227646dd949abc34a7a4a138&pvs=4", + report: "https://reports.pse.dev/", + firstGoodIssue: "https://pse-gfis.vercel.app", discordAnnouncementChannel: "https://discord.com/channels/943612659163602974/969614451089227876", }, diff --git a/data/projects/channel-4.ts b/data/projects/channel-4.ts index 96ebc93..d813fe4 100644 --- a/data/projects/channel-4.ts +++ b/data/projects/channel-4.ts @@ -7,7 +7,7 @@ Channel 4 is a community-driven platform where users can submit and discover con export const channel4: ProjectInterface = { id: "channel-4", section: "pse", - projectStatus: "archived", + projectStatus: "inactive", image: "channel4.svg", name: "Channel 4", tldr: "Content discovery through community contributions, using state channels to reward users for popular posts.", diff --git a/data/projects/coco.ts b/data/projects/coco.ts index 2aa052e..2a0f74b 100644 --- a/data/projects/coco.ts +++ b/data/projects/coco.ts @@ -8,7 +8,7 @@ export const Coco: ProjectInterface = { 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", + projectStatus: "inactive", tags: { keywords: ["prediction market", "scaling"], }, diff --git a/data/projects/cryptkeeper.ts b/data/projects/cryptkeeper.ts index 26aed06..91fcfc4 100644 --- a/data/projects/cryptkeeper.ts +++ b/data/projects/cryptkeeper.ts @@ -7,7 +7,7 @@ CryptKeeper is a browser extension that generates Semaphore and RLN proofs for w export const cryptkeeper: ProjectInterface = { id: "cryptkeeper", section: "pse", - projectStatus: "archived", + projectStatus: "inactive", image: "cryptkeeper.webp", name: "CryptKeeper", tldr: "A browser extension for secure, portable anonymous identity management across applications.", diff --git a/data/projects/eigen-trust.ts b/data/projects/eigen-trust.ts index fae4c29..b5af93f 100644 --- a/data/projects/eigen-trust.ts +++ b/data/projects/eigen-trust.ts @@ -7,7 +7,7 @@ EigenTrust is a library designed to manage trust within a distributed network, i export const eigenTrust: ProjectInterface = { id: "eigen-trust", section: "pse", - projectStatus: "archived", + projectStatus: "inactive", image: "", name: "EigenTrust", tldr: "A distributed reputation system with zero-knowledge features.", diff --git a/data/projects/interep.ts b/data/projects/interep.ts index 0f4bc57..f8958cc 100644 --- a/data/projects/interep.ts +++ b/data/projects/interep.ts @@ -8,7 +8,7 @@ export const Interep: ProjectInterface = { tldr: "An identity bridge from web2 to web3", description: "Interep aims to provide an identity solution for Ethereum users by bridging from an established digital identity source such as Reddit, Twitter, and Github. The product provides an identity layer in the application stack and uses the Semaphore framework to ensure privacy. Interep allows users to establish sybil-resistant decentralized identities on web3 without starting from scratch. By leveraging zero-knowledge proofs, Interep ensures only essential information is disclosed.", - projectStatus: "archived", + projectStatus: "inactive", tags: { keywords: ["social", "reputation"], }, diff --git a/data/projects/unirep-protocol.ts b/data/projects/unirep-protocol.ts index c05d28c..a292234 100644 --- a/data/projects/unirep-protocol.ts +++ b/data/projects/unirep-protocol.ts @@ -9,7 +9,7 @@ Using anonymous identifiers (epoch keys), the protocol allows for trustless enga export const unirepProtocol: ProjectInterface = { id: "unirep-protocol", section: "pse", - projectStatus: "archived", + projectStatus: "inactive", image: "unirep.svg", name: "UniRep Protocol", tldr: "A Zero-Knowledge Protocol built to handle anonymous user data.", @@ -26,22 +26,22 @@ export const unirepProtocol: ProjectInterface = { types: ["Legos/dev tools, Protocol"], builtWith: ["semaphore", "circom"], }, - extraLinks: { + extraLinks: { buildWith: [ { label: "Getting Started with create-unirep-app", - url: 'https://developer.unirep.io/docs/next/getting-started/create-unirep-app', + url: "https://developer.unirep.io/docs/next/getting-started/create-unirep-app", }, ], play: [ { label: "Try it out: UniRep.social (Staging)", - url: 'https://social-staging.unirep.workers.dev', + url: "https://social-staging.unirep.workers.dev", }, { label: "Try it out: Trustlist (coming soon) ", - url: 'https://trustlist.pse.dev', - } + url: "https://trustlist.pse.dev", + }, ], }, } diff --git a/data/projects/zkitter.ts b/data/projects/zkitter.ts index f16914c..b2d32c0 100644 --- a/data/projects/zkitter.ts +++ b/data/projects/zkitter.ts @@ -7,7 +7,7 @@ Zkitter is a decentralized social network that emphasizes privacy by default. It export const zkitter: ProjectInterface = { id: "zkitter", section: "pse", - projectStatus: "archived", + projectStatus: "inactive", image: "zkitter.webp", name: "Zkitter", tldr: "A decentralized social network prioritizing privacy and anonymity", diff --git a/data/projects/zkopru.ts b/data/projects/zkopru.ts index 5c06bb0..f82744c 100644 --- a/data/projects/zkopru.ts +++ b/data/projects/zkopru.ts @@ -8,7 +8,7 @@ export const Zkopru: ProjectInterface = { tldr: "Optimistic Rollup with zk-SNARKs for private Ethereum transactions.", description: "ZKOPRU is one of the initial projects of EF's PSE team. It is a Layer 2 scaling solution for Ethereum, emphasizing private transactions through zk-SNARKs and optimistic rollups. It provides an economical Ethereum privacy wallet, enabling users to transact with ETH, ERC-20s, and NFTs anonymously", - projectStatus: "archived", + projectStatus: "inactive", links: { website: "https://zkopru.network/", github: "https://github.com/zkopru-network", diff --git a/hooks/useAppSettings.ts b/hooks/useAppSettings.ts index 8482ebe..0199f9d 100644 --- a/hooks/useAppSettings.ts +++ b/hooks/useAppSettings.ts @@ -1,3 +1,4 @@ +import { siteConfig } from "@/config/site" import { MainNavProps } from "@/components/main-nav" import { useTranslation } from "@/app/i18n/client" import { LocaleTypes, fallbackLng, languageList } from "@/app/i18n/settings" @@ -31,24 +32,7 @@ export function useAppSettings(lang: LocaleTypes) { title: t("menu.blog"), href: "https://mirror.xyz/privacy-scaling-explorations.eth", external: true, - }, - { - title: t("menu.activity"), - href: "https://pse-team.notion.site/50dcf22c5191485e93406a902ae9e93b?v=453023f8227646dd949abc34a7a4a138&pvs=4", - external: true, - onlyFooter: true, - }, - { - title: t("menu.report"), - href: "https://reports.pse.dev/", - external: true, - onlyFooter: true, - }, - { - title: t("menu.firstGoodIssue"), - href: "https://pse-gfis.vercel.app", - external: true, - onlyFooter: true, + onlyHeader: true, }, ] diff --git a/lib/types.ts b/lib/types.ts index 4894cf5..9a599f8 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -2,6 +2,18 @@ export const ProjectSections = ["pse", "grant", "collaboration"] as const export type ProjectSection = (typeof ProjectSections)[number] +export const ProjectStatusList = ["active", "inactive"] as const +export type ProjectStatusType = (typeof ProjectStatusList)[number] + +export const ProjectSectionLabelMapping: Record = { + pse: "PSE projects", + grant: "Grants", + collaboration: "Collaborations", +} +export const ProjectStatusLabelMapping: Record = { + active: "Active", + inactive: "Not Currently Active", +} export interface AnnounceInterface { id: number type?: number @@ -50,7 +62,6 @@ export type ActionLinkType = Partial< Record> > -export type ProjectStatusType = "active" | "inactive" | "archived" export interface ProjectInterface { id: string section: ProjectSection diff --git a/public/icons/resource-illustration.webp b/public/icons/resource-illustration.webp new file mode 100644 index 0000000..75f55b2 Binary files /dev/null and b/public/icons/resource-illustration.webp differ diff --git a/public/logos/pse-logo-circle-white.svg b/public/logos/pse-logo-circle-white.svg new file mode 100644 index 0000000..d81ef95 --- /dev/null +++ b/public/logos/pse-logo-circle-white.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/state/useProjectFiltersState.ts b/state/useProjectFiltersState.ts index 250a8bc..21cc2b9 100644 --- a/state/useProjectFiltersState.ts +++ b/state/useProjectFiltersState.ts @@ -47,6 +47,7 @@ export const FilterTypeMapping: Partial< keywords: "checkbox", builtWith: "checkbox", themes: "button", + fundingSource: "checkbox", } interface ProjectStateProps { sortBy: ProjectSortBy diff --git a/types/nav.ts b/types/nav.ts index 2737534..8492a7f 100644 --- a/types/nav.ts +++ b/types/nav.ts @@ -4,4 +4,5 @@ export interface NavItem { disabled?: boolean external?: boolean onlyFooter?: boolean + onlyHeader?: boolean }