From 1a75f42f299864f0bf462877ff96603d51a63c31 Mon Sep 17 00:00:00 2001 From: bilalgursen Date: Mon, 21 Sep 2026 04:48:10 +0300 Subject: [PATCH] =?UTF-8?q?fix(rehber):=20=C5=9Fema=20metni=20SSR'da=20+?= =?UTF-8?q?=20mermaid=20hata=20toparlama?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Şemanın metin karşılığı yalnızca SVG çizilince `aria-label` olarak basılıyordu; JS çalıştırmayan botlar iskeletten başka bir şey görmüyordu. Artık aynı `ariaLabel` metni figure içinde bir `
` olarak sunucu HTML'ine girer. mermaid import/render hatası yakalanır: iskelet kalkar, metin açık gelir, mermaid'in body'de bıraktığı geçici div temizlenir. Co-Authored-By: Claude Fable 5.1 --- .../rehber/components/el-cizimi-sema.tsx | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/src/features/rehber/components/el-cizimi-sema.tsx b/src/features/rehber/components/el-cizimi-sema.tsx index ad0955f..e373ea9 100644 --- a/src/features/rehber/components/el-cizimi-sema.tsx +++ b/src/features/rehber/components/el-cizimi-sema.tsx @@ -30,6 +30,9 @@ export function ElCizimiSema({ figcaption?: React.ReactNode; }) { const [svg, setSvg] = useState(null); + // mermaid yüklenemez ya da çizemezse (bazı tarayıcılarda `getBBox` hatası) + // sonsuz iskelet yerine metin karşılığı açık gelir + const [hata, setHata] = useState(false); const figureRef = useRef(null); // mermaid.render'ın istediği DOM id'si: useId'nin ":" karakterleri geçersiz const semaId = `sema-${useId().replace(/[^a-zA-Z0-9-]/g, "")}`; @@ -52,26 +55,34 @@ export function ElCizimiSema({ io.observe(el); function cizdir() { - import("mermaid").then(async ({ default: mermaid }) => { - mermaid.initialize({ - startOnLoad: false, - look: "handDrawn", - handDrawnSeed: 7, // her render'da aynı çizgi titremesi (deterministik) - theme: "base", - fontFamily: `${elYazisi.style.fontFamily}, cursive`, - themeVariables: { - primaryColor: "#ffffff", - primaryBorderColor: "#e2e8f0", - primaryTextColor: "#0f172a", - lineColor: "#94a3b8", - edgeLabelBackground: "#ffffff", + import("mermaid") + .then(async ({ default: mermaid }) => { + mermaid.initialize({ + startOnLoad: false, + // Hata olursa mermaid kendi "bomba" SVG'sini basmasın; biz toparlıyoruz + suppressErrorRendering: true, + look: "handDrawn", + handDrawnSeed: 7, // her render'da aynı çizgi titremesi (deterministik) + theme: "base", fontFamily: `${elYazisi.style.fontFamily}, cursive`, - fontSize: "17px", // script fontun x-yüksekliği düşük; okunurluk için büyütüldü - }, + themeVariables: { + primaryColor: "#ffffff", + primaryBorderColor: "#e2e8f0", + primaryTextColor: "#0f172a", + lineColor: "#94a3b8", + edgeLabelBackground: "#ffffff", + fontFamily: `${elYazisi.style.fontFamily}, cursive`, + fontSize: "17px", // script fontun x-yüksekliği düşük; okunurluk için büyütüldü + }, + }); + const sonuc = await mermaid.render(semaId, tanim); + if (!iptal) setSvg(sonuc.svg); + }) + .catch(() => { + // mermaid.render atarsa geçici ölçüm div'ini body'de bırakabiliyor + document.getElementById(`d${semaId}`)?.remove(); + if (!iptal) setHata(true); }); - const sonuc = await mermaid.render(semaId, tanim); - if (!iptal) setSvg(sonuc.svg); - }); } return () => { @@ -89,7 +100,7 @@ export function ElCizimiSema({ className={`${elYazisi.className} overflow-x-auto [&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full`} dangerouslySetInnerHTML={{ __html: svg }} /> - ) : ( + ) : hata ? null : (
) : null} + {/* Şemanın metin karşılığı sunucu HTML'inde de durur: JS çalıştırmayan + botlar ve şemayı çizemeyen tarayıcılar aynı içeriği okur. Kaynak + yine tek `ariaLabel` prop'u — ikinci bir metin tutulmaz. */} +
+ + Şemayı metin olarak oku + +

{ariaLabel}

+
); }