Rehbere mermaid şema desteği ve 4 yeni tercih dönemi yazısı ekle

Markdown'daki \`\`\`mermaid çitleri artık yazıyı parçalara bölüyor ve şemalar
üründeki ortak el çizimi bileşeniyle (ElCizimiSema) çiziliyor; çitte "%% aria:"
satırı zorunlu, "%% altyazi:" figcaption veriyor. Tercih dönemi aramalarına
dayanan dört yeni yazı: merkezi yerleştirme algoritması, OBP hesabı, üniversite
kayıt rehberi ve yerleşememe/istenmeyen bölüm karar ağacı — her biri risk renk
dilinde birer şemayla.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-08-02 04:25:58 +03:00
parent 716f7bb3fb
commit 6bd210075f
10 changed files with 1215 additions and 4 deletions

View File

@@ -0,0 +1,85 @@
"use client";
// Ürün genelindeki "el çizimi" mermaid şemalarının tek kaynağı: /meraklisina
// hunisi de rehber yazılarındaki şemalar da bu bileşenle çizilir, böylece
// görünüm (font, renk teması, çizgi titremesi) her yerde birebir aynı kalır.
// Mermaid ağır bir paket olduğu için useEffect içinde dinamik import edilir;
// sayfa paketine girmez.
import { useEffect, useId, useState } from "react";
import localFont from "next/font/local";
// Şemanın "el çizimi" görünümüne uyan el yazısı fontu (Sweet Cucumber
// Mocktail, Misti's Fonts). Türkçe glifler doğrulandı (ş, ğ, ı, İ… hepsi
// var). DİKKAT: lisans "kişisel kullanım için ücretsiz" — canlıya çıkmadan
// mistifonts.com/sweet-cucumber-mocktail adresinden ticari lisans alınmalı.
const elYazisi = localFont({
src: "../fonts/SweetCucumberMocktail.woff2",
display: "swap",
});
export function ElCizimiSema({
tanim,
ariaLabel,
figcaption,
}: {
/** Mermaid tanımı (flowchart vb.) */
tanim: string;
/** Şemanın tamamını anlatan erişilebilirlik metni */
ariaLabel: string;
figcaption?: React.ReactNode;
}) {
const [svg, setSvg] = useState<string | null>(null);
// mermaid.render'ın istediği DOM id'si: useId'nin ":" karakterleri geçersiz
const semaId = `sema-${useId().replace(/[^a-zA-Z0-9-]/g, "")}`;
useEffect(() => {
let iptal = false;
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",
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);
});
return () => {
iptal = true;
};
}, [semaId, tanim]);
return (
<figure className="mt-6">
{svg ? (
<div
role="img"
aria-label={ariaLabel}
className={`${elYazisi.className} overflow-x-auto [&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-full`}
dangerouslySetInnerHTML={{ __html: svg }}
/>
) : (
<div
aria-hidden
className="h-96 animate-pulse rounded-xl bg-slate-100"
/>
)}
{figcaption ? (
<figcaption className="mt-3 text-xs text-slate-500">
{figcaption}
</figcaption>
) : null}
</figure>
);
}