import { useState, useCallback } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import rehypeHighlight from 'rehype-highlight'; import rehypeSlug from 'rehype-slug'; import rehypeAutolinkHeadings from 'rehype-autolink-headings'; import GithubSlugger from 'github-slugger'; import { Copy, Check, BookOpen, Hash, User, Terminal } from 'lucide-react'; import { CategoryBadge } from '@/components/CategoryBadge'; import { Footer } from '@/components/Footer'; import { Button } from '@/components/ui/button'; import { ScrollArea } from '@/components/ui/scroll-area'; import { cn } from '@/lib/utils'; import { Skill } from '@/types/skills'; export interface TocItem { id: string; text: string; level: number; } export function extractToc(content: string): TocItem[] { const toc: TocItem[] = []; const slugger = new GithubSlugger(); const headingRegex = /^(#{1,6})\s+(.+)$/gm; let match; while ((match = headingRegex.exec(content)) !== null) { const level = match[1].length; const text = match[2].trim(); const id = slugger.slug(text); toc.push({ id, text, level }); } return toc; } interface SkillViewerProps { skill: Skill | null; content: string | null; isLoading: boolean; } function useCopyText(text: string) { const [copied, setCopied] = useState(false); const copy = useCallback(async () => { if (!text) return; try { await navigator.clipboard.writeText(text); } catch { const textarea = document.createElement('textarea'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); } setCopied(true); setTimeout(() => setCopied(false), 2000); }, [text]); return { copied, copy }; } function CopyCodeButton({ text }: { text: string }) { const { copied, copy } = useCopyText(text); return ( ); } function CopySkillContentButton({ text }: { text: string }) { const { copied, copy } = useCopyText(text); return ( ); } export function SkillViewer({ skill, content, isLoading }: SkillViewerProps) { if (!skill) { return (

Select a skill

Pick any skill from the catalog to read documentation, usage hints, and examples.

); } if (isLoading) { return (
loading skill…
); } return (
{(skill.metadata.version || skill.metadata.author) && (
{skill.metadata.version && ( {skill.metadata.version} )} {skill.metadata.author && ( {skill.metadata.author} )}
)}

{skill.name}

{skill.description}

{(skill.keywords.length > 0 || skill.argumentHint) && (
{skill.keywords.slice(0, 4).map((keyword) => ( {keyword} ))} {skill.keywords.length > 4 && ( +{skill.keywords.length - 4} )} {skill.argumentHint && ( {skill.argumentHint} )}
)}
{content ? ( (
                      {children}
                    
), a: ({ children, href, ...props }) => ( {children} ), table: ({ children, ...props }) => (
{children}
), th: ({ children, ...props }) => ( {children} ), td: ({ children, ...props }) => ( {children} ), blockquote: ({ children, ...props }) => (
{children}
), }} > {content}
) : (

No content available

)}