diff --git a/app/[lang]/about/page.tsx b/app/[lang]/about/page.tsx index e023363c..8d08b366 100644 --- a/app/[lang]/about/page.tsx +++ b/app/[lang]/about/page.tsx @@ -1,4 +1,3 @@ -import React from "react" import Image from "next/image" import Link from "next/link" diff --git a/app/[lang]/page.tsx b/app/[lang]/page.tsx index bf2ee9db..1faf9b98 100644 --- a/app/[lang]/page.tsx +++ b/app/[lang]/page.tsx @@ -6,12 +6,12 @@ import PSELogo from "@/public/icons/archstar.webp" import { motion } from "framer-motion" 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 { ConnectWithUs } from "@/components/sections/ConnectWithUs" import { NewsSection } from "@/components/sections/NewsSection" import { WhatWeDo } from "@/components/sections/WhatWeDo" @@ -61,6 +61,8 @@ export default function IndexPage({ params: { lang } }: any) { + + { + return ( + + {label} + + ) +} + +const AccordionLabel = ({ + label, + className, +}: { + label: string + className?: string +}) => { + return ( + + {label} + + ) +} + +const ProgramDetail = ({ + title, + location, + date, + region, + deadline, +}: ProgramDetailProps) => { + return ( +
+ + {region}
+ {title} +
+ + {deadline && ( + + Application Deadline: {deadline} + + )} + + {location && ( +
+ + + {location} + +
+ )} +
+ + {date} +
+
+ ) +} + +const ProgramSections = ["coreProgram", "acceleratorProgram"] as const + +const ChooseProgramItems: { label: string; value: string; href?: string }[] = [ + { + label: "Core Program", + value: "coreProgram", + href: siteConfig.links.coreProgram, + }, + { + label: "Accelerator Program", + value: "acceleratorProgram", + href: siteConfig.links.acceleratorProgram, + }, +] +export const ProgramPageContent = ({ lang }: any) => { + const { t } = useTranslation(lang, "programs-page") + const { t: common } = useTranslation(lang, "common") + const [activeId, setActiveId] = useState("") + const [isManualScroll, setIsManualScroll] = useState(false) + const [selectedProgram, setSelectedProgram] = useState( + ChooseProgramItems[0].value + ) + const SCROLL_OFFSET = -900 + const sectionsRef = useRef | null>(null) + const [{ value: defaultProgramValue }] = ChooseProgramItems + + const howToApply: any = + t("howToApply", { + returnObjects: true, + }) || [] + + const coreProgramDescription: any[] = + t("coreProgram.description", { + returnObjects: true, + }) || [] + const acceleratorProgramDescription: any[] = + t("acceleratorProgram.description", { + returnObjects: true, + }) ?? [] + + const curriculum: any[] = + t("curriculum", { + returnObjects: true, + }) ?? [] + + useEffect(() => { + if (sectionsRef.current === null) + sectionsRef.current = document.querySelectorAll(`div[data-section]`) + if (!activeId) setActiveId(ProgramSections?.[0] ?? "") + + 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 scrollTop = document.documentElement.scrollTop + const rectViewportTop = element?.getBoundingClientRect()?.top ?? 0 + const top = rectViewportTop + scrollTop + + if (element) { + setActiveId(id) // active clicked id + setIsManualScroll(true) // tell the window event listener to ignore this scrolling + window?.scrollTo({ + behavior: "smooth", + top, + }) + } + + setTimeout(() => setIsManualScroll(false), 800) + }, []) + + const selectedProgramKey: string = + ChooseProgramItems?.find((item) => item.value === selectedProgram)?.label ?? + "" + const selectedProgramLabel = t(selectedProgramKey) + + const ApplyButton = () => { + return ( + + ) + } + + const selectedProgramUrl = ChooseProgramItems?.find( + (item) => item.value === selectedProgram + )?.href + + return ( +
+
+ {defaultProgramValue && ( + + } + actions={ + defaultProgramValue && ( +
+
+ {common("chooseProgram")}* + setSelectedProgram(value)} + defaultItem={defaultProgramValue} + /> +
+ {!selectedProgram ? ( + + ) : ( + + + + )} +
+ ) + } + /> + )} +
+
+
+ +
+
+
+
+ +
+
+ + + + + + + + + + + + +
+
+ {coreProgramDescription?.map((description, index) => { + return ( + + {description} + + ) + })} +
+
+
+ + ), + value: "curriculum", + children: ( + + {curriculum.map(({ title, items }, index) => ( +
+
+ + {t("common.week", { + week: index, + })} +
+ {title} +
+
+
+
    + {items.map( + (label: string, index: number) => { + return
  • {label}
  • + } + )} +
+
+
+ ))} +
+ ), + }, + ]} + /> + , + value: "faq", + children: ( +
+ { + return { + label: ( + + {question} + + ), + value: index.toString(), + children: ( + + ), + } + } + )} + /> +
+ ), + }, + ]} + /> +
+
+
+
+
+ +
+
+ + +
+
+
+ + + + Acceleration Program
+ Round 2 + + } + deadline="May 31, 2024" + location="Remote Application" + date="June 1, 2024 - August 31, 2024" + /> +
+ + + +
+
+
+
+ {acceleratorProgramDescription?.map((description, index) => { + return ( + + {description} + + ) + })} +
+
+ , + value: "howToApply", + children: ( +
+
+
+
+ + {t("howToApply.openTasks.title")} + +
    + {howToApply?.openTasks?.description?.map( + (task: string, index: number) => { + return ( +
  • +
    +
  • + ) + } + )} +
+
+
+ + {t("howToApply.submitIdea.title")} + +
    + {howToApply?.submitIdea?.description?.map( + (task: string, index: number) => { + return ( +
  • +
    +
  • + ) + } + )} +
+
+ + {t("howToApply.description")} + +
+
+
+ ), + }, + ]} + /> + + , + value: "faq", + children: ( +
+ { + return { + label: ( + + {question} + + ), + value: index.toString(), + children: ( + + {answer} + + ), + } + } + )} + /> +
+ ), + }, + ]} + /> +
+
+
+
+
+
+
+ ) +} diff --git a/app/[lang]/programs/page.tsx b/app/[lang]/programs/page.tsx new file mode 100644 index 00000000..9573d77a --- /dev/null +++ b/app/[lang]/programs/page.tsx @@ -0,0 +1,21 @@ +import { Metadata } from "next" + +import { ProgramPageContent } from "." + +export const metadata: Metadata = { + title: "Programs page", + description: "Join our free programs to start your journey!", + openGraph: { + images: [ + { + url: "/programs-page-banner.png", + width: 1200, + height: 630, + }, + ], + }, +} + +export default function ProgramsPage({ params: { lang } }: any) { + return +} diff --git a/app/i18n/locales/en/common.json b/app/i18n/locales/en/common.json index 03a0a79f..571f362b 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": "Reports", + "report": "Report", "firstGoodIssue": "First Good Issue", + "programs": "Programs", "openIssues": "Open Issues" }, "footer": { @@ -72,10 +73,14 @@ "whatDoYouWantDoToday": "What do you want to do today?", "showingProjects": "Showing {{count}} projects", "showingProjectsWith": "Showing {{count}} projects with:", + "connectWithUs": "Connect with us", + "connectWithUsDescription": "We welcome contributions from around the world! Join our discord to try out apps, build with our tools, contribute to projects, or check out job openings and grant opportunities.", + "ourYearProgram": "Our {{year}} program", + "onThisPage": "On this page", + "howToApply": "How to apply", + "chooseProgram": "Choose your program", "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 2a339ac8..578bb1e3 100644 --- a/app/i18n/locales/en/homepage.json +++ b/app/i18n/locales/en/homepage.json @@ -5,5 +5,10 @@ "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 discord" + "joinOurDiscord": "Join our community", + "recentUpdates": "Recent updates", + "connectWithUs": { + "title": "Join our programs", + "description": "Want to explore the world of programmable cryptography and learn how to make contributions to open-source projects? Join our free programs to start your journey!" + } } diff --git a/app/i18n/locales/en/programs-page.json b/app/i18n/locales/en/programs-page.json new file mode 100644 index 00000000..a7df600f --- /dev/null +++ b/app/i18n/locales/en/programs-page.json @@ -0,0 +1,91 @@ +{ + "title": "Join our programs", + "description": "Want to explore the world of programmable cryptography and learn how to make substantial contributions to open-source projects? Join our free programs to kickstart your journey!", + "common": { + "faq": "FAQ", + "curriculum": "Curriculum", + "howToApply": "How to apply", + "applyNow": "Apply now", + "learnMoreOnGithub": "Learn more on Github", + "week": "Week {{week}}" + }, + "curriculum": [ + { + "title": "PRE-REQUISITES", + "items": [ + "Course overview and resources", + "Git, GitHub, and PR workflow basics", + "Introduction to ZKPs and Number Theory" + ] + }, + { + "title": "Cryptographic Basics", + "items": [ + "Getting started with Circom", + "Basics of encryption and hash functions", + "Digital signatures and elliptic curve cryptography" + ] + }, + { + "title": "More Crypto + ZKPs", + "items": [ + "Circom crash course + practice", + "KZG Commitments and zkSNARKs", + "Overview of Trusted Setups and Groth16" + ] + }, + { + "title": "Hackathon", + "items": [ + "A break from studying", + "One week to build something with your new skills!" + ] + }, + { + "title": "PLONK Week", + "items": [ + "Learn Rust and complete Rustlings", + "Deep dive into PLONK", + "Make a presentation and blog post on PLONK" + ] + }, + { + "title": "Technologies + Applications", + "items": [ + "Halo2 introduction and practical", + "Study of FHE and MPC", + "Explore Semaphore, Bandada, TLSNotary, ZKEmail" + ] + } + ], + "coreProgram": { + "title": "Core Program", + "description": [ + "PSE's Core Program is an eight-week introductory course for university students looking to explore the world of programmable cryptography. The program will be run hybrid style with online and in-person sessions in Argentina (Buenos Aires), Costa Rica (San José), Ecuador (Cuenca), Japan (Tokyo), South Korea (Seoul), and Taiwan (Taipei).", + "By the end of the program, you will gain comprehensive knowledge about Zero Knowledge Proofs (ZKP), Fully Homomorphic Encryption (FHE), and Multiparty Computation (MPC). You will also bolster your GitHub portfolio, and potentially receive grants for further research and contributions!" + ] + }, + "acceleratorProgram": { + "title": "Accelerator Program", + "description": [ + "The Accelerator Program supports alumni of our entry level programs (e.g. Core Program, ZK Summer, ZK Playground) to deepen explorations of ZKP, FHE, MPC, and related technologies through grants and mentorship. This program operates on a round-based application system, focusing on specific open tasks for each round." + ] + }, + "howToApply": { + "description": "We encourage people to apply as each round opens because we review applications on a first-come first-serve basis! If there are multiple proposals about the same issue, we may consider granting multiple applications on a case-by-case basis.", + "openTasks": { + "title": "To apply for an open task:", + "description": [ + "Explore the Open Task RFP List", + "Apply using this template" + ] + }, + "submitIdea": { + "title": "To submit your own idea:", + "description": [ + "Submit your idea using this template", + "You can look into this idea pool and find one and submit here" + ] + } + } +} \ No newline at end of file diff --git a/components/cards/card.tsx b/components/cards/card.tsx new file mode 100644 index 00000000..2f6e4cc0 --- /dev/null +++ b/components/cards/card.tsx @@ -0,0 +1,45 @@ +import { VariantProps, cva } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const cardVariants = cva("flex flex-col rounded-[8px] overflow-hidden", { + variants: { + variant: { + blue: "bg-anakiwa-100 border border-tuatara-300", + transparent: "bg-transparent border border-tuatara-300", + }, + padding: { + none: "p-0", + xs: "p-4", + sm: "py-8 px-6", + }, + }, + defaultVariants: { + variant: "blue", + padding: "sm", + }, +}) + +interface ProjectCardProps + extends React.HTMLAttributes, + VariantProps {} + +const Card = ({ variant, padding, children, className }: ProjectCardProps) => { + return ( +
+ {children} +
+ ) +} + +Card.displayName = "Card" + +export { Card } diff --git a/components/icons.tsx b/components/icons.tsx index eabc7b35..28e2b69d 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -285,8 +285,8 @@ export const Icons = { ), arrowRight: (props: LucideProps) => ( ), + location: (props: LucideProps) => ( + + + + + + + ), + calendar: (props: LucideProps) => ( + + + + + + + ), + checked: (props: LucideProps) => ( + + + + ), + logoWhite: (props: LucideProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ), } diff --git a/components/main-nav.tsx b/components/main-nav.tsx index 558612bf..6e73aab3 100644 --- a/components/main-nav.tsx +++ b/components/main-nav.tsx @@ -25,6 +25,7 @@ export function MainNav({ items, lang = fallbackLng }: MainNavProps) {