feat(universite): tür, ızgaraya değil H1'in altındaki kimlik çipine döndü

Izgara 5 karta çıkamıyor: lg:grid-cols-[1fr_1fr_1.35fr] + lg:grid-rows-2
şablonunda harita 3. sütunu iki satır kaplıyor, kartlara tam 4 hücre kalıyor.
Tür zaten bir metrik değil kategori; sitenin geri kalanında (program tablosu,
rapor listesi, tadımlık, bölüm listesi) başlığın altında çip olarak yaşıyor,
detay sayfası bunu taşımayan tek yüzeydi.

- Tür çipi H1'in altına girdi; sınıf seti program-tablosu.tsx:329-333'ten
  birebir kopya (yeni varyant yok). Sayfalama sayfalarında da yazar.
- URAP'ı olmayan 31 sayfada ızgaranın 4. hücresi "Tür" yerine "Toplam
  kontenjan" oldu; toplam kontenjanı 0 olan üniversite yok, o hücrede "—"
  çıkmıyor.
- UNITUR_ETIKET bileşenin içinden src/lib/unitur.ts'e çıktı (DILIM_ETIKET'in
  lib/risk.ts'te durması gibi tek kaynak) ve bölüm listesi rozetleri de buna
  bağlandı: "Kktc" → "KKTC", "Vakıf Myo" → "Vakıf MYO".
- Özet cümledeki "…, devlet üniversitesi, …" telafisi kalıyor: tür bir kez
  taranabilir çip, bir kez okunabilir cümle olarak geçiyor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-09-23 11:14:54 +03:00
parent fa7f228822
commit e8434dc054
3 changed files with 84 additions and 41 deletions

View File

