diff --git a/app/[lang]/about/page.tsx b/app/[lang]/about/page.tsx index dd2457c2..e023363c 100644 --- a/app/[lang]/about/page.tsx +++ b/app/[lang]/about/page.tsx @@ -1,32 +1,20 @@ import React from "react" import Image from "next/image" +import Link from "next/link" +import { siteConfig } from "@/config/site" import { Accordion } from "@/components/ui/accordion" import { AppContent } from "@/components/ui/app-content" +import { Button } from "@/components/ui/button" import { Label } from "@/components/ui/label" +import { Banner } from "@/components/banner" +import { Icons } from "@/components/icons" +import { PageHeader } from "@/components/page-header" import { useTranslation } from "@/app/i18n" -const PrincipleImageSizes: Record = { - "principle-1": { - width: 126, - height: 114, - }, - "principle-2": { - width: 176, - height: 260, - }, - "principle-3": { - width: 236, - height: 260, - }, - "principle-4": { - width: 238, - height: 260, - }, -} - export default async function AboutPage({ params: { lang } }: any) { const { t } = await useTranslation(lang, "about-page") + const { t: common } = await useTranslation(lang, "common") const principles: any[] = t("principles", { @@ -34,29 +22,45 @@ export default async function AboutPage({ params: { lang } }: any) { }) ?? [] return ( -
-
- -
-
- - - {t("description")} - -
- pse logo -
-
-
+
+ + } + actions={ + + + + } + /> - -
{t("our-principles-title")}
+ + + {principle.description?.map( (description: string, index: number) => { return

{description}

@@ -78,6 +82,25 @@ export default async function AboutPage({ params: { lang } }: any) { ]} />
+ + + + + +
) } diff --git a/app/[lang]/page.tsx b/app/[lang]/page.tsx index f33b8322..bf2ee9db 100644 --- a/app/[lang]/page.tsx +++ b/app/[lang]/page.tsx @@ -9,7 +9,9 @@ import { siteConfig } from "@/config/site" import { AppContent } from "@/components/ui/app-content" import { Button } from "@/components/ui/button" import { Label } from "@/components/ui/label" +import { Banner } from "@/components/banner" import { Icons } from "@/components/icons" +import { PageHeader } from "@/components/page-header" import { NewsSection } from "@/components/sections/NewsSection" import { WhatWeDo } from "@/components/sections/WhatWeDo" @@ -17,12 +19,12 @@ import { useTranslation } from "../i18n/client" export default function IndexPage({ params: { lang } }: any) { const { t } = useTranslation(lang, "homepage") - const { t: ct } = useTranslation(lang, "common") + const { t: common } = useTranslation(lang, "common") return ( -
- -
+
+ -
- {t("headerSubtitle")} -
+ } + subtitle={t("headerSubtitle")} + image={ +
+ pselogo +
+ } + actions={ -
-
- pselogo -
-
+ } + /> - +
+ -
-
- -
-
- {t("howToPlugIn")} -
-

{t("howToPlugInDescription")}

-
- - - -
-
+ + + + +
) diff --git a/app/[lang]/projects/[id]/page.tsx b/app/[lang]/projects/[id]/page.tsx index fcfa12f3..44f39d50 100644 --- a/app/[lang]/projects/[id]/page.tsx +++ b/app/[lang]/projects/[id]/page.tsx @@ -63,9 +63,9 @@ export default async function ProjectDetailPage({ params }: PageProps) { const hasSocialLinks = Object.keys(currProject?.links ?? {}).length > 0 return ( -
-
-
+
+
+
)} +
-
+
{!currProject?.image && ( - + {currProject?.imageAlt || currProject?.name} )} diff --git a/app/[lang]/projects/page.tsx b/app/[lang]/projects/page.tsx index 619bc48e..d44ecfee 100644 --- a/app/[lang]/projects/page.tsx +++ b/app/[lang]/projects/page.tsx @@ -1,5 +1,7 @@ import { Metadata } from "next" +import Image from "next/image" +import { PageHeader } from "@/components/page-header" import ProjectFiltersBar from "@/components/project/project-filters-bar" import { ProjectList } from "@/components/project/project-list" import { ProjectResultBar } from "@/components/project/project-result-bar" @@ -16,25 +18,27 @@ export default async function ProjectsPage({ params: { lang } }: any) { return ( <> -
-
-
-
-

-

-

- {t("subtitle")} -

-
-
- + + lens icon
-
-
+ } + > + + -
-
-
+
+
+
diff --git a/app/[lang]/resources/page.tsx b/app/[lang]/resources/page.tsx index a3ef58e6..c961b515 100644 --- a/app/[lang]/resources/page.tsx +++ b/app/[lang]/resources/page.tsx @@ -1,8 +1,8 @@ "use client" import { useCallback, useEffect, useRef, useState } from "react" +import Image from "next/image" import Link from "next/link" -import { ArrowUpRight } from "lucide-react" import { LangProps } from "@/types/common" import { siteConfig } from "@/config/site" @@ -10,7 +10,9 @@ import { cn } from "@/lib/utils" import { AppContent } from "@/components/ui/app-content" import { Button } from "@/components/ui/button" import { Label } from "@/components/ui/label" +import { Banner } from "@/components/banner" import { Icons } from "@/components/icons" +import { PageHeader } from "@/components/page-header" import { useTranslation } from "@/app/i18n/client" import ResourcesContent from "../content/resources.md" @@ -48,22 +50,21 @@ const ResourceItem = ({ href={url} target="_blank" rel="noreferrer noopener" - className="group border-b-2 border-anakiwa-300 pb-3 duration-500 hover:border-orange group-hover:transition" + className="group pb-3 duration-500 group-hover:transition" > -
+
- {label} + + {label} +
- +
-

{description}

+

{description}

) } @@ -73,15 +74,12 @@ const ResourceCard = ({ id, title, children }: ResourceCardProps) => {
-

- {title} -

-
{children}
+ +
+ {children} +
) } @@ -166,35 +164,50 @@ const ResourceNav = ({ lang }: LangProps["params"]) => { })}
- - -
) } export default function ResourcePage({ params: { lang } }: LangProps) { const { t } = useTranslation(lang, "resources-page") + const { t: common } = useTranslation(lang, "common") return ( -
- +
+ + illustrations +
+ } + actions={ + + + + } + /> +
-
- -

- {t("subtitle")} -

-
-
- + {t("addResourceQuestion")} - - - - -
+ } + > + + + + ) } diff --git a/app/i18n/locales/en/about-page.json b/app/i18n/locales/en/about-page.json index 3cc7d84b..6f328479 100644 --- a/app/i18n/locales/en/about-page.json +++ b/app/i18n/locales/en/about-page.json @@ -2,30 +2,38 @@ "title": "About our team", "description": "PSE is an Ethereum Foundation supported research and development lab dedicated to testing use cases for cryptographic primitives. We build open source infrastructure and tools, host workshops and summer programs, and collaborate with people bringing cryptography to life.", "our-principles-title": "Our Principles", + "banner": { + "title": "Connect with us", + "subtitle": "Join our discord to learn more about our research, connect with our community, and keep posted about jobs and grant opportunities!" + }, "principles": [ { "title": "01. Cryptography for people", "description": [ - "Cryptography is everywhere: every time you connect to a secure site, log in with a password or unlock your phone, you're seeing cryptography in action. With “programmable” cryptography (like zero knowledge proofs, multi-party computation or homomorphic encryption) we can make verifiable claims about secret information without revealing the information itself. This can be applied to identity management, collusion resistance, anonymous communication and so much more. We're building a library of dev tools, research papers, and prototypes that are open source and free for everyone to use. We hope our resources inspire people to innovate the technologies that their communities need." + "Cryptography is everywhere: every time you connect to a secure site, log in with a password or unlock your phone, you're seeing cryptography in action. With “programmable” cryptography (like zero knowledge proofs, multi-party computation or homomorphic encryption) we can make verifiable claims about secret information without revealing the information itself.", + " This can be applied to identity management, collusion resistance, anonymous communication and so much more. We're building a library of dev tools, research papers, and prototypes that are open source and free for everyone to use. We hope our resources inspire people to innovate the technologies that their communities need." ] }, { "title": "02. Prioritizing privacy", "description": [ - "We believe that privacy is a fundamental right. We want to be part of building an internet that divests from invasive data practices, and instead gives people real choices about who has access to their personal information. Permission should be purpose specific, revocable, informed and uncoerced. We make tools that help people to securely authenticate themselves, make confidential transactions on the blockchain, and respect and preserve user privacy." + "We believe that privacy is a fundamental right. We want to be part of building an internet that divests from invasive data practices, and instead gives people real choices about who has access to their personal information.", + " Permission should be purpose specific, revocable, informed and uncoerced. We make tools that help people to securely authenticate themselves, make confidential transactions on the blockchain, and respect and preserve user privacy." ] }, { "title": "03. Scaling for communities", "description": [ - "Zero knowledge proofs can verify computations quickly and cheaply, helping decentralized systems like Ethereum become more efficient. We research, design and share scaling solutions that anyone can use to contribute to a stronger and more practical digital public infrastructure. We also grow our community by supporting the next generation of builders. We host immersive programs for students and lecture series that are open to everyone interested in building with cryptography." + "Zero knowledge proofs can verify computations quickly and cheaply, helping decentralized systems like Ethereum become more efficient. We research, design and share scaling solutions that anyone can use to contribute to a stronger and more practical digital public infrastructure.", + " We also grow our community by supporting the next generation of builders. We host immersive programs for students and lecture series that are open to everyone interested in building with cryptography." ] }, { "title": "04. Collective exploration", "description": [ - "We are cultivating a diverse and multidisciplinary team to explore the emerging zero knowledge ecosystem. PSE is made up of programmers, engineers, and mathematicians working alongside creatives and community organizers to collaboratively discover the potential of programmable cryptography. We experiment in the open and welcome contributions, integrations, forks, or feedback on all of our projects." + "We are cultivating a diverse and multidisciplinary team to explore the emerging zero knowledge ecosystem. PSE is made up of programmers, engineers, and mathematicians working alongside creatives and community organizers to collaboratively discover the potential of programmable cryptography.", + "We experiment in the open and welcome contributions, integrations, forks, or feedback on all of our projects." ] } ] -} \ No newline at end of file +} diff --git a/app/i18n/locales/en/common.json b/app/i18n/locales/en/common.json index 55f6681c..03a0a79f 100644 --- a/app/i18n/locales/en/common.json +++ b/app/i18n/locales/en/common.json @@ -10,8 +10,9 @@ "languages": "Languages {{locale}}", "blog": "Blog", "activity": "Activity", - "report": "Report", - "firstGoodIssue": "First Good Issue" + "report": "Reports", + "firstGoodIssue": "First Good Issue", + "openIssues": "Open Issues" }, "footer": { "description": "Privacy + Scaling Explorations is a multidisciplinary team supported by the Ethereum Foundation.", @@ -28,7 +29,8 @@ "keywords": "Keywords", "builtWith": "Built with", "themes": "Themes selected", - "projectStatus": "Project status" + "projectStatus": "Project status", + "fundingSource": "Funding source" }, "error": { "404": { @@ -69,5 +71,11 @@ "filters": "Filters", "whatDoYouWantDoToday": "What do you want to do today?", "showingProjects": "Showing {{count}} projects", - "showingProjectsWith": "Showing {{count}} projects with:" + "showingProjectsWith": "Showing {{count}} projects with:", + "connectWithUsOnPlatform": "Connect with us on {{platform}}", + "addResource": "Add a resource", + "notCurrentlyActive": "Not Currently Active", + "connectWithUs": "Connect with us", + "connectWithUsDescription": "Connect with our community on Discord to try out new apps, build with our tools, and contribute to projects!", + "joinOurDiscord": "Join our discord" } \ No newline at end of file diff --git a/app/i18n/locales/en/homepage.json b/app/i18n/locales/en/homepage.json index 8ffcd237..2a339ac8 100644 --- a/app/i18n/locales/en/homepage.json +++ b/app/i18n/locales/en/homepage.json @@ -5,5 +5,5 @@ "whoWeAreDescription": "PSE is a research lab building free tools that expand the world of cryptography.", "howToPlugIn": "How to plug in", "howToPlugInDescription": "Try out our apps, build with our tools, contribute to projects, or check out our job openings. We welcome contributions from around the world!", - "joinOurDiscord": "Join our community" -} \ No newline at end of file + "joinOurDiscord": "Join our discord" +} diff --git a/app/i18n/locales/en/projects-page.json b/app/i18n/locales/en/projects-page.json index 17bf41e3..34b5a7cf 100644 --- a/app/i18n/locales/en/projects-page.json +++ b/app/i18n/locales/en/projects-page.json @@ -1,3 +1,4 @@ { + "title": "Explore the library", "subtitle": "PSE is home to many projects, from cryptography research to developer tools, protocols and proof-of-concept applications." -} +} \ No newline at end of file diff --git a/app/i18n/locales/zh-TW/about-page.json b/app/i18n/locales/zh-TW/about-page.json index 58313ce4..7981480a 100644 --- a/app/i18n/locales/zh-TW/about-page.json +++ b/app/i18n/locales/zh-TW/about-page.json @@ -7,7 +7,7 @@ "title": "01. 面向大眾的密碼學", "description": [ "密碼學無處不在:每次您連接到安全網站、使用密碼登錄或解鎖手機時,都在使用密碼學。", - "通過「可程式化」密碼學(例如零知識證明(ZKP)、多方計算(MPC)或同態加密(FHE)),我們可以對秘密訊息產生可驗證的聲明,而不必揭露訊息本身。這可以應用於身份管理、抵抗共謀、匿名通訊等眾多領域。", + "通過「可程式化」密碼學 (例如零知識證明 (ZKP)、多方計算(MPC)或同態加密(FHE)),我們可以對秘密訊息產生可驗證的聲明,而不必揭露訊息本身。這可以應用於身份管理、抵抗共謀、匿名通訊等眾多領域。", "我們正在建立一系列開源且自由供所有人使用的開發工具、研究論文和軟體原型。我們希望我們的資源能啟發人們去創造他們社群所需的新科技。" ] }, diff --git a/components/banner.tsx b/components/banner.tsx new file mode 100644 index 00000000..fda88301 --- /dev/null +++ b/components/banner.tsx @@ -0,0 +1,35 @@ +import { ReactNode } from "react" + +import { AppContent } from "./ui/app-content" + +type BannerProps = { + title: ReactNode + subtitle?: string + children?: ReactNode +} + +const Banner = ({ title, subtitle, children }: BannerProps) => { + return ( +
+
+ +
+ {typeof title === "string" ? ( +
+ {title} +
+ ) : ( + title + )} + {subtitle &&

{subtitle}

} +
+ {children} +
+
+
+ ) +} + +Banner.displayName = "Banner" + +export { Banner } diff --git a/components/icons.tsx b/components/icons.tsx index 3645d3b6..eabc7b35 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -40,8 +40,8 @@ export const Icons = { ), discord: (props: LucideProps) => ( ( { if (item?.onlyFooter) return null + const langKey = `/${lang}` + const pathParts = item.href + .replace(langKey, "") + .split("/") + .filter(Boolean) + + const isHome = router === "/" && item.href === "/" + // is home or the first part of the path matches the first part of the href + const isActive = + isHome || + (router !== null && + pathParts[0] === router.replace(langKey, "").split("/")[1]) + return ( {item.title} diff --git a/components/page-header.tsx b/components/page-header.tsx new file mode 100644 index 00000000..0463be9a --- /dev/null +++ b/components/page-header.tsx @@ -0,0 +1,55 @@ +import { ReactNode } from "react" +import { t } from "i18next" + +import { cn } from "@/lib/utils" + +import { AppContent } from "./ui/app-content" +import { Label } from "./ui/label" + +type PageHeaderProps = { + title: ReactNode + subtitle?: string + actions?: ReactNode + children?: ReactNode + image?: ReactNode + contentWidth?: number +} + +const PageHeader = ({ + title, + subtitle, + actions, + children, + image, +}: PageHeaderProps) => { + return ( +
+ +
+
+
+ + {subtitle && ( +
+ {subtitle} +
+ )} +
+ {actions} +
+ {image} +
+ {children && ( +
+
+ {children} +
+ )} +
+
+ ) +} + +PageHeader.displayName = "PageHeader" + +export { PageHeader } diff --git a/components/project/discover-more-projects.tsx b/components/project/discover-more-projects.tsx index 9f6cc8ff..d8e7bea6 100644 --- a/components/project/discover-more-projects.tsx +++ b/components/project/discover-more-projects.tsx @@ -36,20 +36,24 @@ export default function DiscoverMoreProjects({ project, lang }: ProjectProps) { const suggestedProject = getSuggestedProjects() return ( -
-

{t("discoverMore")}

-
- {suggestedProject?.map((project: ProjectInterface) => ( - - ))} +
+
+

{t("discoverMore")}

+
+ {suggestedProject?.map((project: ProjectInterface) => ( + + ))} +
+ + + + {t("backToProjectLibrary")} + +
- - - {t("backToProjectLibrary")} -
) } diff --git a/components/project/project-card.tsx b/components/project/project-card.tsx index 06a1a2af..3163e9ea 100644 --- a/components/project/project-card.tsx +++ b/components/project/project-card.tsx @@ -7,6 +7,7 @@ import { VariantProps, cva } from "class-variance-authority" import { ProjectInterface, ProjectLinkWebsite } from "@/lib/types" import { cn } from "@/lib/utils" +import { useTranslation } from "@/app/i18n/client" import { LocaleTypes } from "@/app/i18n/settings" import { Icons } from "../icons" @@ -29,11 +30,11 @@ const TagsIconMapping: Record = { } const projectCardVariants = cva( - "flex w-[310px] cursor-pointer flex-col overflow-hidden rounded-lg transition duration-150 ease-in hover:scale-105", + "flex cursor-pointer flex-col overflow-hidden rounded-lg transition duration-150 ease-in hover:scale-105", { variants: { showLinks: { - true: "min-h-[460px]", + true: "min-h-[450px]", false: "min-h-[200px]", }, border: { @@ -51,9 +52,13 @@ export default function ProjectCard({ className, lang, }: ProjectCardProps & { lang: LocaleTypes }) { + const { t } = useTranslation(lang, "common") const router = useRouter() - const { id, image, links, name, tldr, tags, imageAlt } = project + const { id, image, links, name, tldr, tags, imageAlt, projectStatus } = + project + + const projectNotActive = projectStatus !== "active" return (
)} -
+
{tags?.themes?.map((theme, index) => { @@ -94,21 +99,30 @@ export default function ProjectCard({ })}

{name}

-

{tldr}

-
- {showLinks && ( -
- {Object.entries(links ?? {})?.map(([website, url], index) => { - return ( - - ) - })} +
+

{tldr}

- )} +
+
+ {showLinks && ( +
+ {Object.entries(links ?? {})?.map(([website, url], index) => { + return ( + + ) + })} +
+ )} + {projectNotActive && ( + + {t("notCurrentlyActive")} + + )} +
) diff --git a/components/project/project-detail-tags.tsx b/components/project/project-detail-tags.tsx index 6e10c8ff..cde29fc2 100644 --- a/components/project/project-detail-tags.tsx +++ b/components/project/project-detail-tags.tsx @@ -7,7 +7,7 @@ import { ProjectFilter, } from "@/state/useProjectFiltersState" -import { ProjectInterface } from "@/lib/types" +import { ProjectInterface, ProjectSectionLabelMapping } from "@/lib/types" import { useTranslation } from "@/app/i18n/client" import { LocaleTypes } from "@/app/i18n/settings" @@ -20,7 +20,7 @@ interface TagsProps extends HtmlHTMLAttributes { const TagsWrapper = ({ label, children }: TagsProps) => { return ( -
+
{label} {children}
@@ -72,6 +72,13 @@ export function ProjectTags({ project, lang }: IProjectTags) {
+ + +
+ {ProjectSectionLabelMapping[project?.section]} +
+
+
) } diff --git a/components/project/project-filters-bar.tsx b/components/project/project-filters-bar.tsx index b4e31aba..123e081c 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}
@@ -68,7 +75,7 @@ export const ThemesStatusMapping = (lang: LocaleTypes): IThemeStatus => { label: t("status.active"), icon: , }, - archived: { + inactive: { label: t("status.inactive"), icon: , }, @@ -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 - - const hasActiveThemeFilters = - (activeFilters?.themes ?? [])?.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 - if (key === "themes" && !hasActiveThemeFilters) return null + const hasActiveThemeFilters = + (activeFilters?.themes ?? [])?.length > 0 - return ( - hasItems && ( - -
- {items.map((item) => { - const isActive = - activeFilters?.[key as ProjectFilter]?.includes(item) + if (key === "themes" && !hasActiveThemeFilters) return null - if (type === "checkbox") { - return ( - - toggleFilter({ - tag: key as ProjectFilter, - value: item, - searchQuery, - }) - } - name={item} - label={item} - checked={isActive} - /> - ) - } + return ( + hasItems && ( + +
+ {items.map((item) => { + const isActive = + activeFilters?.[key as ProjectFilter]?.includes(item) - 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-link.tsx b/components/project/project-link.tsx index ffadbeed..e8a81d53 100644 --- a/components/project/project-link.tsx +++ b/components/project/project-link.tsx @@ -25,15 +25,13 @@ export function ProjectLink({ website, url }: ProjectLinkProps) { target="_blank" rel="noopener noreferrer" > -
- {`${website}Vector`} -
+ {`${website}Vector`} ) } diff --git a/components/project/project-list.tsx b/components/project/project-list.tsx index 25d0feed..38755995 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"]) => { ) } -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,8 +90,8 @@ export const ProjectList = ({ lang }: LangProps["params"]) => { if (noItems) return return ( -
-
+
+
{ProjectSections.map((section) => { const sectionProjects = projects.filter( @@ -118,13 +116,13 @@ export const ProjectList = ({ lang }: LangProps["params"]) => {

{sectionTitle}

-
+
{sectionProjects.map((project) => ( {

{t("recentUpdates")}

- +
{!loading ? ( diff --git a/components/sections/WhatWeDo.tsx b/components/sections/WhatWeDo.tsx index fb7eab84..d607a521 100644 --- a/components/sections/WhatWeDo.tsx +++ b/components/sections/WhatWeDo.tsx @@ -34,8 +34,8 @@ export const WhatWeDo = ({ lang }: LangProps["params"]) => { ] return ( - <> - +
+
@@ -48,7 +48,7 @@ export const WhatWeDo = ({ lang }: LangProps["params"]) => {
{content.map((item, index) => (
@@ -65,6 +65,6 @@ export const WhatWeDo = ({ lang }: LangProps["params"]) => {
- +
) } diff --git a/components/site-footer.tsx b/components/site-footer.tsx index b18894be..b02a3d84 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,116 +46,144 @@ export function SiteFooter({ lang }: LangProps["params"]) { return (
-
-
- logo -

- {t("footer.description")} -

-
-
-
- - - {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/components/ui/accordion.tsx b/components/ui/accordion.tsx index 2eae2bb1..f1dc7338 100644 --- a/components/ui/accordion.tsx +++ b/components/ui/accordion.tsx @@ -34,7 +34,7 @@ const Accordion = ({ value={value} key={accordionIndex} > - + {label} diff --git a/components/ui/label.tsx b/components/ui/label.tsx index 9ea054a5..a60b4ba1 100644 --- a/components/ui/label.tsx +++ b/components/ui/label.tsx @@ -1,5 +1,21 @@ +import { cn } from "@/lib/utils" + interface LabelProps { label: React.ReactNode + className?: string +} + +const SectionTitle = ({ label, className = "" }: LabelProps) => { + return ( +

+ {label} +

+ ) } const MainPageTitle = ({ label }: LabelProps) => { @@ -13,6 +29,7 @@ const MainPageTitle = ({ label }: LabelProps) => { const Label = { displayName: "Label", PageTitle: MainPageTitle, + Section: SectionTitle, } export { Label } diff --git a/config/site.ts b/config/site.ts index f7ff5a35..3f2a0e07 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 96ebc93b..d813fe46 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 2aa052ef..2a0f74b2 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 26aed060..91fcfc48 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 fae4c299..b5af93ff 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 0f4bc574..f8958ccd 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 c05d28c5..a292234b 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 f16914c8..b2d32c0a 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 5c06bb0f..f82744ce 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 8482ebe3..0199f9df 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 94fe8ee4..9a599f8a 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 @@ -35,7 +47,12 @@ export type ProjectLinkWebsite = export type ProjectLinkType = Partial> export type ProjectExtraLinkType = "buildWith" | "play" | "research" | "learn" -export type TagType = "types" | "themes" | "builtWith" | "keywords" +export type TagType = + | "types" + | "themes" + | "builtWith" + | "keywords" + | "fundingSource" export type ProjectTags = Partial> export type ActionLinkTypeLink = { label: string @@ -45,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/lens.webp b/public/icons/lens.webp new file mode 100644 index 00000000..73fd5474 Binary files /dev/null and b/public/icons/lens.webp differ diff --git a/public/icons/resource-illustration.webp b/public/icons/resource-illustration.webp new file mode 100644 index 00000000..75f55b22 Binary files /dev/null and b/public/icons/resource-illustration.webp differ diff --git a/public/images/lens.svg b/public/images/lens.svg new file mode 100644 index 00000000..75301047 --- /dev/null +++ b/public/images/lens.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/logos/pse-logo-circle-white.svg b/public/logos/pse-logo-circle-white.svg new file mode 100644 index 00000000..d81ef951 --- /dev/null +++ b/public/logos/pse-logo-circle-white.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/social-medias/github-fill.svg b/public/social-medias/github-fill.svg index 691c786d..e5ca7336 100644 --- a/public/social-medias/github-fill.svg +++ b/public/social-medias/github-fill.svg @@ -1,10 +1,10 @@ - - - - - - - - - + + + + + + + + + diff --git a/public/social-medias/global-line.svg b/public/social-medias/global-line.svg index 3056f5db..16f6555b 100644 --- a/public/social-medias/global-line.svg +++ b/public/social-medias/global-line.svg @@ -1,10 +1,10 @@ - - - - - - - - - + + + + + + + + + diff --git a/state/useProjectFiltersState.ts b/state/useProjectFiltersState.ts index c0562e1f..21cc2b9b 100644 --- a/state/useProjectFiltersState.ts +++ b/state/useProjectFiltersState.ts @@ -8,7 +8,11 @@ import { uniq } from "@/lib/utils" import { LocaleTypes, fallbackLng } from "@/app/i18n/settings" export type ProjectSortBy = "random" | "asc" | "desc" | "relevance" -export type ProjectFilter = "keywords" | "builtWith" | "themes" +export type ProjectFilter = + | "keywords" + | "builtWith" + | "themes" + | "fundingSource" export type FiltersProps = Record export const DEFAULT_PROJECT_SORT_BY: ProjectSortBy = "asc" interface ProjectInterfaceScore extends ProjectInterface { @@ -33,13 +37,17 @@ export const FilterLabelMapping = ( keywords: t("filterLabels.keywords"), builtWith: t("filterLabels.builtWith"), themes: t("filterLabels.themes"), + fundingSource: t("filterLabels.fundingSource"), } } -export const FilterTypeMapping: Record = { +export const FilterTypeMapping: Partial< + Record +> = { keywords: "checkbox", builtWith: "checkbox", themes: "button", + fundingSource: "checkbox", } interface ProjectStateProps { sortBy: ProjectSortBy @@ -83,6 +91,7 @@ const getProjectFilters = (): FiltersProps => { themes: ["play", "build", "research"], keywords: [], builtWith: [], + fundingSource: [], } // get list of all tags from project list diff --git a/tailwind.config.js b/tailwind.config.js index f2ce887b..2f39b141 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -8,19 +8,23 @@ module.exports = { container: { center: true, padding: "2rem", + + }, + extend: { screens: { "2xl": "1400px", + "3xl": "1600px", + "medium": "978px", }, - }, - extend: { translate: { center: "translate(-50%, -50%)", }, backgroundImage: { "main-gradient": "radial-gradient(114.29% 42.52% at 103.66% 58.94%, #D0F8F1 0%, #D1F3FF 18.23%, #ECF8FF 51.28%, #E1FFFA 80.21%, #D0F2FF 93.23%)", - "second-gradient": - "radial-gradient(56.07% 115.65% at 93.66% 158.94%, #D0F8F1 0%, #D1F3FF 18.23%, #ECF8FF 51.28%, #E1FFFA 80.21%, #D0F2FF 93.23%)", + "cover-gradient": "linear-gradient(84deg, #FFF -1.95%, #C2E8F5 59.98%, #FFF 100.64%)", + "classic-gradient": "radial-gradient(325.52% 79.63% at 100% -0.02%, #FFF 0%, rgba(255, 255, 255, 0.00) 100%), radial-gradient(205.45% 61.89% at 2.34% 99.98%, #FFF 0%, rgba(255, 255, 255, 0.00) 100%)", + "project-page-gradient": "linear-gradient(180deg, #C2E8F5 -17.44%, #FFF 17.72%)" }, colors: { corduroy: "#4A5754", @@ -30,6 +34,7 @@ module.exports = { input: "hsl(var(--input))", ring: "hsl(var(--ring))", anakiwa: { + default: "#D0F2FF", 50: "#F2FAFD", 100: "hsl(var(--anakiwa))", 100: "#E4F3FA", @@ -45,6 +50,8 @@ module.exports = { tuatara: { 100: "#E5E6E8", 200: "#CDCFD4", + 300: "#AAADB6", + 400: "#808590", 500: "#656A75", 600: "#565964", 700: "#4A4C54", diff --git a/types/nav.ts b/types/nav.ts index 2737534a..8492a7f2 100644 --- a/types/nav.ts +++ b/types/nav.ts @@ -4,4 +4,5 @@ export interface NavItem { disabled?: boolean external?: boolean onlyFooter?: boolean + onlyHeader?: boolean }