"use client" import { Icons } from "./icons" import { LABELS } from "@/app/labels" import { useGetProjectRelatedArticles } from "@/hooks/useGetProjectRelatedArticles" import { ProjectExtraLinkType } from "@/lib/types" import { cn } from "@/lib/utils" import { useEffect, useRef, useState } from "react" interface Section { level: number text: string id: string } interface WikiSideNavigationProps { className?: string content?: string project?: any } const SideNavigationItem = ({ text, id, activeSection, onClick, }: { text: string id: string activeSection: string | null onClick: () => void }) => { return (
  • ) } export const WikiSideNavigation = ({ className, content = "", project, }: WikiSideNavigationProps) => { const [sections, setSections] = useState([]) const [activeSection, setActiveSection] = useState(null) const observerRef = useRef(null) const { articles, loading } = useGetProjectRelatedArticles({ projectId: project.id, }) useEffect(() => { if (!content) return const sectionsRegex = /^(#{1,3})\s(.+)/gm const extractedSections: Section[] = [] let match while ((match = sectionsRegex.exec(content)) !== null) { const text = match[2] if (!extractedSections.some((section) => section.text === text)) { extractedSections.push({ level: match[1].length, text, id: text.toLowerCase().replace(/[^a-z0-9]+/g, "-"), }) } } setSections(extractedSections) if (extractedSections.length > 0) { setActiveSection(extractedSections[0].id) } }, [content]) // Set up intersection observer useEffect(() => { const observerOptions = { root: null, rootMargin: "-20% 0px -80% 0px", threshold: 0, } observerRef.current = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setActiveSection(entry.target.getAttribute("data-section-id")) } }) }, observerOptions) sections.forEach((section) => { const element = document.querySelector( `[data-section-id="${section.id}"]` ) if (element) observerRef.current?.observe(element) }) return () => { if (observerRef.current) { observerRef.current.disconnect() } } }, [sections, loading]) const scrollToSection = (sectionId: string) => { const element = document.querySelector(`[data-section-id="${sectionId}"]`) if (element) { const offset = 80 // Adjust this value based on your header height const elementPosition = element.getBoundingClientRect().top const offsetPosition = elementPosition + window.scrollY - offset window.scrollTo({ top: offsetPosition, behavior: "smooth", }) setActiveSection(sectionId) } } const ExtraLinkLabelMapping: Record< ProjectExtraLinkType, { label: string icon?: any } > = { buildWith: { label: LABELS.COMMON.BUILD_WITH, icon: , }, play: { label: LABELS.COMMON.TRY_IT_OUT, icon: , }, research: { label: LABELS.COMMON.DEEP_DIVE_RESEARCH, icon: , }, learn: { label: LABELS.COMMON.LEARN_MORE, }, } const { extraLinks = {}, team = [], youtubeLinks = [] } = project const hasRelatedArticles = articles.length > 0 && !loading const hasTeam = Array.isArray(team) && team.length > 0 const hasYoutubeVideos = Array.isArray(youtubeLinks) && youtubeLinks.length > 0 if (sections.length === 0 || content.length === 0) return null return (
    ) }