"use client"; import Link from "next/link"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { useEffect, useMemo, useRef, useState } from "react"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism"; import { Badge, Card, Typography } from "poyraz-ui/atoms"; import type { BlogDetail } from "@/data/blog-detail"; import { BlogToc } from "@/components/blog-toc"; import { GiscusComments } from "@/components/giscus-comments"; type BlogDetailContentProps = { post: BlogDetail; }; function slugify(text: string) { return text .toLowerCase() .replace(/\*\*/g, "") .replace(/\*/g, "") .replace(/[^a-zçğıöşü0-9\s-]/g, "") .replace(/\s+/g, "-") .replace(/-+/g, "-") .replace(/^-|-$/g, ""); } function extractText(children: React.ReactNode): string { if (typeof children === "string") return children; if (Array.isArray(children)) return children.map(extractText).join(""); if (children && typeof children === "object" && "props" in children) { return extractText((children as React.ReactElement<{ children?: React.ReactNode }>).props.children); } return ""; } function MermaidBlock({ chart }: { chart: string }) { const [svg, setSvg] = useState(""); const [error, setError] = useState(""); const idRef = useRef(`mermaid-${Math.random().toString(36).slice(2)}`); useEffect(() => { let mounted = true; const renderChart = async () => { try { const mermaid = (await import("mermaid")).default; mermaid.initialize({ startOnLoad: false, theme: "neutral", securityLevel: "loose" }); const { svg: rendered } = await mermaid.render(idRef.current, chart); if (mounted) { setSvg(rendered); setError(""); } } catch { if (mounted) { setError("Mermaid diyagramı oluşturulamadı."); } } }; void renderChart(); return () => { mounted = false; }; }, [chart]); if (error) { return ( {error} ); } if (!svg) { return ( Diyagram hazırlanıyor... ); } return (
); } const GISCUS_REPO = process.env.NEXT_PUBLIC_GISCUS_REPO || ""; const GISCUS_REPO_ID = process.env.NEXT_PUBLIC_GISCUS_REPO_ID || ""; const GISCUS_CATEGORY = process.env.NEXT_PUBLIC_GISCUS_CATEGORY || "Announcements"; const GISCUS_CATEGORY_ID = process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID || ""; export function BlogDetailContent({ post }: BlogDetailContentProps) { const scrollerRef = useRef(null); const [progress, setProgress] = useState(0); const progressWidth = useMemo(() => `${Math.min(100, Math.max(0, progress))}%`, [progress]); const handleScroll = () => { const element = scrollerRef.current; if (!element) return; const scrollable = element.scrollHeight - element.clientHeight; if (scrollable <= 0) { setProgress(100); return; } setProgress((element.scrollTop / scrollable) * 100); }; const showGiscus = GISCUS_REPO && GISCUS_REPO_ID && GISCUS_CATEGORY_ID; return ( <>
{"<- Blog'a dön"}
{post.category} {post.title} {post.author} · {post.date} · {post.readTime} {post.excerpt}
{post.title}
{ const text = extractText(children); const id = slugify(text); return ( {children} ); }, h2: ({ children }) => { const text = extractText(children); const id = slugify(text); return ( {children} ); }, h3: ({ children }) => { const text = extractText(children); const id = slugify(text); return ( {children} ); }, h4: ({ children }) => { const text = extractText(children); const id = slugify(text); return ( {children} ); }, p: ({ node, children, ...props }) => { const hasImg = node?.children?.some((c: any) => c.tagName === "img"); if (hasImg) { return (
{children}
); } return ( {children} ); }, ul: ({ children }) => (
    {children}
), ol: ({ children }) => (
    {children}
), li: ({ children }) => (
  • {children}
  • ), a: ({ href, children }) => ( {children} ), blockquote: ({ children }) => (
    {children}
    ), hr: () => (
    ), table: ({ children }) => (
    {children}
    ), thead: ({ children }) => {children}, tr: ({ children }) => {children}, th: ({ children }) => ( {children} ), td: ({ children }) => ( {children} ), img: ({ src, alt }) => ( {alt {alt && (
    {alt}
    )}
    ), code: ({ className, children }) => { const match = /language-(\w+)/.exec(className ?? ""); const codeText = String(children).replace(/\n$/, ""); const language = match?.[1] ?? ""; if (!match) { return ( {children} ); } if (language === "mermaid") { return ; } return ( {codeText} ); }, }} > {post.markdown}
    {showGiscus && (
    Yorumlar
    )}
    ); }