Skip to content

Commit

Permalink
feat(website): create the learn page
Browse files Browse the repository at this point in the history
  • Loading branch information
vplasencia committed Nov 6, 2023
1 parent 4b78701 commit 630ed62
Show file tree
Hide file tree
Showing 18 changed files with 1,115 additions and 53 deletions.
1 change: 1 addition & 0 deletions apps/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"framer-motion": "^10.16.4",
"next": "13.5.5",
"react": "^18",
"react-code-blocks": "^0.1.4",
"react-dom": "^18"
},
"devDependencies": {
Expand Down
293 changes: 293 additions & 0 deletions apps/website/src/app/learn/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
import {
Flex,
Link,
Text,
VStack,
Tabs,
TabList,
TabPanels,
Tab,
TabPanel,
TabIndicator,
Divider
} from "@chakra-ui/react"
import Image from "next/image"
import InfoCard, { InfoBlock } from "../../components/InfoCard"
import SectionBlock, { SectionBlockProps } from "../../components/SectionBlock"
import MediaCarousel from "../../components/VideosCarousel"
import IconEyelash from "@/icons/IconEyelash"
import IconEye from "@/icons/IconEye"
import IconUser from "@/icons/IconUser"
import IconTree from "@/icons/IconTree"
import IconManageUsers from "@/icons/IconManageUsers"
import IconGroup from "@/icons/IconGroup"
import IconBadge from "@/icons/IconBadge"
import IconCheck from "@/icons/IconCheck"
import IconFlag from "@/icons/IconFlag"
import ArticlesCarousel from "@/components/ArticlesCarousel"

export default function Learn() {
const infoCardTexts: InfoBlock[][] = [
[
{
title: "Accessibility",
body: "To reach a very large group of developers, a protocol needs to be extremely user-friendly, understandable and simple."
},
{
title: "Composability",
body: "Achieve an excellent balance between simplicity and functionality through modularity, autonomy, and interoperability. "
},
{
title: "Efficiency",
body: "A protocol must not only work, it must also be extremely efficient if the goal is to support privacy by default for everyone."
}
],
[
{
title: "Developer experience",
body: "Enabling developers to focus on innovation by simplifying complexities while supporting diverse use cases."
},
{
title: "Education",
body: "Empowering individuals with knowledge, resources, and support, ensuring they're equipped to innovate and solve challenges."
},
{
title: "Community",
body: "Fostering spaces where collaboration thrives, ideas flourish, and diverse voices are celebrated."
}
],
[
{
title: "Completeness",
body: "If the statement is true, an honest verifier will be convinced of this fact by an honest prover every time."
},
{
title: "Soundness",
body: "If the statement is false, no cheating prover can convince an honest verifier that is true, except with some small probability."
},
{
title: "Zero-knowledge",
body: "If the statement is true, no verifier learns anything other than the fact that the statement is true."
}
]
]

const sectionBlockTexts: SectionBlockProps[] = [
{
title: "Semaphore identities",
description:
"Given to all Semaphore group members, it is comprised of three parts - identity commitment, trapdoor, and nullifier.",
linkText: "Create Semaphore identities",
linkUrl: "https://semaphore.pse.dev/docs/guides/identities",
codeText: `import { Identity } from "@semaphore-protocol/identity"
const identity = new Identity()
const trapdoor = identity.getTrapdoor()
const nullifier = identity.getNullifier()
const commitment = identity.generateCommitment()`,
itemList: [
{
icon: <IconEyelash w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Private values",
body: "Trapdoor and nullifier values are the private values of the Semaphore identity. To avoid fraud, the owner must keep both values secret."
},
{
icon: <IconEye w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Private values",
body: "Trapdoor and nullifier values are the private values of the Semaphore identity. To avoid fraud, the owner must keep both values secret."
},
{
icon: <IconUser w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Generate identities",
body: "Semaphore identities can be generated deterministically or randomly. Deterministic identities can be generated from the hash of a secret message."
}
]
},
{
title: "Semaphore groups",
description:
"Semaphore groups are binary incremental Merkle trees that store the public identity commitment of each member.",
linkText: "Create Semaphore groups",
linkUrl: "https://semaphore.pse.dev/docs/guides/groups",
codeText: `import { Group } from "@semaphore-protocol/group"
const group = new Group()
group.addMember(commitment)`,
itemList: [
{
icon: <IconTree w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Merkle trees",
body: "Each leaf contains an identity commitment for a user. The identity commitment proves that the user is a group member without revealing the private identity of the user."
},
{
icon: <IconGroup w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Types of groups",
body: "Groups can be created and managed in a decentralized fashion with Semaphore contracts or off-chain with our JavaScript libraries."
},
{
icon: <IconManageUsers w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Group management",
body: "Users can join and leave groups by themselves, or an admin can add and remove them. Admins can be centralized authorities, Ethereum accounts, multi-sig wallets or smart contracts."
}
]
},
{
title: "Semaphore proofs",
description:
"Semaphore group members can anonymously prove that they are part of a group and that they are generating their own proofs and signals.",
linkText: "Generate Semaphore proofs",
linkUrl: "https://semaphore.pse.dev/docs/guides/proofs",
codeText: `import { generateProof, verifyProof } from "@semaphore-protocol/proof"
const externalNullifier = BigInt(1)
const signal = "Hello world"
const fullProof = await generateProof(identity, group, externalNullifier, signal, {
zkeyFilePath: "./semaphore.zkey",
wasmFilePath: "./semaphore.wasm"
})
const verificationKey = JSON.parse(fs.readFileSync("./semaphore.json", "utf-8"))
await verifyProof(verificationKey, fullProof)`,
itemList: [
{
icon: <IconBadge w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Membership",
body: "Only users who are part of a group can generate a valid proof for that group."
},
{
icon: <IconFlag w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Signals",
body: "Group users can anonymously broadcast signals such as votes or endorsements without revealing their original identity."
},
{
icon: <IconCheck w={"24px"} h={"24px"} color={"ceruleanBlue"} />,
heading: "Verifiers",
body: "Semaphore proofs can be verified with our contracts or off-chain with our JavaScript libraries."
}
]
}
]

const renderTabBlockSemaphore = () => (
<VStack>
<VStack w={"720px"}>
<Text fontSize={"44px"} fontWeight={"500"}>
Semaphore: Anonymous interactions
</Text>
<Text fontSize={"20px"} mt={"24px"} lineHeight={"32px"}>
Using zero knowledge, Semaphore allows users to prove their membership of a group and send signals
such as votes or endorsements without revealing their original identity. The goal is to make
Semaphore a standard for anonymous signaling and group membership proving.
</Text>
</VStack>
<VStack mt={"40px"}>
<Flex gap={"32px"}>
<VStack>
<Text fontSize={"30px"} fontWeight={"500"}>
Principles
</Text>
<InfoCard texts={infoCardTexts[0]} />
</VStack>
<VStack>
<Text fontSize={"30px"} fontWeight={"500"}>
Main focus
</Text>
<InfoCard texts={infoCardTexts[1]} />
</VStack>
</Flex>
</VStack>
</VStack>
)

const renderTabBlockZeroKnowledge = () => (
<VStack>
<VStack w={"720px"}>
<Text fontSize={"44px"} fontWeight={"500"}>
Zero Knowledge: new cryptography
</Text>
<Text fontSize={"20px"} mt={"24px"} lineHeight={"32px"}>
Zero-knowledge is a new field in cryptography that allows developers to build apps that allow users
to share information with each other without revealing their identities or the contents of the
information being shared.
</Text>
<Link href="https://pse.dev/resources" isExternal>
<Text
borderBottomWidth={"1px"}
borderBottomColor={"white"}
_hover={{ borderBottomColor: "transparent" }}
fontSize="20px"
fontWeight="normal"
>
Learn more
</Text>
</Link>
</VStack>
<VStack mt={"40px"}>
<VStack>
<Text fontSize={"30px"} fontWeight={"500"}>
Characteristics
</Text>
<InfoCard texts={infoCardTexts[0]} />
</VStack>
</VStack>
</VStack>
)

return (
<VStack>
<VStack h="1187px">
<Image
src="https://semaphore.cedoor.dev/guy-shadow-horizontal.png"
width={0}
height={0}
sizes="100vw"
style={{ width: "auto", height: "1187px", zIndex: "-1", position: "absolute" }}
alt="Shadow of a person"
/>
<Tabs position="relative" variant="unstyled" align={"center"} mt={"170px"}>
<TabList gap={"40px"}>
<Tab px={0} fontSize={"24px"}>
About Semaphore
</Tab>
<Tab px={0} fontSize={"24px"}>
About Zero Knowledge
</Tab>
</TabList>
<TabIndicator mt="-1.5px" height="2px" bg="white" borderRadius="1px" />
<TabPanels mt={"80px"}>
<TabPanel>{renderTabBlockSemaphore()}</TabPanel>
<TabPanel>{renderTabBlockZeroKnowledge()}</TabPanel>
</TabPanels>
</Tabs>
</VStack>
<VStack p={"128px 80px"}>
{sectionBlockTexts.map((sectionBlockText, i) => (
<VStack>
<SectionBlock
key={i}
title={sectionBlockText.title}
description={sectionBlockText.description}
linkText={sectionBlockText.linkText}
linkUrl={sectionBlockText.linkUrl}
codeText={sectionBlockText.codeText}
itemList={sectionBlockText.itemList}
/>
{i !== sectionBlockTexts.length - 1 && <Divider my={"68px"} borderColor={"alabaster.600"} />}
</VStack>
))}
</VStack>
<VStack backgroundColor={"darkBlue"} w={"100vw"}>
<VStack mt={"128px"}>
<MediaCarousel />
</VStack>
<VStack mt={"96px"} mb={"66px"}>
<ArticlesCarousel />
</VStack>
</VStack>
</VStack>
)
}
6 changes: 3 additions & 3 deletions apps/website/src/components/ActionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export type ActionCardProps = {
export default function ActionCard({ title, description, buttonText }: ActionCardProps) {
return (
<Card
bg={"white"}
textColor={"darkBlue1"}
bg={"darkBlue"}
textColor={"white"}
borderRadius={"24px"}
width={{ base: "full", xl: "1110px" }}
height={{ base: "full", xl: "244px" }}
Expand All @@ -24,7 +24,7 @@ export default function ActionCard({ title, description, buttonText }: ActionCar
gap={{ base: "2rem", md: "0" }}
>
<Stack width={{ base: "full", md: "522px" }}>
<Heading fontSize={"40px"} lineHeight={"44px"} fontWeight={"normal"} textColor={"darkBlueBg"}>
<Heading fontSize={"40px"} lineHeight={"44px"} fontWeight={"normal"} textColor={"white"}>
{title}
</Heading>
<Text
Expand Down
47 changes: 25 additions & 22 deletions apps/website/src/components/ArticleCard.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import { Heading, Text, Card, CardBody, CardFooter } from "@chakra-ui/react"
import { Heading, Text, Card, CardBody, CardFooter, Link } from "@chakra-ui/react"

export type ArticleCardProps = {
title: string
minRead: number
url: string
}

export default function ArticleCard({ title, minRead }: ArticleCardProps) {
export default function ArticleCard({ title, minRead, url }: ArticleCardProps) {
return (
<Card
bg={"transparent"}
borderRadius={"10px"}
color={"white"}
padding={"24px 20px"}
width={{ base: "full", sm: "297.5px" }}
height={"210px"}
_hover={{ bgColor: "darkBlue1" }}
>
<CardBody padding={0}>
<Heading fontSize={"20px"} lineHeight={"28px"}>
{title}
</Heading>
</CardBody>
<CardFooter padding={0}>
<Text fontSize={"14px"} lineHeight={"22.4px"}>
{`${minRead} min read`}
</Text>
</CardFooter>
</Card>
<Link href={url} isExternal>
<Card
bg={"transparent"}
borderRadius={"10px"}
color={"white"}
padding={"24px 20px"}
width={{ base: "full", sm: "297.5px" }}
height={"210px"}
_hover={{ bgColor: "darkBlueBg" }}
>
<CardBody padding={0}>
<Heading fontSize={"20px"} lineHeight={"28px"}>
{title}
</Heading>
</CardBody>
<CardFooter padding={0}>
<Text fontSize={"14px"} lineHeight={"22.4px"}>
{`${minRead} min read`}
</Text>
</CardFooter>
</Card>
</Link>
)
}
Loading

0 comments on commit 630ed62

Please sign in to comment.