feat: add react-syntax-highlighter and update JSDoc cheatsheet layout

Integrate react-syntax-highlighter for improved code example rendering and enhance the JSDoc cheatsheet layout with a new navigation structure and quick reference section.
This commit is contained in:
Luke Hagar
2025-09-18 02:57:02 +00:00
parent 26a4db0da8
commit 82090541ed
22 changed files with 3421 additions and 889 deletions

103
app/advanced/page.tsx Normal file
View File

@@ -0,0 +1,103 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { BookOpen } from "lucide-react"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
import Header from "@/components/Header"
const advancedData = jsdocData.advanced
export default function AdvancedPage() {
// Generate TOC items from the data
const tocItems = advancedData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{advancedData.title}
</h2>
<p className="text-muted-foreground text-lg">
{advancedData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{advancedData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

104
app/basic-tags/page.tsx Normal file
View File

@@ -0,0 +1,104 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Tag } from "lucide-react"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Navigation from "@/components/Navigation"
import Header from "@/components/Header"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
const basicTagsData = jsdocData.basic
export default function BasicTagsPage() {
// Generate TOC items from the data
const tocItems = basicTagsData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{basicTagsData.title}
</h2>
<p className="text-muted-foreground text-lg">
{basicTagsData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{basicTagsData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

103
app/best-practices/page.tsx Normal file
View File

@@ -0,0 +1,103 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Users } from "lucide-react"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Header from "@/components/Header"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
const bestPracticesData = jsdocData["best-practices"]
export default function BestPracticesPage() {
// Generate TOC items from the data
const tocItems = bestPracticesData.items.map((item, index) => ({
id: item.tag.replace(/[^a-zA-Z0-9]/g, "-").toLowerCase(),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{bestPracticesData.title}
</h2>
<p className="text-muted-foreground text-lg">
{bestPracticesData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{bestPracticesData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

103
app/documentation/page.tsx Normal file
View File

@@ -0,0 +1,103 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Info } from "lucide-react"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Header from "@/components/Header"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
const documentationData = jsdocData.documentation
export default function DocumentationPage() {
// Generate TOC items from the data
const tocItems = documentationData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{documentationData.title}
</h2>
<p className="text-muted-foreground text-lg">
{documentationData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{documentationData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

103
app/examples/page.tsx Normal file
View File

@@ -0,0 +1,103 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Info } from "lucide-react"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Header from "@/components/Header"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
const examplesData = jsdocData.examples
export default function ExamplesPage() {
// Generate TOC items from the data
const tocItems = examplesData.items.map((item, index) => ({
id: item.tag.replace(/[^a-zA-Z0-9]/g, "-").toLowerCase(),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{examplesData.title}
</h2>
<p className="text-muted-foreground text-lg">
{examplesData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{examplesData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

102
app/functions/page.tsx Normal file
View File

@@ -0,0 +1,102 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Header from "@/components/Header"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
const functionsData = jsdocData.functions
export default function FunctionsPage() {
// Generate TOC items from the data
const tocItems = functionsData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{functionsData.title}
</h2>
<p className="text-muted-foreground text-lg">
{functionsData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{functionsData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

103
app/modules/page.tsx Normal file
View File

@@ -0,0 +1,103 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { FileText } from "lucide-react"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Header from "@/components/Header"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
const modulesData = jsdocData.modules
export default function ModulesPage() {
// Generate TOC items from the data
const tocItems = modulesData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{modulesData.title}
</h2>
<p className="text-muted-foreground text-lg">
{modulesData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{modulesData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

102
app/objects/page.tsx Normal file
View File

@@ -0,0 +1,102 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Header from "@/components/Header"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
const objectsData = jsdocData.objects
export default function ObjectsPage() {
// Generate TOC items from the data
const tocItems = objectsData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{objectsData.title}
</h2>
<p className="text-muted-foreground text-lg">
{objectsData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{objectsData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

File diff suppressed because it is too large Load Diff

103
app/parameters/page.tsx Normal file
View File

@@ -0,0 +1,103 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Code } from "lucide-react"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
import Header from "@/components/Header"
const parametersData = jsdocData.parameters
export default function ParametersPage() {
// Generate TOC items from the data
const tocItems = parametersData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{parametersData.title}
</h2>
<p className="text-muted-foreground text-lg">
{parametersData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{parametersData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

View File

@@ -0,0 +1,102 @@
"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import CodeHighlighter from "@/components/SyntaxHighlighter"
import Sidebar from "@/components/Sidebar"
import TableOfContents from "@/components/TableOfContents"
import { jsdocData } from "@/lib/jsdoc-data"
import Header from "@/components/Header"
const typeDefinitionsData = jsdocData.types
export default function TypeDefinitionsPage() {
// Generate TOC items from the data
const tocItems = typeDefinitionsData.items.map((item, index) => ({
id: item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-"),
title: item.tag,
level: 1
}))
return (
<div className="min-h-screen bg-background">
<Header />
<Sidebar />
<TableOfContents items={tocItems} />
<div className="lg:ml-64 xl:mr-72 px-6 py-8">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{typeDefinitionsData.title}
</h2>
<p className="text-muted-foreground text-lg">
{typeDefinitionsData.description}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6">
{typeDefinitionsData.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CodeHighlighter code={item.example} />
</div>
</CardContent>
</Card>
))}
</div>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

139
components/Content.tsx Normal file
View File

@@ -0,0 +1,139 @@
'use client'
import React from 'react'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import CustomSyntaxHighlighter from "@/components/SyntaxHighlighter"
import { ExternalLink } from "lucide-react"
interface Source {
name: string
url: string
description: string
}
interface JSDocItem {
tag: string
syntax: string
example: string
description: string
sources?: Source[]
}
interface JSDocSection {
title: string
description: string
items: JSDocItem[]
}
interface ContentProps {
activeSection: string
jsdocData: Record<string, JSDocSection>
}
export default function Content({ activeSection, jsdocData }: ContentProps) {
const currentSection = jsdocData[activeSection]
return (
<main className="flex-1 min-w-0 ml-60">
<div className="space-y-6">
{/* Kitchen Sink Example */}
{activeSection === 'kitchen-sink' && (
<Card className="border-primary/20 bg-gradient-to-br from-primary/5 to-primary/10 shadow-lg">
<CardHeader>
<CardTitle className="text-2xl text-foreground flex items-center gap-2">
<Badge variant="default" className="bg-primary text-primary-foreground">
Kitchen Sink Example
</Badge>
</CardTitle>
<CardDescription className="text-base">
A comprehensive example showcasing multiple JSDoc features in one code block
</CardDescription>
</CardHeader>
<CardContent>
<CustomSyntaxHighlighter code={currentSection?.items[0]?.example || ''} />
</CardContent>
</Card>
)}
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{currentSection?.title || "Section"}
</h2>
<p className="text-muted-foreground text-lg">
{currentSection?.description || "Documentation section"}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6" id={`section-${activeSection}`}>
{currentSection?.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<CustomSyntaxHighlighter code={item.example} />
</div>
{/* Source Links */}
{item.sources && item.sources.length > 0 && (
<>
<Separator />
<div>
<h4 className="font-semibold text-foreground mb-2">Sources & References:</h4>
<div className="space-y-2">
{item.sources.map((source, sourceIndex) => (
<div key={sourceIndex} className="flex items-start gap-2 p-2 bg-muted/50 rounded-md">
<ExternalLink className="h-4 w-4 text-muted-foreground mt-0.5 flex-shrink-0" />
<div className="flex-1 min-w-0">
<a
href={source.url}
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline font-medium"
>
{source.name}
</a>
<p className="text-sm text-muted-foreground mt-1">{source.description}</p>
</div>
</div>
))}
</div>
</div>
</>
)}
</CardContent>
</Card>
)) || []}
</div>
</div>
</main>
)
}

19
components/Header.tsx Normal file
View File

@@ -0,0 +1,19 @@
"use client"
import { BookOpen } from "lucide-react"
import Link from "next/link"
export default function Header() {
return (
<header className="border-b border-border bg-card/50 backdrop-blur-sm sticky top-0 z-50">
<div className="w-full px-6 py-4">
<div className="flex items-center">
<Link href="/" className="flex items-center gap-2">
<BookOpen className="h-6 w-6 text-primary" />
<h1 className="text-2xl font-bold text-foreground">JSDoc Cheatsheet</h1>
</Link>
</div>
</div>
</header>
)
}

87
components/Sidebar.tsx Normal file
View File

@@ -0,0 +1,87 @@
"use client"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { BookOpen, Code, FileText, Hash, Settings, Tag, Info, Users, Navigation, ChevronRight, Home } from "lucide-react"
import Link from "next/link"
import { usePathname } from "next/navigation"
const navigationItems = [
{ name: "Kitchen Sink", href: "/", icon: Home },
{ name: "Basic Tags", href: "/basic-tags", icon: Tag },
{ name: "Parameters", href: "/parameters", icon: Code },
{ name: "Types", href: "/type-definitions", icon: Hash },
{ name: "Functions", href: "/functions", icon: Settings },
{ name: "Modules", href: "/modules", icon: FileText },
{ name: "Advanced", href: "/advanced", icon: BookOpen },
{ name: "Objects", href: "/objects", icon: Hash },
{ name: "Docs", href: "/documentation", icon: Info },
{ name: "Examples", href: "/examples", icon: Info },
{ name: "Best Practices", href: "/best-practices", icon: Users },
]
export default function Sidebar() {
const pathname = usePathname()
return (
<aside className="w-64 bg-gradient-to-b from-card/95 to-card/90 backdrop-blur-sm border-r border-border/50 fixed left-0 top-16 h-[calc(100vh-4rem)] z-40 overflow-y-auto hidden lg:block shadow-2xl">
<div className="p-6">
<Card className="bg-card/80 border-border/30 shadow-lg backdrop-blur-sm">
<CardHeader className="pb-4 border-b border-border/20">
<CardTitle className="text-base text-foreground flex items-center gap-3 font-semibold">
<div className="p-2 rounded-lg bg-primary/10">
<Navigation className="h-4 w-4 text-primary" />
</div>
<div>
<div>Navigation</div>
<div className="text-xs text-muted-foreground font-normal mt-1">
{navigationItems.length} {navigationItems.length === 1 ? 'section' : 'sections'}
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<nav className="space-y-1 p-4">
{navigationItems.map((item, index) => {
const Icon = item.icon
const isActive = pathname === item.href
return (
<div key={item.href} className="group">
<Link href={item.href}>
<Button
variant="ghost"
size="sm"
className={`w-full justify-start gap-3 text-sm transition-all duration-300 group-hover:translate-x-1 ${
isActive
? "bg-primary text-primary-foreground hover:bg-primary/90 shadow-md"
: "hover:bg-primary/5 text-muted-foreground hover:text-foreground"
} h-10 px-3`}
>
<div className="flex items-center gap-2 flex-1 min-w-0">
{isActive ? (
<div className="w-2 h-2 rounded-full bg-primary-foreground flex-shrink-0" />
) : (
<Icon className="h-3 w-3 flex-shrink-0 text-muted-foreground group-hover:text-foreground transition-colors" />
)}
<span className="truncate font-medium">{item.name}</span>
</div>
{isActive && (
<ChevronRight className="h-3 w-3 flex-shrink-0 animate-pulse" />
)}
</Button>
</Link>
{index < navigationItems.length - 1 && (
<div className="h-px bg-border/30 mx-3 my-1" />
)}
</div>
)
})}
</nav>
</CardContent>
</Card>
</div>
</aside>
)
}

View File

@@ -0,0 +1,46 @@
"use client"
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
interface SyntaxHighlighterProps {
code: string
language?: string
}
const CodeHighlighter = ({ code, language = "javascript" }: SyntaxHighlighterProps) => {
return (
<div className="rounded-lg overflow-hidden border border-slate-700">
<SyntaxHighlighter
language={language}
style={vscDarkPlus}
customStyle={{
background: '#0f172a',
borderRadius: '0.5rem',
fontSize: '0.875rem',
lineHeight: '1.6',
border: 'none',
margin: 0,
padding: '1rem',
}}
codeTagProps={{
style: {
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace',
}
}}
showLineNumbers={false}
wrapLines={true}
wrapLongLines={true}
PreTag={({ children, ...props }) => (
<pre className="!m-0 !p-0" {...props}>
{children}
</pre>
)}
>
{code}
</SyntaxHighlighter>
</div>
)
}
export default CodeHighlighter

View File

@@ -0,0 +1,148 @@
"use client"
import { useState, useEffect } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { List, ChevronRight, Hash } from "lucide-react"
interface TOCItem {
id: string
title: string
level: number
}
interface TableOfContentsProps {
items: TOCItem[]
className?: string
}
export default function TableOfContents({ items, className = "" }: TableOfContentsProps) {
const [activeId, setActiveId] = useState<string>("")
const [isVisible, setIsVisible] = useState(false)
useEffect(() => {
if (items.length === 0) return
// Calculate header height dynamically
const header = document.querySelector('header')
const headerHeight = header ? header.offsetHeight + 20 : 100 // 20px buffer
const rootMargin = `-${headerHeight}px 0% -35% 0%`
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setActiveId(entry.target.id)
}
})
},
{
rootMargin,
threshold: 0.1,
}
)
// Observe all TOC items
items.forEach((item) => {
const element = document.getElementById(item.id)
if (element) {
observer.observe(element)
}
})
return () => {
items.forEach((item) => {
const element = document.getElementById(item.id)
if (element) {
observer.unobserve(element)
}
})
}
}, [items])
useEffect(() => {
// Show TOC if there are items
setIsVisible(items.length > 0)
}, [items])
const scrollToSection = (id: string) => {
const element = document.getElementById(id)
if (element) {
// Get the actual header height dynamically
const header = document.querySelector('header')
const headerHeight = header ? header.offsetHeight + 20 : 100 // 20px buffer
const elementPosition = element.offsetTop - headerHeight
// Add a small delay to ensure smooth scrolling
setTimeout(() => {
window.scrollTo({
top: Math.max(0, elementPosition), // Ensure we don't scroll to negative position
behavior: "smooth"
})
}, 10)
}
}
if (!isVisible) return null
return (
<aside className={`w-72 bg-gradient-to-b from-card/95 to-card/90 backdrop-blur-sm border-l border-border/50 fixed right-0 top-16 h-[calc(100vh-4rem)] z-40 overflow-y-auto hidden xl:block shadow-2xl ${className}`}>
<div className="p-6">
<Card className="bg-card/80 border-border/30 shadow-lg backdrop-blur-sm">
<CardHeader className="pb-4 border-b border-border/20">
<CardTitle className="text-base text-foreground flex items-center gap-3 font-semibold">
<div className="p-2 rounded-lg bg-primary/10">
<List className="h-4 w-4 text-primary" />
</div>
<div>
<div>Table of Contents</div>
<div className="text-xs text-muted-foreground font-normal mt-1">
{items.length} {items.length === 1 ? 'section' : 'sections'}
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<nav className="space-y-1 p-4">
{items.map((item, index) => {
const isActive = activeId === item.id
const indentClass = item.level > 1 ? `ml-${(item.level - 1) * 6}` : ""
return (
<div key={item.id} className="group">
<Button
variant="ghost"
size="sm"
className={`w-full justify-start gap-3 text-sm transition-all duration-300 group-hover:translate-x-1 ${
isActive
? "bg-primary text-primary-foreground hover:bg-primary/90 shadow-md"
: "hover:bg-primary/5 text-muted-foreground hover:text-foreground"
} ${indentClass} h-10 px-3`}
onClick={() => scrollToSection(item.id)}
>
<div className={`flex items-center gap-2 flex-1 min-w-0`}>
{isActive ? (
<div className="w-2 h-2 rounded-full bg-primary-foreground flex-shrink-0" />
) : (
<Hash className="h-3 w-3 flex-shrink-0 text-muted-foreground group-hover:text-foreground transition-colors" />
)}
<span className="truncate font-medium">{item.title}</span>
</div>
{isActive && (
<ChevronRight className="h-3 w-3 flex-shrink-0 animate-pulse" />
)}
</Button>
{index < items.length - 1 && (
<div className="h-px bg-border/30 mx-3 my-1" />
)}
</div>
)
})}
</nav>
</CardContent>
</Card>
</div>
</aside>
)
}

15
lib/data-loader.ts Normal file
View File

@@ -0,0 +1,15 @@
import { jsdocData } from '@/data/jsdoc-data'
import { restoredJSDocData } from '@/data/restored-jsdoc-data'
// Lazy load data for better performance
export const loadSectionData = async (sectionId: string) => {
return jsdocData[sectionId] || jsdocData.basic
}
// Preload critical data - use restored data for now
export const preloadCriticalData = async () => {
return {
...jsdocData,
...restoredJSDocData
}
}

632
lib/jsdoc-data.ts Normal file
View File

@@ -0,0 +1,632 @@
export const jsdocData = {
kitchenSink: {
title: "Kitchen Sink Example",
description: "A comprehensive example showcasing multiple JSDoc features in one code block",
items: [
{
tag: "Complete Example",
syntax: "Complete function documentation",
example: `/**
* Advanced user management service with comprehensive JSDoc documentation
* @module UserService
* @description Handles user creation, authentication, and profile management
* @author Jane Smith <jane@example.com>
* @version 2.1.0
* @since 1.0.0
* @requires Database
* @requires EmailService
* @exports UserService
* @example
* // Initialize the service
* const userService = new UserService(database, emailService);
*
* // Create a new user
* const user = await userService.createUser({
* name: 'John Doe',
* email: 'john@example.com',
* role: 'admin'
* });
*/
/**
* @typedef {Object} UserData
* @property {string} name - Full name of the user
* @property {string} email - Email address (must be unique)
* @property {('admin'|'user'|'guest')} [role='user'] - User role in the system
* @property {number} [age] - User age (optional)
* @property {UserPreferences} [preferences] - User preferences object
*/
/**
* @typedef {Object} UserPreferences
* @property {boolean} emailNotifications - Whether to send email notifications
* @property {string} theme - UI theme preference
* @property {string} language - Preferred language code
*/
/**
* @callback ValidationCallback
* @param {Error|null} error - Validation error if any
* @param {boolean} isValid - Whether the data is valid
*/
/**
* User management service class
* @class UserService
* @implements {EventEmitter}
* @fires UserService#userCreated
* @fires UserService#userDeleted
* @example
* const service = new UserService(db, emailService);
* service.on('userCreated', (user) => {
* console.log('New user created:', user.name);
* });
*/
class UserService extends EventEmitter {
/**
* Creates a new UserService instance
* @constructor
* @param {Database} database - Database connection instance
* @param {EmailService} emailService - Email service for notifications
* @throws {TypeError} When database or emailService is not provided
* @since 1.0.0
*/
constructor(database, emailService) {
super();
if (!database || !emailService) {
throw new TypeError('Database and EmailService are required');
}
this.db = database;
this.emailService = emailService;
}
/**
* Creates a new user in the system
* @async
* @method createUser
* @memberof UserService
* @param {UserData} userData - User information object
* @param {Object} [options={}] - Additional options
* @param {boolean} [options.sendWelcomeEmail=true] - Send welcome email
* @param {boolean} [options.validateEmail=true] - Validate email format
* @returns {Promise<User>} Promise resolving to created user object
* @throws {ValidationError} When user data is invalid
* @throws {DuplicateEmailError} When email already exists
* @throws {DatabaseError} When database operation fails
* @fires UserService#userCreated
* @example
* // Basic user creation
* const user = await userService.createUser({
* name: 'Alice Johnson',
* email: 'alice@example.com'
* });
*
* @example
* // Advanced user creation with options
* const adminUser = await userService.createUser({
* name: 'Bob Admin',
* email: 'bob@example.com',
* role: 'admin',
* preferences: {
* emailNotifications: false,
* theme: 'dark',
* language: 'en'
* }
* }, {
* sendWelcomeEmail: false,
* validateEmail: true
* });
* @since 1.0.0
* @todo Add support for bulk user creation
* @todo Implement user avatar upload
*/
async createUser(userData, options = {}) {
// Implementation here...
/**
* User created event
* @event UserService#userCreated
* @type {Object}
* @property {User} user - The created user object
* @property {Date} timestamp - When the user was created
*/
this.emit('userCreated', { user: newUser, timestamp: new Date() });
return newUser;
}
/**
* Validates user email address
* @static
* @method validateEmail
* @param {string} email - Email address to validate
* @param {ValidationCallback} callback - Callback function for validation result
* @returns {boolean} True if email format is valid
* @example
* // Synchronous validation
* const isValid = UserService.validateEmail('test@example.com');
*
* // Asynchronous validation with callback
* UserService.validateEmail('test@example.com', (error, isValid) => {
* if (error) {
* console.error('Validation error:', error);
* } else {
* console.log('Email is valid:', isValid);
* }
* });
* @since 1.2.0
*/
static validateEmail(email, callback) {
// Implementation here...
}
/**
* @deprecated Since version 2.0.0. Use {@link UserService#createUser} instead.
* @method addUser
* @param {UserData} userData - User data
* @returns {Promise<User>} Created user
* @see {@link UserService#createUser}
*/
async addUser(userData) {
console.warn('addUser is deprecated. Use createUser instead.');
return this.createUser(userData);
}
}
/**
* @namespace UserService.Utils
* @description Utility functions for user management
*/
UserService.Utils = {
/**
* Formats user display name
* @function formatDisplayName
* @memberof UserService.Utils
* @param {string} firstName - User's first name
* @param {string} lastName - User's last name
* @returns {string} Formatted display name
* @example
* const displayName = UserService.Utils.formatDisplayName('John', 'Doe');
* console.log(displayName); // "John D."
*/
formatDisplayName(firstName, lastName) {
return \`\${firstName} \${lastName.charAt(0)}.\`;
}
};
module.exports = UserService;`,
description: "Complete function documentation with all common tags",
},
],
},
basic: {
title: "Basic Tags",
description: "Essential JSDoc tags for documenting your code",
items: [
{
tag: "@description",
syntax: "@description {string} Description text",
example:
"/**\n * @description Calculates the sum of two numbers\n * @param {number} a - First number\n * @param {number} b - Second number\n * @returns {number} The sum\n */\nfunction add(a, b) {\n return a + b;\n}",
description: "Provides a description of the function, class, or variable",
},
{
tag: "@author",
syntax: "@author {string} Author name <email>",
example: "/**\n * @author John Doe <john@example.com>\n * @author Jane Smith <jane@example.com>\n */",
description: "Specifies the author(s) of the code",
},
{
tag: "@version",
syntax: "@version {string} Version number",
example: "/**\n * @version 1.2.0\n * @since 1.0.0\n */",
description: "Indicates the current version of the code",
},
{
tag: "@since",
syntax: "@since {string} Version when added",
example: "/**\n * @since 1.0.0\n * @description Added in the initial release\n */",
description: "Specifies when the feature was first added",
},
{
tag: "@deprecated",
syntax: "@deprecated {string} Deprecation message",
example:
"/**\n * @deprecated Since version 2.0.0. Use newFunction() instead.\n * @see {@link newFunction}\n */\nfunction oldFunction() {\n // deprecated implementation\n}",
description: "Marks code as deprecated with migration guidance",
},
],
},
parameters: {
title: "Parameters & Returns",
description: "Document function parameters, return values, and exceptions",
items: [
{
tag: "@param",
syntax: "@param {type} name Description",
example:
"/**\n * @param {number} x - The first number\n * @param {number} y - The second number\n * @param {Object} [options] - Optional configuration\n * @param {boolean} [options.strict=false] - Use strict mode\n */\nfunction calculate(x, y, options = {}) {\n // implementation\n}",
description: "Documents function parameters with types and descriptions",
},
{
tag: "@returns",
syntax: "@returns {type} Description",
example:
"/**\n * @param {number[]} numbers - Array of numbers\n * @returns {number} The sum of all numbers\n * @returns {null} Returns null if array is empty\n */\nfunction sum(numbers) {\n if (numbers.length === 0) return null;\n return numbers.reduce((a, b) => a + b, 0);\n}",
description: "Documents the return value and its type",
},
{
tag: "@throws",
syntax: "@throws {ErrorType} Description",
example:
"/**\n * @param {string} email - User email address\n * @throws {TypeError} When email is not a string\n * @throws {Error} When email format is invalid\n */\nfunction validateEmail(email) {\n if (typeof email !== 'string') {\n throw new TypeError('Email must be a string');\n }\n if (!email.includes('@')) {\n throw new Error('Invalid email format');\n }\n}",
description: "Documents exceptions that may be thrown",
},
{
tag: "@yields",
syntax: "@yields {type} Description",
example:
"/**\n * @generator\n * @yields {number} The next number in the Fibonacci sequence\n * @returns {Generator<number, void, unknown>}\n */\nfunction* fibonacci() {\n let a = 0, b = 1;\n while (true) {\n yield a;\n [a, b] = [b, a + b];\n }\n}",
description: "Documents what a generator function yields",
},
],
},
types: {
title: "Type Definitions",
description: "Define and document custom types and interfaces",
items: [
{
tag: "@typedef",
syntax: "@typedef {Object} TypeName",
example: "/**\n * @typedef {Object} User\n * @property {string} name\n * @property {number} age\n */",
description: "Defines a custom type",
},
{
tag: "@property",
syntax: "@property {type} name Description",
example: "/**\n * @property {string} email - User email address\n */",
description: "Documents object properties",
},
{
tag: "@enum",
syntax: "@enum {type}",
example: '/**\n * @enum {string}\n */\nconst Status = {\n PENDING: "pending",\n COMPLETE: "complete"\n}',
description: "Documents enumeration values",
},
{
tag: "@type",
syntax: "@type {type}",
example: "/**\n * @type {string|number}\n */\nlet value;",
description: "Specifies the type of a variable",
},
],
},
functions: {
title: "Functions & Classes",
description: "Document functions, classes, constructors, and methods",
items: [
{
tag: "@function",
syntax: "@function",
example: "/**\n * @function calculateTotal\n * @description Calculates order total\n */",
description: "Explicitly marks something as a function",
},
{
tag: "@class",
syntax: "@class",
example: "/**\n * @class\n * @description Represents a user account\n */",
description: "Documents a class",
},
{
tag: "@constructor",
syntax: "@constructor",
example: "/**\n * @constructor\n * @param {string} name - User name\n */",
description: "Documents a constructor function",
},
{
tag: "@method",
syntax: "@method",
example: "/**\n * @method getName\n * @returns {string} The user name\n */",
description: "Documents a method",
},
{
tag: "@static",
syntax: "@static",
example: "/**\n * @static\n * @method createUser\n */",
description: "Indicates a static method or property",
},
{
tag: "@override",
syntax: "@override",
example: "/**\n * @override\n * @method toString\n */",
description: "Indicates method overrides parent method",
},
],
},
modules: {
title: "Modules & Namespaces",
description: "Organize code with modules, namespaces, and membership",
items: [
{
tag: "@module",
syntax: "@module ModuleName",
example: "/**\n * @module UserUtils\n * @description Utilities for user management\n */",
description: "Documents a module",
},
{
tag: "@namespace",
syntax: "@namespace NamespaceName",
example: "/**\n * @namespace MyApp.Utils\n */",
description: "Documents a namespace",
},
{
tag: "@memberof",
syntax: "@memberof ParentName",
example: "/**\n * @memberof MyApp.Utils\n * @function formatName\n */",
description: "Indicates membership in a parent",
},
{
tag: "@exports",
syntax: "@exports ModuleName",
example: "/**\n * @exports UserService\n */",
description: "Documents what a module exports",
},
{
tag: "@requires",
syntax: "@requires ModuleName",
example: "/**\n * @requires lodash\n */",
description: "Documents module dependencies",
},
],
},
advanced: {
title: "Advanced Tags",
description: "Advanced JSDoc features for complex documentation needs",
items: [
{
tag: "@callback",
syntax: "@callback CallbackName",
example: "/**\n * @callback RequestCallback\n * @param {Error} error\n * @param {Object} response\n */",
description: "Documents a callback function type",
},
{
tag: "@event",
syntax: "@event EventName",
example: "/**\n * @event MyClass#dataLoaded\n * @type {Object}\n */",
description: "Documents an event",
},
{
tag: "@fires",
syntax: "@fires EventName",
example: "/**\n * @fires MyClass#dataLoaded\n */",
description: "Indicates function fires an event",
},
{
tag: "@listens",
syntax: "@listens EventName",
example: "/**\n * @listens MyClass#dataLoaded\n */",
description: "Indicates function listens to an event",
},
{
tag: "@mixes",
syntax: "@mixes MixinName",
example: "/**\n * @mixes EventEmitter\n */",
description: "Documents that class mixes in another",
},
{
tag: "@abstract",
syntax: "@abstract",
example: "/**\n * @abstract\n * @method process\n */",
description: "Indicates abstract method or class",
},
],
},
objects: {
title: "Objects & Interfaces",
description: "Document object structures, interfaces, and inheritance",
items: [
{
tag: "@interface",
syntax: "@interface InterfaceName",
example: "/**\n * @interface Drawable\n * @description Interface for drawable objects\n */",
description: "Documents an interface that classes can implement",
},
{
tag: "@implements",
syntax: "@implements {InterfaceName}",
example: "/**\n * @class Circle\n * @implements {Drawable}\n */",
description: "Indicates that a class implements an interface",
},
{
tag: "@extends",
syntax: "@extends ParentClass",
example: "/**\n * @class ColoredCircle\n * @extends Circle\n */",
description: "Documents class inheritance",
},
{
tag: "@mixin",
syntax: "@mixin MixinName",
example: "/**\n * @mixin EventEmitter\n * @description Adds event handling capabilities\n */",
description: "Documents a mixin that can be mixed into classes",
},
],
},
documentation: {
title: "Documentation Tags",
description: "Tags for linking, examples, and additional documentation",
items: [
{
tag: "@example",
syntax: "@example\n// Example code here",
example:
"/**\n * @example\n * // Basic usage\n * const result = myFunction('test');\n * console.log(result);\n */",
description: "Provides usage examples",
},
{
tag: "@see",
syntax: "@see {reference}",
example: "/**\n * @see {@link MyClass#method}\n * @see https://example.com/docs\n */",
description: "References related documentation or code",
},
{
tag: "@link",
syntax: "{@link reference}",
example: "/**\n * Uses {@link MyClass} for processing\n */",
description: "Creates inline links to other documentation",
},
{
tag: "@tutorial",
syntax: "@tutorial TutorialName",
example: "/**\n * @tutorial getting-started\n */",
description: "Links to a tutorial document",
},
{
tag: "@todo",
syntax: "@todo Description of what needs to be done",
example: "/**\n * @todo Add input validation\n * @todo Optimize performance\n */",
description: "Documents future improvements or fixes needed",
},
],
},
examples: {
title: "Complete Examples",
description: "Real-world JSDoc documentation examples",
items: [
{
tag: "Function Example",
syntax: "Complete function documentation",
example: `/**
* Calculates the area of a rectangle
* @function calculateArea
* @param {number} width - The width of the rectangle
* @param {number} height - The height of the rectangle
* @returns {number} The area of the rectangle
* @throws {TypeError} When width or height is not a number
* @example
* // Calculate area of 5x3 rectangle
* const area = calculateArea(5, 3);
* console.log(area); // 15
* @since 1.0.0
* @author Jane Smith <jane@example.com>
*/
function calculateArea(width, height) {
if (typeof width !== 'number' || typeof height !== 'number') {
throw new TypeError('Width and height must be numbers');
}
return width * height;
}`,
description: "Complete function documentation with all common tags",
},
{
tag: "Class Example",
syntax: "Complete class documentation",
example: `/**
* Represents a user in the system
* @class User
* @param {string} name - The user's name
* @param {string} email - The user's email address
* @example
* const user = new User('John Doe', 'john@example.com');
* console.log(user.getName()); // 'John Doe'
*/
class User {
/**
* Create a user
* @constructor
* @param {string} name - The user's name
* @param {string} email - The user's email address
*/
constructor(name, email) {
this.name = name;
this.email = email;
}
/**
* Get the user's name
* @method getName
* @returns {string} The user's name
*/
getName() {
return this.name;
}
}`,
description: "Complete class documentation with constructor and methods",
},
{
tag: "Module Example",
syntax: "Complete module documentation",
example: `/**
* User management module
* @module UserManagement
* @description Handles user creation and deletion
* @requires Database
* @requires EmailService
* @exports createUser
* @exports deleteUser
* @example
* // Create a user
* const user = createUser('John Doe', 'john@example.com');
* console.log(user);
*
* // Delete a user
* deleteUser(user.id);
*/
const Database = require('./Database');
const EmailService = require('./EmailService');
function createUser(name, email) {
// Implementation here
}
function deleteUser(userId) {
// Implementation here
}
module.exports = {
createUser,
deleteUser
};`,
description: "Complete module documentation with dependencies and exports",
},
],
},
"best-practices": {
title: "Best Practices",
description: "Guidelines for writing effective JSDoc documentation",
items: [
{
tag: "Consistency",
syntax: "Use consistent formatting and style",
example:
"// Always use the same format for similar tags\n// Good: @param {string} name - User name\n// Good: @param {number} age - User age",
description: "Maintain consistent formatting across your documentation",
},
{
tag: "Completeness",
syntax: "Document all public APIs",
example: "// Document all parameters, return values, and exceptions\n// Include examples for complex functions",
description: "Ensure all public functions, classes, and modules are documented",
},
{
tag: "Clarity",
syntax: "Write clear, concise descriptions",
example: "// Good: Calculates user age from birth date\n// Bad: Does age stuff",
description: "Use clear, descriptive language that explains purpose and behavior",
},
{
tag: "Type Safety",
syntax: "Always specify types for parameters and returns",
example:
"// Always include types\n@param {string|null} name - User name or null\n@returns {Promise<User>} Promise resolving to user object",
description: "Include detailed type information to improve code reliability",
},
{
tag: "Examples",
syntax: "Include usage examples for complex functions",
example:
"/**\n * @example\n * // Basic usage\n * const result = myFunction('input');\n * \n * @example\n * // Advanced usage\n * const result = myFunction('input', { option: true });\n */",
description: "Provide practical examples showing how to use the code",
},
],
},
}

980
original-page.tsx Normal file
View File

@@ -0,0 +1,980 @@
"use client"
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"
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 highlightCode = (text: string) => {
// Escape HTML first
let highlighted = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;")
// Apply syntax highlighting with proper HTML structure
highlighted = highlighted
// JSDoc comments and tags
.replace(/(\/\*\*[\s\S]*?\*\/)/g, '<span class="text-green-400">$1</span>')
.replace(/(@\w+)/g, '<span class="text-blue-400 font-semibold">$1</span>')
// JavaScript keywords
.replace(
/\b(function|class|const|let|var|if|else|for|while|return|async|await|new|this|super|extends|implements|static|public|private|protected)\b/g,
'<span class="text-purple-400 font-semibold">$1</span>',
)
// Strings
.replace(/(["'`])((?:\\.|(?!\1)[^\\])*?)\1/g, '<span class="text-green-300">$1$2$1</span>')
// Numbers
.replace(/\b(\d+\.?\d*)\b/g, '<span class="text-orange-400">$1</span>')
// Booleans and null/undefined
.replace(/\b(true|false|null|undefined)\b/g, '<span class="text-red-400">$1</span>')
// Types in curly braces
.replace(/\{([^}]+)\}/g, '<span class="text-cyan-300">{<span class="text-cyan-200">$1</span>}</span>')
return highlighted
}
return (
<pre className="bg-slate-900 text-slate-100 p-4 rounded-lg text-sm font-mono overflow-x-auto border border-slate-700 leading-relaxed">
<code dangerouslySetInnerHTML={{ __html: highlightCode(code) }} />
</pre>
)
}
const sections = [
{
id: "kitchen-sink",
title: "Kitchen Sink Example",
icon: BookOpen,
subsections: ["Complete Example"],
},
{
id: "basic",
title: "Basic Tags",
icon: Tag,
subsections: ["@description", "@author", "@version", "@since", "@deprecated"],
},
{
id: "parameters",
title: "Parameters & Returns",
icon: Code,
subsections: ["@param", "@returns", "@throws", "@yields"],
},
{
id: "types",
title: "Type Definitions",
icon: Hash,
subsections: ["@typedef", "@property", "@enum", "@type"],
},
{
id: "functions",
title: "Functions & Classes",
icon: Settings,
subsections: ["@function", "@class", "@constructor", "@method", "@static", "@override"],
},
{
id: "modules",
title: "Modules & Namespaces",
icon: FileText,
subsections: ["@module", "@namespace", "@memberof", "@exports", "@requires"],
},
{
id: "advanced",
title: "Advanced Tags",
icon: BookOpen,
subsections: ["@callback", "@event", "@fires", "@listens", "@mixes", "@abstract"],
},
{
id: "objects",
title: "Objects & Interfaces",
icon: Hash,
subsections: ["@interface", "@implements", "@extends", "@mixin"],
},
{
id: "documentation",
title: "Documentation Tags",
icon: Info,
subsections: ["@example", "@see", "@link", "@tutorial", "@todo"],
},
{
id: "examples",
title: "Complete Examples",
icon: Info,
subsections: ["Function Example", "Class Example", "Module Example"],
},
{
id: "best-practices",
title: "Best Practices",
icon: Users,
subsections: ["Consistency", "Completeness", "Clarity", "Type Safety", "Examples"],
},
]
const jsdocData = {
kitchenSink: {
title: "Kitchen Sink Example",
description: "A comprehensive example showcasing multiple JSDoc features in one code block",
items: [
{
tag: "Complete Example",
syntax: "Complete function documentation",
example: `/**
* Advanced user management service with comprehensive JSDoc documentation
* @module UserService
* @description Handles user creation, authentication, and profile management
* @author Jane Smith <jane@example.com>
* @version 2.1.0
* @since 1.0.0
* @requires Database
* @requires EmailService
* @exports UserService
* @example
* // Initialize the service
* const userService = new UserService(database, emailService);
*
* // Create a new user
* const user = await userService.createUser({
* name: 'John Doe',
* email: 'john@example.com',
* role: 'admin'
* });
*/
/**
* @typedef {Object} UserData
* @property {string} name - Full name of the user
* @property {string} email - Email address (must be unique)
* @property {('admin'|'user'|'guest')} [role='user'] - User role in the system
* @property {number} [age] - User age (optional)
* @property {UserPreferences} [preferences] - User preferences object
*/
/**
* @typedef {Object} UserPreferences
* @property {boolean} emailNotifications - Whether to send email notifications
* @property {string} theme - UI theme preference
* @property {string} language - Preferred language code
*/
/**
* @callback ValidationCallback
* @param {Error|null} error - Validation error if any
* @param {boolean} isValid - Whether the data is valid
*/
/**
* User management service class
* @class UserService
* @implements {EventEmitter}
* @fires UserService#userCreated
* @fires UserService#userDeleted
* @example
* const service = new UserService(db, emailService);
* service.on('userCreated', (user) => {
* console.log('New user created:', user.name);
* });
*/
class UserService extends EventEmitter {
/**
* Creates a new UserService instance
* @constructor
* @param {Database} database - Database connection instance
* @param {EmailService} emailService - Email service for notifications
* @throws {TypeError} When database or emailService is not provided
* @since 1.0.0
*/
constructor(database, emailService) {
super();
if (!database || !emailService) {
throw new TypeError('Database and EmailService are required');
}
this.db = database;
this.emailService = emailService;
}
/**
* Creates a new user in the system
* @async
* @method createUser
* @memberof UserService
* @param {UserData} userData - User information object
* @param {Object} [options={}] - Additional options
* @param {boolean} [options.sendWelcomeEmail=true] - Send welcome email
* @param {boolean} [options.validateEmail=true] - Validate email format
* @returns {Promise<User>} Promise resolving to created user object
* @throws {ValidationError} When user data is invalid
* @throws {DuplicateEmailError} When email already exists
* @throws {DatabaseError} When database operation fails
* @fires UserService#userCreated
* @example
* // Basic user creation
* const user = await userService.createUser({
* name: 'Alice Johnson',
* email: 'alice@example.com'
* });
*
* @example
* // Advanced user creation with options
* const adminUser = await userService.createUser({
* name: 'Bob Admin',
* email: 'bob@example.com',
* role: 'admin',
* preferences: {
* emailNotifications: false,
* theme: 'dark',
* language: 'en'
* }
* }, {
* sendWelcomeEmail: false,
* validateEmail: true
* });
* @since 1.0.0
* @todo Add support for bulk user creation
* @todo Implement user avatar upload
*/
async createUser(userData, options = {}) {
// Implementation here...
/**
* User created event
* @event UserService#userCreated
* @type {Object}
* @property {User} user - The created user object
* @property {Date} timestamp - When the user was created
*/
this.emit('userCreated', { user: newUser, timestamp: new Date() });
return newUser;
}
/**
* Validates user email address
* @static
* @method validateEmail
* @param {string} email - Email address to validate
* @param {ValidationCallback} callback - Callback function for validation result
* @returns {boolean} True if email format is valid
* @example
* // Synchronous validation
* const isValid = UserService.validateEmail('test@example.com');
*
* // Asynchronous validation with callback
* UserService.validateEmail('test@example.com', (error, isValid) => {
* if (error) {
* console.error('Validation error:', error);
* } else {
* console.log('Email is valid:', isValid);
* }
* });
* @since 1.2.0
*/
static validateEmail(email, callback) {
// Implementation here...
}
/**
* @deprecated Since version 2.0.0. Use {@link UserService#createUser} instead.
* @method addUser
* @param {UserData} userData - User data
* @returns {Promise<User>} Created user
* @see {@link UserService#createUser}
*/
async addUser(userData) {
console.warn('addUser is deprecated. Use createUser instead.');
return this.createUser(userData);
}
}
/**
* @namespace UserService.Utils
* @description Utility functions for user management
*/
UserService.Utils = {
/**
* Formats user display name
* @function formatDisplayName
* @memberof UserService.Utils
* @param {string} firstName - User's first name
* @param {string} lastName - User's last name
* @returns {string} Formatted display name
* @example
* const displayName = UserService.Utils.formatDisplayName('John', 'Doe');
* console.log(displayName); // "John D."
*/
formatDisplayName(firstName, lastName) {
return \`\${firstName} \${lastName.charAt(0)}.\`;
}
};
module.exports = UserService;`,
description: "Complete function documentation with all common tags",
},
],
},
basic: {
title: "Basic Tags",
description: "Essential JSDoc tags for documenting your code",
items: [
{
tag: "@description",
syntax: "@description {string} Description text",
example:
"/**\n * @description Calculates the sum of two numbers\n * @param {number} a - First number\n * @param {number} b - Second number\n * @returns {number} The sum\n */\nfunction add(a, b) {\n return a + b;\n}",
description: "Provides a description of the function, class, or variable",
},
{
tag: "@author",
syntax: "@author {string} Author name <email>",
example: "/**\n * @author John Doe <john@example.com>\n * @author Jane Smith <jane@example.com>\n */",
description: "Specifies the author(s) of the code",
},
{
tag: "@version",
syntax: "@version {string} Version number",
example: "/**\n * @version 1.2.0\n * @since 1.0.0\n */",
description: "Indicates the current version of the code",
},
{
tag: "@since",
syntax: "@since {string} Version when added",
example: "/**\n * @since 1.0.0\n * @description Added in the initial release\n */",
description: "Specifies when the feature was first added",
},
{
tag: "@deprecated",
syntax: "@deprecated {string} Deprecation message",
example:
"/**\n * @deprecated Since version 2.0.0. Use newFunction() instead.\n * @see {@link newFunction}\n */\nfunction oldFunction() {\n // deprecated implementation\n}",
description: "Marks code as deprecated with migration guidance",
},
],
},
parameters: {
title: "Parameters & Returns",
description: "Document function parameters, return values, and exceptions",
items: [
{
tag: "@param",
syntax: "@param {type} name Description",
example:
"/**\n * @param {number} x - The first number\n * @param {number} y - The second number\n * @param {Object} [options] - Optional configuration\n * @param {boolean} [options.strict=false] - Use strict mode\n */\nfunction calculate(x, y, options = {}) {\n // implementation\n}",
description: "Documents function parameters with types and descriptions",
},
{
tag: "@returns",
syntax: "@returns {type} Description",
example:
"/**\n * @param {number[]} numbers - Array of numbers\n * @returns {number} The sum of all numbers\n * @returns {null} Returns null if array is empty\n */\nfunction sum(numbers) {\n if (numbers.length === 0) return null;\n return numbers.reduce((a, b) => a + b, 0);\n}",
description: "Documents the return value and its type",
},
{
tag: "@throws",
syntax: "@throws {ErrorType} Description",
example:
"/**\n * @param {string} email - User email address\n * @throws {TypeError} When email is not a string\n * @throws {Error} When email format is invalid\n */\nfunction validateEmail(email) {\n if (typeof email !== 'string') {\n throw new TypeError('Email must be a string');\n }\n if (!email.includes('@')) {\n throw new Error('Invalid email format');\n }\n}",
description: "Documents exceptions that may be thrown",
},
{
tag: "@yields",
syntax: "@yields {type} Description",
example:
"/**\n * @generator\n * @yields {number} The next number in the Fibonacci sequence\n * @returns {Generator<number, void, unknown>}\n */\nfunction* fibonacci() {\n let a = 0, b = 1;\n while (true) {\n yield a;\n [a, b] = [b, a + b];\n }\n}",
description: "Documents what a generator function yields",
},
],
},
types: {
title: "Type Definitions",
description: "Define and document custom types and interfaces",
items: [
{
tag: "@typedef",
syntax: "@typedef {Object} TypeName",
example: "/**\n * @typedef {Object} User\n * @property {string} name\n * @property {number} age\n */",
description: "Defines a custom type",
},
{
tag: "@property",
syntax: "@property {type} name Description",
example: "/**\n * @property {string} email - User email address\n */",
description: "Documents object properties",
},
{
tag: "@enum",
syntax: "@enum {type}",
example: '/**\n * @enum {string}\n */\nconst Status = {\n PENDING: "pending",\n COMPLETE: "complete"\n}',
description: "Documents enumeration values",
},
{
tag: "@type",
syntax: "@type {type}",
example: "/**\n * @type {string|number}\n */\nlet value;",
description: "Specifies the type of a variable",
},
],
},
functions: {
title: "Functions & Classes",
description: "Document functions, classes, constructors, and methods",
items: [
{
tag: "@function",
syntax: "@function",
example: "/**\n * @function calculateTotal\n * @description Calculates order total\n */",
description: "Explicitly marks something as a function",
},
{
tag: "@class",
syntax: "@class",
example: "/**\n * @class\n * @description Represents a user account\n */",
description: "Documents a class",
},
{
tag: "@constructor",
syntax: "@constructor",
example: "/**\n * @constructor\n * @param {string} name - User name\n */",
description: "Documents a constructor function",
},
{
tag: "@method",
syntax: "@method",
example: "/**\n * @method getName\n * @returns {string} The user name\n */",
description: "Documents a method",
},
{
tag: "@static",
syntax: "@static",
example: "/**\n * @static\n * @method createUser\n */",
description: "Indicates a static method or property",
},
{
tag: "@override",
syntax: "@override",
example: "/**\n * @override\n * @method toString\n */",
description: "Indicates method overrides parent method",
},
],
},
modules: {
title: "Modules & Namespaces",
description: "Organize code with modules, namespaces, and membership",
items: [
{
tag: "@module",
syntax: "@module ModuleName",
example: "/**\n * @module UserUtils\n * @description Utilities for user management\n */",
description: "Documents a module",
},
{
tag: "@namespace",
syntax: "@namespace NamespaceName",
example: "/**\n * @namespace MyApp.Utils\n */",
description: "Documents a namespace",
},
{
tag: "@memberof",
syntax: "@memberof ParentName",
example: "/**\n * @memberof MyApp.Utils\n * @function formatName\n */",
description: "Indicates membership in a parent",
},
{
tag: "@exports",
syntax: "@exports ModuleName",
example: "/**\n * @exports UserService\n */",
description: "Documents what a module exports",
},
{
tag: "@requires",
syntax: "@requires ModuleName",
example: "/**\n * @requires lodash\n */",
description: "Documents module dependencies",
},
],
},
advanced: {
title: "Advanced Tags",
description: "Advanced JSDoc features for complex documentation needs",
items: [
{
tag: "@callback",
syntax: "@callback CallbackName",
example: "/**\n * @callback RequestCallback\n * @param {Error} error\n * @param {Object} response\n */",
description: "Documents a callback function type",
},
{
tag: "@event",
syntax: "@event EventName",
example: "/**\n * @event MyClass#dataLoaded\n * @type {Object}\n */",
description: "Documents an event",
},
{
tag: "@fires",
syntax: "@fires EventName",
example: "/**\n * @fires MyClass#dataLoaded\n */",
description: "Indicates function fires an event",
},
{
tag: "@listens",
syntax: "@listens EventName",
example: "/**\n * @listens MyClass#dataLoaded\n */",
description: "Indicates function listens to an event",
},
{
tag: "@mixes",
syntax: "@mixes MixinName",
example: "/**\n * @mixes EventEmitter\n */",
description: "Documents that class mixes in another",
},
{
tag: "@abstract",
syntax: "@abstract",
example: "/**\n * @abstract\n * @method process\n */",
description: "Indicates abstract method or class",
},
],
},
examples: {
title: "Complete Examples",
description: "Real-world JSDoc documentation examples",
items: [
{
tag: "Function Example",
syntax: "Complete function documentation",
example: `/**
* Calculates the area of a rectangle
* @function calculateArea
* @param {number} width - The width of the rectangle
* @param {number} height - The height of the rectangle
* @returns {number} The area of the rectangle
* @throws {TypeError} When width or height is not a number
* @example
* // Calculate area of 5x3 rectangle
* const area = calculateArea(5, 3);
* console.log(area); // 15
* @since 1.0.0
* @author Jane Smith <jane@example.com>
*/
function calculateArea(width, height) {
if (typeof width !== 'number' || typeof height !== 'number') {
throw new TypeError('Width and height must be numbers');
}
return width * height;
}`,
description: "Complete function documentation with all common tags",
},
{
tag: "Class Example",
syntax: "Complete class documentation",
example: `/**
* Represents a user in the system
* @class User
* @param {string} name - The user's name
* @param {string} email - The user's email address
* @example
* const user = new User('John Doe', 'john@example.com');
* console.log(user.getName()); // 'John Doe'
*/
class User {
/**
* Create a user
* @constructor
* @param {string} name - The user's name
* @param {string} email - The user's email address
*/
constructor(name, email) {
this.name = name;
this.email = email;
}
/**
* Get the user's name
* @method getName
* @returns {string} The user's name
*/
getName() {
return this.name;
}
}`,
description: "Complete class documentation with constructor and methods",
},
{
tag: "Module Example",
syntax: "Complete module documentation",
example: `/**
* User management module
* @module UserManagement
* @description Handles user creation and deletion
* @requires Database
* @requires EmailService
* @exports createUser
* @exports deleteUser
* @example
* // Create a user
* const user = createUser('John Doe', 'john@example.com');
* console.log(user);
*
* // Delete a user
* deleteUser(user.id);
*/
const Database = require('./Database');
const EmailService = require('./EmailService');
function createUser(name, email) {
// Implementation here
}
function deleteUser(userId) {
// Implementation here
}
module.exports = {
createUser,
deleteUser
};`,
description: "Complete module documentation with dependencies and exports",
},
],
},
"best-practices": {
title: "Best Practices",
description: "Guidelines for writing effective JSDoc documentation",
items: [
{
tag: "Consistency",
syntax: "Use consistent formatting and style",
example:
"// Always use the same format for similar tags\n// Good: @param {string} name - User name\n// Good: @param {number} age - User age",
description: "Maintain consistent formatting across your documentation",
},
{
tag: "Completeness",
syntax: "Document all public APIs",
example: "// Document all parameters, return values, and exceptions\n// Include examples for complex functions",
description: "Ensure all public functions, classes, and modules are documented",
},
{
tag: "Clarity",
syntax: "Write clear, concise descriptions",
example: "// Good: Calculates user age from birth date\n// Bad: Does age stuff",
description: "Use clear, descriptive language that explains purpose and behavior",
},
{
tag: "Type Safety",
syntax: "Always specify types for parameters and returns",
example:
"// Always include types\n@param {string|null} name - User name or null\n@returns {Promise<User>} Promise resolving to user object",
description: "Include detailed type information to improve code reliability",
},
{
tag: "Examples",
syntax: "Include usage examples for complex functions",
example:
"/**\n * @example\n * // Basic usage\n * const result = myFunction('input');\n * \n * @example\n * // Advanced usage\n * const result = myFunction('input', { option: true });\n */",
description: "Provide practical examples showing how to use the code",
},
],
},
objects: {
title: "Objects & Interfaces",
description: "Document object structures, interfaces, and inheritance",
items: [
{
tag: "@interface",
syntax: "@interface InterfaceName",
example: "/**\n * @interface Drawable\n * @description Interface for drawable objects\n */",
description: "Documents an interface that classes can implement",
},
{
tag: "@implements",
syntax: "@implements {InterfaceName}",
example: "/**\n * @class Circle\n * @implements {Drawable}\n */",
description: "Indicates that a class implements an interface",
},
{
tag: "@extends",
syntax: "@extends ParentClass",
example: "/**\n * @class ColoredCircle\n * @extends Circle\n */",
description: "Documents class inheritance",
},
{
tag: "@mixin",
syntax: "@mixin MixinName",
example: "/**\n * @mixin EventEmitter\n * @description Adds event handling capabilities\n */",
description: "Documents a mixin that can be mixed into classes",
},
],
},
documentation: {
title: "Documentation Tags",
description: "Tags for linking, examples, and additional documentation",
items: [
{
tag: "@example",
syntax: "@example\n// Example code here",
example:
"/**\n * @example\n * // Basic usage\n * const result = myFunction('test');\n * console.log(result);\n */",
description: "Provides usage examples",
},
{
tag: "@see",
syntax: "@see {reference}",
example: "/**\n * @see {@link MyClass#method}\n * @see https://example.com/docs\n */",
description: "References related documentation or code",
},
{
tag: "@link",
syntax: "{@link reference}",
example: "/**\n * Uses {@link MyClass} for processing\n */",
description: "Creates inline links to other documentation",
},
{
tag: "@tutorial",
syntax: "@tutorial TutorialName",
example: "/**\n * @tutorial getting-started\n */",
description: "Links to a tutorial document",
},
{
tag: "@todo",
syntax: "@todo Description of what needs to be done",
example: "/**\n * @todo Add input validation\n * @todo Optimize performance\n */",
description: "Documents future improvements or fixes needed",
},
],
},
}
export default function JSDocCheatsheet() {
const [activeSection, setActiveSection] = useState("kitchen-sink")
const [expandedSections, setExpandedSections] = useState<string[]>(["kitchen-sink"])
const [isScrolling, setIsScrolling] = useState(false)
const toggleSection = (sectionId: string) => {
setExpandedSections((prev) =>
prev.includes(sectionId) ? prev.filter((id) => id !== sectionId) : [...prev, sectionId],
)
}
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 (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="border-b border-border bg-card/50 backdrop-blur-sm sticky top-0 z-50">
<div className="w-full px-6 py-6">
<div className="text-center">
<h1 className="text-4xl font-bold text-foreground mb-2">JSDoc Cheatsheet</h1>
<p className="text-muted-foreground text-lg">Complete Reference for JavaScript Documentation</p>
</div>
</div>
</header>
<div className="w-full px-6 py-8">
<div className="flex gap-8">
{/* Sidebar Navigation */}
<aside className="w-80 shrink-0">
<div className="sticky top-32">
<Card className="bg-sidebar border-sidebar-border shadow-lg">
<CardHeader className="pb-3">
<CardTitle className="text-sidebar-foreground text-lg">Navigation</CardTitle>
</CardHeader>
<CardContent className="p-0">
<ScrollArea className="h-[calc(100vh-200px)]">
<nav className="space-y-1 p-3">
{sections.map((section) => {
const Icon = section.icon
const isExpanded = expandedSections.includes(section.id)
const isActive = activeSection === section.id
return (
<div key={section.id} className="space-y-1">
<Button
variant={isActive ? "secondary" : "ghost"}
className={`w-full justify-between gap-2 transition-all duration-200 ${
isActive
? "bg-sidebar-primary text-sidebar-primary-foreground hover:bg-sidebar-primary/90 shadow-sm"
: "text-sidebar-foreground hover:bg-sidebar-accent/10 hover:text-foreground"
}`}
onClick={() => {
setActiveSection(section.id)
toggleSection(section.id)
const element = document.getElementById(`section-${section.id}`)
if (element) {
setIsScrolling(true)
element.scrollIntoView({ behavior: "smooth", block: "start" })
setTimeout(() => setIsScrolling(false), 1000)
}
}}
>
<div className="flex items-center gap-2">
<Icon className="h-4 w-4" />
{section.title}
</div>
<ChevronRight
className={`h-4 w-4 transition-transform duration-200 ${isExpanded ? "rotate-90" : ""}`}
/>
</Button>
{isExpanded && section.subsections && (
<div className="ml-6 space-y-1 animate-in slide-in-from-left-2 duration-200">
{section.subsections.map((subsection) => (
<Button
key={subsection}
variant="ghost"
size="sm"
className="w-full justify-start text-xs text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/10 transition-all duration-150 hover:translate-x-1"
onClick={() => scrollToTag(subsection)}
>
<span className="truncate">{subsection}</span>
</Button>
))}
</div>
)}
</div>
)
})}
</nav>
</ScrollArea>
</CardContent>
</Card>
</div>
</aside>
{/* Main Content */}
<main className="flex-1 min-w-0">
<div className="space-y-6">
{/* Kitchen Sink Example */}
<Card className="border-primary/20 bg-gradient-to-br from-primary/5 to-primary/10 shadow-lg">
<CardHeader>
<CardTitle className="text-2xl text-foreground flex items-center gap-2">
<Badge variant="default" className="bg-primary text-primary-foreground">
Kitchen Sink Example
</Badge>
</CardTitle>
<CardDescription className="text-base">
A comprehensive example showcasing multiple JSDoc features in one code block
</CardDescription>
</CardHeader>
<CardContent>
<SyntaxHighlighter code={jsdocData.kitchenSink.items[0].example} />
</CardContent>
</Card>
{/* Section Header */}
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-foreground mb-2">
{jsdocData[activeSection as keyof typeof jsdocData]?.title || "Section"}
</h2>
<p className="text-muted-foreground text-lg">
{jsdocData[activeSection as keyof typeof jsdocData]?.description || "Documentation section"}
</p>
</div>
{/* Content Cards */}
<div className="grid gap-6" id={`section-${activeSection}`}>
{jsdocData[activeSection as keyof typeof jsdocData]?.items.map((item, index) => (
<Card
key={index}
id={item.tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")}
className="border-border hover:shadow-lg transition-all duration-300 hover:border-primary/50 hover:shadow-primary/5"
>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-xl text-foreground flex items-center gap-2">
<Badge variant="secondary" className="bg-primary text-primary-foreground font-mono">
{item.tag}
</Badge>
</CardTitle>
</div>
<CardDescription className="text-muted-foreground text-base">{item.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Syntax */}
<div>
<h4 className="font-semibold text-foreground mb-2">Syntax:</h4>
<code className="block bg-muted text-muted-foreground p-3 rounded-md text-sm font-mono border border-border">
{item.syntax}
</code>
</div>
<Separator />
{/* Example with Syntax Highlighting */}
<div>
<h4 className="font-semibold text-foreground mb-2">Example:</h4>
<SyntaxHighlighter code={item.example} />
</div>
</CardContent>
</Card>
)) || []}
</div>
</div>
</main>
</div>
</div>
{/* Footer */}
<footer className="border-t border-border bg-card/50 mt-16">
<div className="w-full px-6 py-8">
<div className="text-center text-muted-foreground">
<p className="mb-2">
For more information, visit the{" "}
<a
href="https://jsdoc.app/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
official JSDoc documentation
</a>
</p>
<p className="text-sm">This cheatsheet covers the most commonly used JSDoc tags and patterns.</p>
</div>
</div>
</footer>
</div>
)
}

View File

@@ -54,6 +54,7 @@
"react-dom": "^18",
"react-hook-form": "^7.60.0",
"react-resizable-panels": "^2.1.7",
"react-syntax-highlighter": "^15.6.6",
"recharts": "2.15.4",
"sonner": "^1.7.4",
"tailwind-merge": "^2.5.5",
@@ -66,6 +67,7 @@
"@types/node": "^22",
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/react-syntax-highlighter": "^15.5.13",
"postcss": "^8.5",
"tailwindcss": "^4.1.9",
"tw-animate-css": "1.3.3",

181
pnpm-lock.yaml generated
View File

@@ -143,6 +143,9 @@ importers:
react-resizable-panels:
specifier: ^2.1.7
version: 2.1.7(react-dom@18.0.0(react@18.0.0))(react@18.0.0)
react-syntax-highlighter:
specifier: ^15.6.6
version: 15.6.6(react@18.0.0)
recharts:
specifier: 2.15.4
version: 2.15.4(react-dom@18.0.0(react@18.0.0))(react@18.0.0)
@@ -174,6 +177,9 @@ importers:
'@types/react-dom':
specifier: ^18
version: 18.0.0
'@types/react-syntax-highlighter':
specifier: ^15.5.13
version: 15.5.13
postcss:
specifier: ^8.5
version: 8.5.0
@@ -1121,6 +1127,9 @@ packages:
'@types/d3-timer@3.0.2':
resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
'@types/hast@2.3.10':
resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==}
'@types/node@22.0.0':
resolution: {integrity: sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==}
@@ -1130,12 +1139,18 @@ packages:
'@types/react-dom@18.0.0':
resolution: {integrity: sha512-49897Y0UiCGmxZqpC8Blrf6meL8QUla6eb+BBhn69dTXlmuOlzkfr7HHY/O8J25e1lTUMs+YYxSlVDAaGHCOLg==}
'@types/react-syntax-highlighter@15.5.13':
resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==}
'@types/react@18.0.0':
resolution: {integrity: sha512-7+K7zEQYu7NzOwQGLR91KwWXXDzmTFODRVizJyIALf6RfLv2GDpqpknX64pvRVILXCpXi7O/pua8NGk44dLvJw==}
'@types/scheduler@0.26.0':
resolution: {integrity: sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==}
'@types/unist@2.0.11':
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
'@vercel/analytics@1.5.0':
resolution: {integrity: sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==}
peerDependencies:
@@ -1189,6 +1204,15 @@ packages:
caniuse-lite@1.0.30001743:
resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==}
character-entities-legacy@1.1.4:
resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==}
character-entities@1.2.4:
resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==}
character-reference-invalid@1.1.4:
resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==}
chownr@3.0.0:
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'}
@@ -1209,6 +1233,9 @@ packages:
react: ^18 || ^19 || ^19.0.0-rc
react-dom: ^18 || ^19 || ^19.0.0-rc
comma-separated-tokens@1.0.8:
resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==}
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -1306,6 +1333,13 @@ packages:
resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==}
engines: {node: '>=6.0.0'}
fault@1.0.4:
resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==}
format@0.2.2:
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
engines: {node: '>=0.4.x'}
fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
@@ -1321,6 +1355,18 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
hast-util-parse-selector@2.2.5:
resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
hastscript@6.0.0:
resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
highlight.js@10.7.3:
resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
highlightjs-vue@1.0.0:
resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==}
input-otp@1.4.1:
resolution: {integrity: sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==}
peerDependencies:
@@ -1331,6 +1377,18 @@ packages:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
is-alphabetical@1.0.4:
resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==}
is-alphanumerical@1.0.4:
resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==}
is-decimal@1.0.4:
resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==}
is-hexadecimal@1.0.4:
resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==}
jiti@2.5.1:
resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
hasBin: true
@@ -1409,6 +1467,9 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
lowlight@1.20.0:
resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==}
lucide-react@0.454.0:
resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==}
peerDependencies:
@@ -1470,6 +1531,9 @@ packages:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
parse-entities@2.0.0:
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -1484,9 +1548,20 @@ packages:
resolution: {integrity: sha512-27VKOqrYfPncKA2NrFOVhP5MGAfHKLYn/Q0mz9cNQyRAKYi3VNHwYU2qKKqPCqgBmeeJ0uAFB56NumXZ5ZReXg==}
engines: {node: ^10 || ^12 || >=14}
prismjs@1.27.0:
resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==}
engines: {node: '>=6'}
prismjs@1.30.0:
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
engines: {node: '>=6'}
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
property-information@5.6.0:
resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==}
react-day-picker@9.8.0:
resolution: {integrity: sha512-E0yhhg7R+pdgbl/2toTb0xBhsEAtmAx1l7qjIWYfcxOy8w4rTSVfbtBoSzVVhPwKP/5E9iL38LivzoE3AQDhCQ==}
engines: {node: '>=18'}
@@ -1552,6 +1627,11 @@ packages:
'@types/react':
optional: true
react-syntax-highlighter@15.6.6:
resolution: {integrity: sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw==}
peerDependencies:
react: '>= 0.14.0'
react-transition-group@4.4.5:
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
peerDependencies:
@@ -1572,6 +1652,9 @@ packages:
react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
refractor@3.6.0:
resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==}
scheduler@0.21.0:
resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==}
@@ -1585,6 +1668,9 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
space-separated-tokens@1.1.5:
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
@@ -1678,6 +1764,10 @@ packages:
victory-vendor@36.9.2:
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
yallist@5.0.0:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
@@ -2593,6 +2683,10 @@ snapshots:
'@types/d3-timer@3.0.2': {}
'@types/hast@2.3.10':
dependencies:
'@types/unist': 2.0.11
'@types/node@22.0.0':
dependencies:
undici-types: 6.11.1
@@ -2603,6 +2697,10 @@ snapshots:
dependencies:
'@types/react': 18.0.0
'@types/react-syntax-highlighter@15.5.13':
dependencies:
'@types/react': 18.0.0
'@types/react@18.0.0':
dependencies:
'@types/prop-types': 15.7.15
@@ -2611,6 +2709,8 @@ snapshots:
'@types/scheduler@0.26.0': {}
'@types/unist@2.0.11': {}
'@vercel/analytics@1.5.0(next@14.2.16(react-dom@18.0.0(react@18.0.0))(react@18.0.0))(react@18.0.0)':
optionalDependencies:
next: 14.2.16(react-dom@18.0.0(react@18.0.0))(react@18.0.0)
@@ -2646,6 +2746,12 @@ snapshots:
caniuse-lite@1.0.30001743: {}
character-entities-legacy@1.1.4: {}
character-entities@1.2.4: {}
character-reference-invalid@1.1.4: {}
chownr@3.0.0: {}
class-variance-authority@0.7.1:
@@ -2668,6 +2774,8 @@ snapshots:
- '@types/react'
- '@types/react-dom'
comma-separated-tokens@1.0.8: {}
csstype@3.1.3: {}
d3-array@3.2.4:
@@ -2748,6 +2856,12 @@ snapshots:
fast-equals@5.2.2: {}
fault@1.0.4:
dependencies:
format: 0.2.2
format@0.2.2: {}
fraction.js@4.3.7: {}
geist@1.5.1(next@14.2.16(react-dom@18.0.0(react@18.0.0))(react@18.0.0)):
@@ -2758,6 +2872,20 @@ snapshots:
graceful-fs@4.2.11: {}
hast-util-parse-selector@2.2.5: {}
hastscript@6.0.0:
dependencies:
'@types/hast': 2.3.10
comma-separated-tokens: 1.0.8
hast-util-parse-selector: 2.2.5
property-information: 5.6.0
space-separated-tokens: 1.1.5
highlight.js@10.7.3: {}
highlightjs-vue@1.0.0: {}
input-otp@1.4.1(react-dom@18.0.0(react@18.0.0))(react@18.0.0):
dependencies:
react: 18.0.0
@@ -2765,6 +2893,17 @@ snapshots:
internmap@2.0.3: {}
is-alphabetical@1.0.4: {}
is-alphanumerical@1.0.4:
dependencies:
is-alphabetical: 1.0.4
is-decimal: 1.0.4
is-decimal@1.0.4: {}
is-hexadecimal@1.0.4: {}
jiti@2.5.1: {}
js-tokens@4.0.0: {}
@@ -2820,6 +2959,11 @@ snapshots:
dependencies:
js-tokens: 4.0.0
lowlight@1.20.0:
dependencies:
fault: 1.0.4
highlight.js: 10.7.3
lucide-react@0.454.0(react@18.0.0):
dependencies:
react: 18.0.0
@@ -2874,6 +3018,15 @@ snapshots:
object-assign@4.1.1: {}
parse-entities@2.0.0:
dependencies:
character-entities: 1.2.4
character-entities-legacy: 1.1.4
character-reference-invalid: 1.1.4
is-alphanumerical: 1.0.4
is-decimal: 1.0.4
is-hexadecimal: 1.0.4
picocolors@1.1.1: {}
postcss-value-parser@4.2.0: {}
@@ -2890,12 +3043,20 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
prismjs@1.27.0: {}
prismjs@1.30.0: {}
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
react-is: 16.13.1
property-information@5.6.0:
dependencies:
xtend: 4.0.2
react-day-picker@9.8.0(react@18.0.0):
dependencies:
'@date-fns/tz': 1.2.0
@@ -2957,6 +3118,16 @@ snapshots:
optionalDependencies:
'@types/react': 18.0.0
react-syntax-highlighter@15.6.6(react@18.0.0):
dependencies:
'@babel/runtime': 7.28.4
highlight.js: 10.7.3
highlightjs-vue: 1.0.0
lowlight: 1.20.0
prismjs: 1.30.0
react: 18.0.0
refractor: 3.6.0
react-transition-group@4.4.5(react-dom@18.0.0(react@18.0.0))(react@18.0.0):
dependencies:
'@babel/runtime': 7.28.4
@@ -2987,6 +3158,12 @@ snapshots:
tiny-invariant: 1.3.3
victory-vendor: 36.9.2
refractor@3.6.0:
dependencies:
hastscript: 6.0.0
parse-entities: 2.0.0
prismjs: 1.27.0
scheduler@0.21.0:
dependencies:
loose-envify: 1.4.0
@@ -2998,6 +3175,8 @@ snapshots:
source-map-js@1.2.1: {}
space-separated-tokens@1.1.5: {}
streamsearch@1.1.0: {}
styled-jsx@5.1.1(react@18.0.0):
@@ -3085,6 +3264,8 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
xtend@4.0.2: {}
yallist@5.0.0: {}
zod@3.25.67: {}

2
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,2 @@
onlyBuiltDependencies:
- '@tailwindcss/oxide'