import { cn, LinkIcon } from "@cv/ui"; import { type PropsWithChildren, useState } from "react"; interface HeadingWithAnchorProps extends PropsWithChildren { level: 1 | 2 | 3 | 4 | 5 | 6; className?: string; } const generateId = (text: string): string => { return text .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/^-|-$/g, ""); }; const copyToClipboard = async (text: string): Promise => { try { await navigator.clipboard.writeText(text); return true; } catch { return false; } }; export const HeadingWithAnchor = ({ children, level, className, }: HeadingWithAnchorProps) => { const [copied, setCopied] = useState(false); // Extract text content from React children recursively const extractText = (node: React.ReactNode): string => { if (typeof node === "string" || typeof node === "number") { return String(node); } if (Array.isArray(node)) { return node.map(extractText).join(""); } if (node && typeof node === "object" && "props" in node) { const props = node.props as { children?: React.ReactNode }; return extractText(props.children); } return ""; }; const textContent = extractText(children); const id = generateId(textContent); const handleCopy = async () => { const url = `${window.location.origin}${window.location.pathname}#${id}`; const success = await copyToClipboard(url); if (success) { setCopied(true); setTimeout(() => { setCopied(false); }, 2000); } }; const HeadingTag: React.ElementType = `h${level}`; const baseClasses = level === 1 ? "text-3xl font-bold mt-8 mb-4 text-ctp-text" : level === 2 ? "text-2xl font-semibold mt-6 mb-3 text-ctp-text" : level === 3 ? "text-xl font-semibold mt-4 mb-2 text-ctp-text" : level === 4 ? "text-lg font-semibold mt-3 mb-2 text-ctp-text" : level === 5 ? "text-base font-semibold mt-2 mb-1 text-ctp-text" : "text-sm font-semibold mt-2 mb-1 text-ctp-text"; return ( {children} ); };