fix(rehber): şema metni SSR'da + mermaid hata toparlama
Ş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 `<details>` 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 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,9 @@ export function ElCizimiSema({
|
|||||||
figcaption?: React.ReactNode;
|
figcaption?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const [svg, setSvg] = useState<string | null>(null);
|
const [svg, setSvg] = useState<string | null>(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<HTMLElement>(null);
|
const figureRef = useRef<HTMLElement>(null);
|
||||||
// mermaid.render'ın istediği DOM id'si: useId'nin ":" karakterleri geçersiz
|
// mermaid.render'ın istediği DOM id'si: useId'nin ":" karakterleri geçersiz
|
||||||
const semaId = `sema-${useId().replace(/[^a-zA-Z0-9-]/g, "")}`;
|
const semaId = `sema-${useId().replace(/[^a-zA-Z0-9-]/g, "")}`;
|
||||||
@@ -52,9 +55,12 @@ export function ElCizimiSema({
|
|||||||
io.observe(el);
|
io.observe(el);
|
||||||
|
|
||||||
function cizdir() {
|
function cizdir() {
|
||||||
import("mermaid").then(async ({ default: mermaid }) => {
|
import("mermaid")
|
||||||
|
.then(async ({ default: mermaid }) => {
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
startOnLoad: false,
|
startOnLoad: false,
|
||||||
|
// Hata olursa mermaid kendi "bomba" SVG'sini basmasın; biz toparlıyoruz
|
||||||
|
suppressErrorRendering: true,
|
||||||
look: "handDrawn",
|
look: "handDrawn",
|
||||||
handDrawnSeed: 7, // her render'da aynı çizgi titremesi (deterministik)
|
handDrawnSeed: 7, // her render'da aynı çizgi titremesi (deterministik)
|
||||||
theme: "base",
|
theme: "base",
|
||||||
@@ -71,6 +77,11 @@ export function ElCizimiSema({
|
|||||||
});
|
});
|
||||||
const sonuc = await mermaid.render(semaId, tanim);
|
const sonuc = await mermaid.render(semaId, tanim);
|
||||||
if (!iptal) setSvg(sonuc.svg);
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +100,7 @@ export function ElCizimiSema({
|
|||||||
className={`${elYazisi.className} overflow-x-auto [&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full`}
|
className={`${elYazisi.className} overflow-x-auto [&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full`}
|
||||||
dangerouslySetInnerHTML={{ __html: svg }}
|
dangerouslySetInnerHTML={{ __html: svg }}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : hata ? null : (
|
||||||
<div
|
<div
|
||||||
aria-hidden
|
aria-hidden
|
||||||
className="h-96 animate-pulse rounded-xl bg-slate-100"
|
className="h-96 animate-pulse rounded-xl bg-slate-100"
|
||||||
@@ -100,6 +111,18 @@ export function ElCizimiSema({
|
|||||||
{figcaption}
|
{figcaption}
|
||||||
</figcaption>
|
</figcaption>
|
||||||
) : 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. */}
|
||||||
|
<details
|
||||||
|
open={hata || undefined}
|
||||||
|
className="mt-2 text-xs text-slate-500"
|
||||||
|
>
|
||||||
|
<summary className="cursor-pointer font-medium text-slate-600">
|
||||||
|
Şemayı metin olarak oku
|
||||||
|
</summary>
|
||||||
|
<p className="mt-2 text-sm leading-6 text-slate-600">{ariaLabel}</p>
|
||||||
|
</details>
|
||||||
</figure>
|
</figure>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user