@@ -5,6 +5,7 @@ import Link from "next/link";
import { ChevronDown, ChevronUp } from "lucide-react";
import type { Program } from "@/types/yokatlas";
import { trBaslikDuzeni } from "@/lib/slug";
import { UNITUR_ETIKET } from "@/lib/unitur";
import { VERI_YIL_SAYISI } from "@/lib/veri-yillari";
import { Sayfalama, SAYFA_BOYU } from "./sayfalama";
import {
@@ -224,7 +225,8 @@ export function BolumProgramListesi({
: "bg-violet-50 text-violet-600"
}`}
>
{devlet ? "Devlet" : trBaslikDuzeni(p.unitur)}
{UNITUR_ETIKET[p.unitur]?.cip ??
trBaslikDuzeni(p.unitur)}
</span>
) : null}
<span className="truncate">

View File

@@ -9,6 +9,7 @@ import {
bolumSlugFromIsim,
} from "../katalog-queries";
import { trBaslikDuzeni } from "@/lib/slug";
import { UNITUR_ETIKET, uniturDevletMi } from "@/lib/unitur";
import {
JsonLd,
breadcrumbJsonLd,
@@ -43,29 +44,6 @@ import { BASLIK_YILI, SON_YIL, TERCIH_YILI } from "@/lib/veri-yillari";
const sayi = (n: number) => n.toLocaleString("tr-TR");
// Ham `unitur` değerlerinin ekranda görünen karşılığı. `trBaslikDuzeni`
// tr-TR küçültmesi yaptığı için ("I" → "ı") ham değerlere uygulanamaz:
// "YURTDISI KAMU" → "Yurtdısı Kamu" gibi Türkçede olmayan kelimeler çıkıyor.
// İki biçim tek kaynakta durur, çünkü aynı bilgi iki yerde geçiyor:
// `kart` = "Tür" kartındaki kısa etiket (yalnız URAP'ta olmayan üniversitede),
// `cumle` = özet paragrafın ilk virgülündeki öbek (her üniversitede).
// `cumle` cümle ortasında okunacak biçimde küçük harfle başlar; KKTC gibi
// kısaltmalar büyük kalır.
const UNITUR_ETIKET: Record<string, { kart: string; cumle: string }> = {
DEVLET: { kart: "Devlet", cumle: "devlet üniversitesi" },
VAKIF: { kart: "Vakıf", cumle: "vakıf üniversitesi" },
"VAKIF MYO": { kart: "Vakıf MYO", cumle: "vakıf meslek yüksekokulu" },
KKTC: { kart: "KKTC", cumle: "KKTC üniversitesi" },
"YURTDISI KAMU": {
kart: "Yurt dışı (kamu)",
cumle: "yurt dışında bir kamu üniversitesi",
},
"YURTDISI VAKIF": {
kart: "Yurt dışı (vakıf)",
cumle: "yurt dışında bir vakıf üniversitesi",
},
};
export function uniToplamSayfa(programSayisi: number): number {
return Math.max(1, Math.ceil(programSayisi / SAYFA_BOYU));
}
@@ -235,14 +213,13 @@ export function UniversiteIcerik({
}
const ilkSayfa = sayfa === 1;
// Devlet/vakıf bilgisi sayfada başka hiçbir yerde geçmiyor (URAP'ta olan
// üniversitede "Tür" kartının yerini URAP sırası aldı), o yüzden özet
// paragrafın ilk virgülünde duruyor. Haritada olmayan ya da NULL bir
// `unitur`'da öbek hiç yazılmaz: cümlede kopuk virgül/boşluk kalmaz ve
// ham DB değeri cümlenin içine sızmaz.
const turCumlesi = uni.unitur
? UNITUR_ETIKET[uni.unitur]?.cumle
: undefined;
// Tür iki yerde geçer ve bu bilinçli: H1'in altındaki çip taranmak,
// özet paragrafın ilk virgülündeki öbek okunmak içindir. Izgarada "Tür"
// kartı yok (şablon 4 hücre, bkz. aşağıdaki ızgara yorumu). Haritada
// olmayan ya da NULL bir `unitur`'da öbek hiç yazılmaz: cümlede kopuk
// virgül/boşluk kalmaz ve ham DB değeri cümlenin içine sızmaz.
const turEtiketi = uni.unitur ? UNITUR_ETIKET[uni.unitur] : undefined;
const turCumlesi = turEtiketi?.cumle;
const buYol = ilkSayfa
? `/universite/${slug}`
: `/universite/${slug}/sayfa/${sayfa}`;
@@ -336,6 +313,31 @@ export function UniversiteIcerik({
</h1>
</div>
{/* Kurumun kimliği (tür + il): ızgaradaki kartlar sayısal ve
karşılaştırılabilir metriklerdir, tür ise kategoridir — sitenin
geri kalanında da başlığın altında çip olarak duruyor. Çipin sınıf
seti program-tablosu.tsx:329-333'ten birebir kopyadır (AGENTS.md
"ortak elemanlar tek kaynaktan"); yeni varyant üretilmez.
Sayfalama sayfalarında da yazar: ziyaretçi Google'dan doğrudan
/sayfa/N'ye inebiliyor, kimlik orada da aynı. `unitur` NULL ise
satırın tamamı düşer, kopuk boşluk kalmaz. */}
{turEtiketi ? (
<p className="mt-3 flex min-w-0 items-center gap-1.5 text-xs text-slate-500">
<span
className={`shrink-0 rounded px-1 py-px text-[10px] font-medium leading-4 ${
uniturDevletMi(uni.unitur)
? "bg-slate-100 text-slate-600"
: "bg-violet-50 text-violet-600"
}`}
>
{turEtiketi.cip}
</span>
{uni.il ? (
<span className="truncate">{trBaslikDuzeni(uni.il)}</span>
) : null}
</p>
) : null}
{ilkSayfa ? (
<>
<p className="mt-4 max-w-3xl text-sm leading-7 text-slate-600">
@@ -387,10 +389,15 @@ export function UniversiteIcerik({
{sayi(uni.fakulteSayisi)}
</dd>
</div>
{/* URAP'ta olan üniversitede "Tür" kartının yeri URAP'a
bırakılır (kart sayısı 4'te kalır, ızgara şablonu değişmez);
olmayanda "Tür" yerinde durur — hiçbir sayfada boş kutu yok.
Payda kartın içindedir: "18." tek başına yanıltır. */}
{/* Şablon tam 4 hücre bırakıyor: masaüstünde harita 3. sütunu
iki satır boyunca kaplıyor (lg:grid-rows-2 + row-span-2), 5.
kart ızgarayı bozar. Bu yüzden 4. hücre tek: URAP'ta olan
üniversitede URAP sırası, olmayan 31 sayfada toplam
kontenjan. Toplam kontenjanı 0 olan üniversite yok
(yokatlas.db: GROUP BY universite HAVING
SUM(COALESCE(kontenjan2026,0))=0 → 0 satır), yani hiçbir
sayfada "—" çıkmaz. URAP'ta payda kartın içindedir: "18."
tek başına yanıltır. */}
<div className="rounded-xl border border-slate-200 bg-white p-4">
{uni.urap ? (
<>
@@ -407,13 +414,10 @@ export function UniversiteIcerik({
) : (
<>
<dt className="text-xs font-medium uppercase tracking-wide text-slate-500">
Tür
Toplam kontenjan
</dt>
<dd className="mt-1 font-heading text-2xl font-bold text-slate-900">
{uni.unitur
? (UNITUR_ETIKET[uni.unitur]?.kart ??
trBaslikDuzeni(uni.unitur))
: "—"}
{sayi(uni.stats.toplamKontenjan)}
</dd>
</>
)}

37
src/lib/unitur.ts Normal file
View File

@@ -0,0 +1,37 @@
/**
* Ham `unitur` değerlerinin (DB: DEVLET, VAKIF, VAKIF MYO, KKTC,
* YURTDISI KAMU, YURTDISI VAKIF) ekranda görünen karşılığı — **tek kaynak**.
* `DILIM_ETIKET`'in `lib/risk.ts`'te durması gibi: ham anahtarı kullanıcıya
* basma, buradan oku (AGENTS.md "ortak elemanlar tek kaynaktan").
*
* `trBaslikDuzeni` bu değerlere uygulanamaz: tr-TR küçültmesi "I" → "ı"
* yaptığı için "KKTC" → "Kktc", "VAKIF MYO" → "Vakıf Myo",
* "YURTDISI KAMU" → "Yurtdısı Kamu" gibi Türkçede olmayan kelimeler çıkıyor.
*
* İki biçim var, çünkü aynı bilgi iki bağlamda geçiyor:
* `cip` = başlık altındaki kimlik çipinde okunan kısa etiket,
* `cumle` = özet paragrafın ilk virgülündeki öbek; cümle ortasında
* okunacağı için küçük harfle başlar, KKTC gibi kısaltmalar
* büyük kalır.
*/
export const UNITUR_ETIKET: Record<string, { cip: string; cumle: string }> = {
DEVLET: { cip: "Devlet", cumle: "devlet üniversitesi" },
VAKIF: { cip: "Vakıf", cumle: "vakıf üniversitesi" },
"VAKIF MYO": { cip: "Vakıf MYO", cumle: "vakıf meslek yüksekokulu" },
KKTC: { cip: "KKTC", cumle: "KKTC üniversitesi" },
"YURTDISI KAMU": {
cip: "Yurt dışı (kamu)",
cumle: "yurt dışında bir kamu üniversitesi",
},
"YURTDISI VAKIF": {
cip: "Yurt dışı (vakıf)",
cumle: "yurt dışında bir vakıf üniversitesi",
},
};
/**
* Çipin renk dili: devlet → slate, diğer her şey (vakıf, KKTC, yurt dışı)
* → violet. Sitedeki dört çip kopyasının hepsinde aynı kural.
*/
export const uniturDevletMi = (unitur: string | null | undefined) =>
unitur === "DEVLET";