Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project details wiki #180

Merged
merged 7 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 124 additions & 89 deletions app/[lang]/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import GithubVector from "@/public/social-medias/github-fill.svg"
import GlobalVector from "@/public/social-medias/global-line.svg"
import TwitterVector from "@/public/social-medias/twitter-fill.svg"

import { siteConfig } from "@/config/site"
import { ProjectInterface } from "@/lib/types"
import { Markdown } from "@/components/ui/markdown"
import { AppContent } from "@/components/ui/app-content"
import { Markdown, createMarkdownElement } from "@/components/ui/markdown"
import { WikiCard } from "@/components/cards/wiki-card"
import { Divider } from "@/components/divider"
import { Icons } from "@/components/icons"
import DiscoverMoreProjects from "@/components/project/discover-more-projects"
import { ProjectTags } from "@/components/project/project-detail-tags"
import ProjectExtraLinks from "@/components/project/project-extra-links"
import { ThemesStatusMapping } from "@/components/project/project-filters-bar"
import { WikiSideNavigation } from "@/components/wiki-side-navigation"
import { useTranslation } from "@/app/i18n"
import { LocaleTypes } from "@/app/i18n/settings"

Expand Down Expand Up @@ -54,115 +59,145 @@ export async function generateMetadata(
}

export default async function ProjectDetailPage({ params }: PageProps) {
const currProject = projects.filter(
const currProject: ProjectInterface = projects.filter(
(project) => String(project.id) === params.id
)[0]
const lang = params?.lang as LocaleTypes
const { t } = await useTranslation(lang, "common")
const { t: tProject } = await useTranslation(
const { t: projectTranslation } = await useTranslation(
lang,
"projects/" + currProject.id
)

const { github, twitter, website } = currProject.links ?? {}
const hasSocialLinks = Object.keys(currProject?.links ?? {}).length > 0

const editPageURL = siteConfig?.editProjectPage(currProject.id, lang)

return (
<section className="bg-project-page-gradient">
<Divider.Section className="flex flex-col items-center">
<div className="flex w-full flex-col items-center justify-center gap-5 px-6 py-8 md:px-0 md:py-16">
<div className=" w-full md:max-w-[644px]">
<div className="flex flex-col">
<div className="flex flex-col gap-6 text-left">
<Link
className="flex items-center gap-2 text-tuatara-950/80 hover:text-tuatara-950"
href={`/${lang}/projects`}
>
<Icons.arrowLeft />
<span className="font-sans text-base">
{t("projectLibrary")}
</span>
</Link>
<div className="flex flex-col gap-2">
<h1 className="py-2 text-3xl font-bold leading-[110%] md:text-5xl">
{currProject.name}
</h1>
<p className="py-2 leading-[150%] text-slate-600">
{tProject("tldr")}
</p>
</div>
</div>
{hasSocialLinks && (
<div className="flex flex-wrap items-center justify-start gap-6 pt-4">
{github && (
<Link href={github} target="_blank" rel="noreferrer">
<div className="flex items-center gap-2">
<Image
src={GithubVector}
alt=""
width={16}
height={16}
/>
<p className="text-slate-600">Github</p>
</div>
</Link>
)}
{website && (
<Link href={website} target="_blank" rel="noreferrer">
<div className="flex items-center gap-2">
<Image
src={GlobalVector}
alt=""
width={16}
height={16}
/>
<p className="text-slate-600">Website</p>
</div>
</Link>
)}
{twitter && (
<Link href={twitter} target="_blank" rel="noreferrer">
<div className="flex items-center gap-2">
<Image
src={TwitterVector}
alt=""
width={16}
height={16}
/>
<p className="text-slate-600">Twitter</p>
</div>
<AppContent className="flex flex-col gap-12 py-16">
<div className="grid grid-cols-1 gap-10 lg:grid-cols-[140px_1fr_290px] lg:items-start lg:gap-12">
<div className="sticky top-20">
<WikiSideNavigation
className="hidden md:block"
content={projectTranslation("description")}
/>
</div>

<div className="flex flex-col items-center justify-center w-full gap-5 ">
<div className="w-full ">
<div className="flex flex-col">
<div className="flex flex-col gap-6 text-left">
<Link
className="flex items-center gap-2 text-tuatara-950/80 hover:text-tuatara-950"
href={`/${lang}/projects`}
>
<Icons.arrowLeft />
<span className="font-sans text-base">
{t("projectLibrary")}
</span>
</Link>
<div className="flex flex-col gap-2">
<h1 className="py-2 text-3xl font-bold leading-[110%] md:text-5xl">
{currProject.name}
</h1>
<p className="py-2 leading-[150%] text-slate-600">
{projectTranslation("tldr")}
</p>
</div>
</div>
{hasSocialLinks && (
<div className="flex flex-wrap items-center justify-start gap-6 pt-4">
{github && (
<Link href={github} target="_blank" rel="noreferrer">
<div className="flex items-center gap-2">
<Image
src={GithubVector}
alt=""
width={16}
height={16}
/>
<p className="text-slate-600">Github</p>
</div>
</Link>
)}
{website && (
<Link href={website} target="_blank" rel="noreferrer">
<div className="flex items-center gap-2">
<Image
src={GlobalVector}
alt=""
width={16}
height={16}
/>
<p className="text-slate-600">Website</p>
</div>
</Link>
)}
{twitter && (
<Link href={twitter} target="_blank" rel="noreferrer">
<div className="flex items-center gap-2">
<Image
src={TwitterVector}
alt=""
width={16}
height={16}
/>
<p className="text-slate-600">Twitter</p>
</div>
</Link>
)}
</div>
)}
<div className="mt-10 hidden h-[1px] w-full bg-anakiwa-300 md:block"></div>
</div>
)}
<div className="mt-10 hidden h-[1px] w-full bg-anakiwa-300 md:block"></div>
</div>

<div className="mt-6 flex w-full flex-col gap-6 md:mt-[50px]">
<div className="relative flex items-center justify-center overflow-hidden rounded-lg">
<Image
src={`/project-banners/${
currProject.image ? currProject.image : "fallback.webp"
}`}
alt={`${currProject.name} banner`}
width={1200}
height={630}
className="w-full rounded-t-lg object-cover"
/>
{!currProject?.image && (
<span className="absolute left-1/2 top-1/2 w-full -translate-x-1/2 -translate-y-1/2 px-5 text-center text-3xl font-bold text-black">
{currProject?.imageAlt || currProject?.name}
</span>
)}
</div>
<ProjectTags project={currProject} lang={lang} />
<div className="flex w-full flex-col gap-5 text-base font-normal leading-relaxed">
<Markdown>{tProject("description")}</Markdown>
<div className="flex flex-col w-full gap-6 mt-6 md:mt-10">
<div className="flex flex-col w-full gap-4 text-base font-normal leading-relaxed">
{typeof currProject?.description === "string" && (
<Markdown
components={{
p: ({ node, ...props }) =>
createMarkdownElement("p", {
className:
"text-tuatara-700 font-sans text-lg font-normal",
...props,
}),
}}
>
{projectTranslation("description")}
</Markdown>
)}
<ProjectTags project={currProject} lang={lang} />
</div>
<ProjectExtraLinks project={currProject} lang={lang} />
</div>
</div>
<ProjectExtraLinks project={currProject} lang={lang} />
</div>
<WikiCard
className="lg:sticky lg:top-20"
project={currProject}
lang={lang}
/>
<div className="lg:col-start-2">
<Link
href={editPageURL}
target="_blank"
rel="noreferrer"
passHref
className="inline-flex items-center self-start gap-2 px-4 py-2 duration-200 bg-white border-2 rounded-md group border-tuatara-950 hover:bg-tuatara-950 hover:text-white"
>
<Icons.edit />
<span className="text-sm duration-200 text-tuatara-950 group-hover:text-white">
{t("editThisPage")}
</span>
</Link>
</div>
</div>
</div>
</AppContent>

<DiscoverMoreProjects project={currProject} lang={lang} />
</Divider.Section>
</section>
Expand Down
12 changes: 9 additions & 3 deletions app/i18n/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@
"builtWith": "Built with",
"themes": "Themes selected",
"projectStatus": "Project status",
"fundingSource": "Funding source"
"fundingSource": "Funding source",
"funding": "Funding",
"license": "License",
"projectType": "Project type"
},
"error": {
"404": {
Expand Down Expand Up @@ -83,5 +86,8 @@
"connectWithUsOnPlatform": "Connect with us on {{platform}}",
"addResource": "Add a resource",
"notCurrentlyActive": "Not Currently Active",
"joinOurDiscord": "Join our discord"
}
"joinOurDiscord": "Join our discord",
"prevBrandImage": "Previous branding",
"editThisPage": "Edit this page",
"contents": "Contents"
}
2 changes: 1 addition & 1 deletion app/i18n/locales/en/projects/semaphore.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"description": "Semaphore is a protocol that allows users to prove their membership in a group and transmit anonymous data, such as votes or feedback, without revealing their identities. It is designed for developers aiming to build privacy-preserving applications. Semaphore enables the creation of identities and their corresponding public value, which can be added to Merkle trees. This facilitates the authentication of anonymous user messages through zero-knowledge proofs, where membership is proven using Merkle proofs within the circuit. Key use cases include anonymous voting applications, receiving anonymous feedback from event attendees, and anonymous text messages. It is currently in production and is being used in a wide variety of projects.",
"description": "### Overview\n\n[Semaphore](https://github.com/semaphore-protocol/semaphore/tree/main) is a [zero-knowledge](https://z.cash/learn/what-are-zk-snarks/) protocol that allows you to cast a message (for example, a vote or endorsement) as a provable group member without revealing your identity. Additionally, it provides a simple mechanism to prevent double-signaling. Use cases include private voting, whistleblowing, anonymous DAOs and mixers.\n\nSemaphore is designed to be a simple and generic privacy layer for decentralized applications (dApps) on Ethereum. It encourages modular application design, allowing dApp developers to choose and customize the on-chain and off-chain components they need.\n\nThe core of the protocol is the circuit logic. In addition to circuits, Semaphore provides [Solidity contracts](https://github.com/semaphore-protocol/semaphore/tree/main/packages/contracts) and [JavaScript libraries](https://github.com/semaphore-protocol/semaphore/tree/main#-packages) that allow developers to generate zero-knowledge proofs and verify them with minimal effort.\n\n### Features\n\nWith Semaphore, you can allow your users to do the following:\n\n1. [Create a Semaphore identity](https://docs.semaphore.pse.dev/guides/identities)\n2. [Add their Semaphore identity to a group (i.e. Merkle tree)](https://docs.semaphore.pse.dev/guides/groups)\n3. [Send a verifiable, anonymous message (e.g., a vote or endorsement)](https://docs.semaphore.pse.dev/guides/proofs)\n\nWhen a user broadcasts a message, Semaphore zero-knowledge proofs can ensure that the user has joined the group and hasn't already cast a message with their nullifier.\nSemaphore uses on-chain Solidity contracts and off-chain JavaScript libraries that work in tandem.\n\n* Off chain, JavaScript libraries can be used to create identities, manage groups, and generate proofs.\n* On chain, Solidity contracts can be used to manage groups and verify proofs.",
"tldr": "A zero-knowledge protocol for anonymous interactions."
}
2 changes: 1 addition & 1 deletion app/i18n/locales/en/projects/unirep-protocol.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"description": "UniRep is a zero-knowledge protocol that securely manages user data through anonymous identifiers, enabling trustless interactions and enhanced user privacy in applications. UniRep expands the notion of reputation to include various user data aspects, such as preferences, activity, alignments, and ownership.\n\nUsing anonymous identifiers (epoch keys), the protocol allows for trustless engagement with applications while preserving user privacy. This approach promotes non-custodial applications that don't hold user data, reducing data breach risks and emphasizing security for both users and developers.",
"description": "### Overview\nUniRep is a zero-knowledge protocol that securely manages user data through anonymous identifiers, enabling trustless interactions and enhanced user privacy in applications. UniRep expands the notion of reputation to include various user data aspects, such as preferences, activity, alignments, and ownership.\n\nUsing anonymous identifiers [(epoch keys)](https://developer.unirep.io/docs/protocol/epoch-key) the protocol allows for trustless engagement with applications while preserving user privacy. This approach promotes non-custodial applications that don't hold user data, reducing data breach risks and emphasizing security for both users and developers.\n\nUniRep was originally proposed by BarryWhiteHat in this [ethresear.ch](https://ethresear.ch) post\n\n### Features\n\nUniRep aims to be the ultimate foundation for constructing tailored, yet fully compatible, zero-knowledge (zk) applications. It functions as a powerful memory layer for zk, offering private, non-repudiable data storage and retrieval capabilities. With UniRep, users can effortlessly receive data, prove facts about their information, and store the results while enjoying robust privacy assurances. The protocol empowers developers to create bespoke zk applications without compromising on interoperability and efficiency.\n\nKey UniRep features include:\n\n| | |\n| -------- | ------- |\n| **Data Storage** | Unirep allows small amounts of data to be associated with anonymous users. Applications can conditionally associate data, like requiring a user to prove control of an Ethereum address before attesting to it. |\n| **Extensible Proofs** | The system is designed to be extended with custom application logic. For example, an application might require proof of Ethereum address control to [sign up](https://github.com/Unirep/zketh/blob/b7e0fdf3dcc1b3f97673da20837ed9c7d3e27c9f/packages/circuits/circuits/signupWithAddress.circom). |\n| **Trustless Interoperability** | Applications can interconnect by having users create proofs using publicly available state. |\n| **No Forced Data Sharing** | Unirep applications cannot see what data belongs to what user, unless the user reveals it. User data also cannot be changed unless the user provides the application with an [epoch key](https://developer.unirep.io/docs/protocol/epoch-key). |\n\n### Applications\n\n - Anon Transfer - [Website](https://anon-transfer.online/) | [GitHub](https://github.com/vivianjeng/anon-transfer)\n - Trustlist - [Website](https://trustlist.xyz/) | [GitHub](https://github.com/trustlist/trustlist)\n - Unirep Social TW - [GitHub](https://github.com/social-tw/social-tw-website)\n - Unirep Social - [Website](https://unirep.social/) | [GitHub](https://github.com/Unirep/Unirep-Social)\n - Sacred Protocol - [Website](https://www.sacredprotocol.com/)\n - My-Badge - [GitHub](https://github.com/kittybest/my-badge)\n - Voteathon - [Website](https://voteathon.org/) | [GitHub](https://github.com/NicoSerranoP/voteathon)",
"tldr": "A Zero-Knowledge Protocol built to handle anonymous user data."
}
43 changes: 43 additions & 0 deletions components/app-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client"

import React from "react"
import Link from "next/link"

import { Icons } from "./icons"

interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
children: React.ReactNode
href: string
to?: string
external?: boolean
}

/**
* This component easily manages internal and external links and adds the necessary attributes.
*
* @param {string} href - The URL of the link.
* @param {React.ReactNode} children - The content of the link.
* @param {boolean} external - If the link is external, in this case it will open in a new tab and also add rel="noreferrer noopener nofollow".
*/
export const AppLink = ({
href,
children,
external,
className,
...props
}: LinkProps) => {
return (
<Link
href={href}
target={external ? "_blank" : undefined}
className={`${className} cursor-pointer`}
rel={external ? "noreferrer noopener nofollow" : undefined}
{...props}
>
<div className="flex items-center gap-0.5">
{children}
{external && <Icons.externalPageUrl />}
</div>
</Link>
)
}
Loading
Loading