mirror of
https://github.com/privacy-scaling-explorations/pse.dev.git
synced 2026-04-23 03:01:03 -04:00
side navbar contents
This commit is contained in:
@@ -60,6 +60,7 @@ export const ProjectContent = ({
|
||||
{content?.description?.length > 0 && (
|
||||
<WikiSideNavigation
|
||||
className="hidden lg:block"
|
||||
project={project}
|
||||
content={content?.description}
|
||||
/>
|
||||
)}
|
||||
@@ -186,7 +187,7 @@ export const ProjectContent = ({
|
||||
project={project}
|
||||
lang={lang}
|
||||
/>
|
||||
<div className="lg:col-start-2">
|
||||
<div data-section-id="edit-this-page" className="lg:col-start-2">
|
||||
<Link
|
||||
href={editPageURL}
|
||||
target="_blank"
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"learnMore": "Learn more",
|
||||
"learnMoreDiscord": "Join our Discord to learn more about our programs and other educational opportunities!",
|
||||
"buildWithThisTool": "Build with this tool",
|
||||
"buildWith": "Build with",
|
||||
"deepDiveResearch": "Dive deeper into the research",
|
||||
"searchProjectPlaceholder": "Search project title or keyword",
|
||||
"close": "Close",
|
||||
|
||||
@@ -20,8 +20,8 @@ interface TagsProps extends HtmlHTMLAttributes<HTMLDivElement> {
|
||||
|
||||
const TagsWrapper = ({ label, children }: TagsProps) => {
|
||||
return (
|
||||
<div className="flex flex-col items-start md:gap-2">
|
||||
<h3 className="py-2 text-[22px] font-bold text-tuatara-700">{label}</h3>
|
||||
<div className="flex flex-col items-start gap-2">
|
||||
<h3 className="text-[22px] font-bold text-tuatara-700">{label}</h3>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -63,9 +63,9 @@ export default function ProjectExtraLinks({
|
||||
if (!links.length) return null // no links hide the section
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-col gap-2" data-section-id={id}>
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="py-2 text-[22px] font-bold text-tuatara-700">{label}</p>
|
||||
<p className="text-[22px] font-bold text-tuatara-700">{label}</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-start gap-2">
|
||||
{links.map((link: ActionLinkTypeLink, index) => {
|
||||
@@ -89,7 +89,7 @@ export default function ProjectExtraLinks({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-8 py-4">
|
||||
<div className="flex flex-col gap-8">
|
||||
{Object.entries(ExtraLinkLabelMapping).map(([key]) => {
|
||||
const links = extraLinks[key as ProjectExtraLinkType] ?? []
|
||||
return (
|
||||
|
||||
@@ -2,12 +2,24 @@ import React from "react"
|
||||
import ReactMarkdown, { Components } from "react-markdown"
|
||||
import remarkGfm from "remark-gfm"
|
||||
|
||||
const generateSectionId = (text: string) => {
|
||||
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-")
|
||||
}
|
||||
|
||||
export const createMarkdownElement = (
|
||||
tag: keyof JSX.IntrinsicElements,
|
||||
props: any
|
||||
) =>
|
||||
React.createElement(tag, {
|
||||
...props,
|
||||
ref: (node: HTMLElement | null) => {
|
||||
if (node && node.textContent) {
|
||||
node.setAttribute(
|
||||
"data-section-id",
|
||||
generateSectionId(node.textContent)
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const Table = (props: any) => {
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
|
||||
import { ProjectExtraLinkType } from "@/lib/types"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useTranslation } from "@/app/i18n/client"
|
||||
|
||||
import { Icons } from "./icons"
|
||||
|
||||
interface Section {
|
||||
level: number
|
||||
text: string
|
||||
@@ -15,12 +18,14 @@ interface WikiSideNavigationProps {
|
||||
className?: string
|
||||
lang?: string
|
||||
content?: string
|
||||
project?: any
|
||||
}
|
||||
|
||||
export const WikiSideNavigation = ({
|
||||
className,
|
||||
lang = "en",
|
||||
content = "",
|
||||
project,
|
||||
}: WikiSideNavigationProps) => {
|
||||
const { t } = useTranslation(lang, "common")
|
||||
const [sections, setSections] = useState<Section[]>([])
|
||||
@@ -46,6 +51,10 @@ export const WikiSideNavigation = ({
|
||||
}
|
||||
|
||||
setSections(extractedSections)
|
||||
// Set the first section as active by default
|
||||
if (extractedSections.length > 0) {
|
||||
setActiveSection(extractedSections[0].id)
|
||||
}
|
||||
}, [content])
|
||||
|
||||
// Set up intersection observer
|
||||
@@ -59,7 +68,7 @@ export const WikiSideNavigation = ({
|
||||
observerRef.current = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
setActiveSection(entry.target.id)
|
||||
setActiveSection(entry.target.getAttribute("data-section-id"))
|
||||
}
|
||||
})
|
||||
}, observerOptions)
|
||||
@@ -89,9 +98,37 @@ export const WikiSideNavigation = ({
|
||||
top: offsetPosition,
|
||||
behavior: "smooth",
|
||||
})
|
||||
setActiveSection(sectionId)
|
||||
}
|
||||
}
|
||||
|
||||
const ExtraLinkLabelMapping: Record<
|
||||
ProjectExtraLinkType,
|
||||
{
|
||||
label: string
|
||||
icon?: any
|
||||
}
|
||||
> = {
|
||||
buildWith: {
|
||||
label: t("buildWith"),
|
||||
icon: <Icons.hammer />,
|
||||
},
|
||||
play: {
|
||||
label: t("tryItOut"),
|
||||
icon: <Icons.hand />,
|
||||
},
|
||||
research: {
|
||||
label: t("deepDiveResearch"),
|
||||
icon: <Icons.readme />,
|
||||
},
|
||||
learn: {
|
||||
label: t("learnMore"),
|
||||
},
|
||||
}
|
||||
|
||||
const { extraLinks = {} } = project
|
||||
const hasExtraLinks = Object.keys(extraLinks).length > 0
|
||||
|
||||
if (sections.length === 0 || content.length === 0) return null
|
||||
|
||||
return (
|
||||
@@ -105,7 +142,7 @@ export const WikiSideNavigation = ({
|
||||
<li
|
||||
key={index}
|
||||
className={cn(
|
||||
"flex h-8 items-center border-l-2 border-l-anakiwa-200 px-3 duration-200",
|
||||
"flex h-8 items-center border-l-2 border-l-anakiwa-200 px-3 duration-200 cursor-pointer",
|
||||
{
|
||||
"border-l-anakiwa-500 text-anakiwa-500 font-medium":
|
||||
activeSection === section.id,
|
||||
@@ -120,6 +157,40 @@ export const WikiSideNavigation = ({
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
{Object.entries(ExtraLinkLabelMapping).map(([key]) => {
|
||||
const links = extraLinks[key as ProjectExtraLinkType] ?? []
|
||||
// @ts-ignore
|
||||
const { label } = ExtraLinkLabelMapping?.[key as any] ?? {}
|
||||
if (!links.length) return null // no links hide the section
|
||||
return (
|
||||
<li
|
||||
key={key}
|
||||
onClick={() => scrollToSection(key)}
|
||||
className={cn(
|
||||
"flex h-8 items-center border-l-2 border-l-anakiwa-200 px-3 duration-200 cursor-pointer",
|
||||
{
|
||||
"border-l-anakiwa-500 text-anakiwa-500 font-medium":
|
||||
activeSection === key,
|
||||
}
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
<li
|
||||
key="edit"
|
||||
onClick={() => scrollToSection("edit-this-page")}
|
||||
className={cn(
|
||||
"flex h-8 items-center border-l-2 border-l-anakiwa-200 px-3 duration-200 cursor-pointer",
|
||||
{
|
||||
"border-l-anakiwa-500 text-anakiwa-500 font-medium":
|
||||
activeSection === "edit-this-page",
|
||||
}
|
||||
)}
|
||||
>
|
||||
Edit this page
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,6 @@ import { discreetly } from "./projects/discreetly"
|
||||
import { dslWorkingGroup } from "./projects/dsl-working-group"
|
||||
import { ECIPHalo2 } from "./projects/ecip-halo2"
|
||||
import { eigenTrust } from "./projects/eigen-trust"
|
||||
import { example } from "./projects/example"
|
||||
import { Interep } from "./projects/interep"
|
||||
import { jubmoji } from "./projects/jubmoji"
|
||||
import { maci } from "./projects/maci"
|
||||
@@ -47,7 +46,6 @@ import { zkp2p } from "./projects/zkp2p"
|
||||
* Every 'description' props supports markdown syntax https://www.markdownguide.org/basic-syntax/
|
||||
*/
|
||||
export const projects: ProjectInterface[] = [
|
||||
example,
|
||||
rln,
|
||||
zkitter,
|
||||
maci,
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { ProjectInterface, ProjectStatus } from "@/lib/types"
|
||||
|
||||
export const example: ProjectInterface = {
|
||||
id: "project_name",
|
||||
image: "",
|
||||
section: "pse",
|
||||
projectStatus: ProjectStatus.ACTIVE,
|
||||
name: "This is an example of the project",
|
||||
content: {
|
||||
en: {
|
||||
tldr: "Short description",
|
||||
description: `
|
||||
## Heading
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
`,
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
keywords: [],
|
||||
themes: [],
|
||||
types: [],
|
||||
builtWith: [],
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user