diff --git a/app/page.tsx b/app/page.tsx index af3a694..5fc4d73 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useState, useEffect } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" @@ -8,6 +8,43 @@ import { ScrollArea } from "@/components/ui/scroll-area" import { Separator } from "@/components/ui/separator" import { BookOpen, Code, FileText, Hash, Info, Settings, Tag, Users, ChevronRight } from "lucide-react" +const SyntaxHighlighter = ({ code, language = "javascript" }: { code: string; language?: string }) => { + const [highlightedCode, setHighlightedCode] = useState(code) + + useEffect(() => { + // Simple syntax highlighting for JavaScript/JSDoc + const highlight = (text: string) => { + return ( + text + // JSDoc tags + .replace(/(@\w+)/g, '$1') + // Comments + .replace(/(\/\*\*[\s\S]*?\*\/)/g, '$1') + .replace(/(\/\/.*$)/gm, '$1') + // Strings + .replace(/(['"`])((?:(?!\1)[^\\]|\\.)*)(\1)/g, '$1$2$3') + // Keywords + .replace( + /\b(function|class|const|let|var|if|else|for|while|return|new|this|typeof|instanceof)\b/g, + '$1', + ) + // Types in curly braces + .replace(/\{([^}]+)\}/g, '{$1}') + // Numbers + .replace(/\b(\d+\.?\d*)\b/g, '$1') + ) + } + + setHighlightedCode(highlight(code)) + }, [code]) + + return ( +
+      
+    
+ ) +} + const sections = [ { id: "basic", @@ -499,6 +536,7 @@ module.exports = { export default function JSDocCheatsheet() { const [activeSection, setActiveSection] = useState("basic") const [expandedSections, setExpandedSections] = useState(["basic"]) + const [isScrolling, setIsScrolling] = useState(false) const toggleSection = (sectionId: string) => { setExpandedSections((prev) => @@ -509,10 +547,43 @@ export default function JSDocCheatsheet() { const scrollToTag = (tag: string) => { const element = document.getElementById(tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")) if (element) { + setIsScrolling(true) element.scrollIntoView({ behavior: "smooth", block: "start" }) + + // Reset scrolling state after animation + setTimeout(() => setIsScrolling(false), 1000) + + // Highlight the element briefly + element.classList.add("ring-2", "ring-primary", "ring-opacity-50") + setTimeout(() => { + element.classList.remove("ring-2", "ring-primary", "ring-opacity-50") + }, 2000) } } + useEffect(() => { + const handleScroll = () => { + if (isScrolling) return // Don't update during programmatic scrolling + + const sections = Object.keys(jsdocData) + const scrollPosition = window.scrollY + 200 + + for (const sectionId of sections) { + const element = document.getElementById(`section-${sectionId}`) + if (element) { + const { offsetTop, offsetHeight } = element + if (scrollPosition >= offsetTop && scrollPosition < offsetTop + offsetHeight) { + setActiveSection(sectionId) + break + } + } + } + } + + window.addEventListener("scroll", handleScroll) + return () => window.removeEventListener("scroll", handleScroll) + }, [isScrolling]) + return (
{/* Header */} @@ -530,7 +601,7 @@ export default function JSDocCheatsheet() { {/* Sidebar Navigation */}