Update routing in next.config.ts to redirect "/tercih-robotu" to the hero form, add simple-icons dependency in package.json, and enhance database indexing for improved query performance. Remove unused SVG files and update metadata across various pages for better SEO and clarity.
All checks were successful
Deploy / deploy (push) Successful in 14m14s

This commit is contained in:
bilalgursen
2026-08-01 17:28:38 +03:00
parent 569b9e5da2
commit 8cf0c3267d
76 changed files with 5050 additions and 255 deletions

View File

@@ -0,0 +1,640 @@
"use client";
// /meraklisina'nın canlı anlatım katmanı: kullanıcı kendi sıralamasını girer,
// dilim şeridi ve kademeli filtre hunisi o sıralamanın GERÇEK sayılarıyla
// güncellenir. Provider sayfadaki metin bölümlerini (RSC children) sarar;
// görseller context'ten okur, böylece tek girişle iki diyagram birden yaşar.
import {
createContext,
useContext,
useEffect,
useRef,
useState,
type ReactNode,
} from "react";
import type { DilimKey, SihirbazFacetleri } from "@/lib/db";
const TUR_SECENEKLERI = [
{ deger: "say", etiket: "Sayısal" },
{ deger: "ea", etiket: "Eşit Ağırlık" },
{ deger: "soz", etiket: "Sözel" },
{ deger: "dil", etiket: "Dil" },
{ deger: "tyt", etiket: "TYT" },
] as const;
export type DemoVeri = {
facetler: SihirbazFacetleri;
dilimToplam: Record<DilimKey, number>;
};
type DemoDurum = {
sira: number;
tur: string;
veri: DemoVeri;
yukleniyor: boolean;
// Huni seçimleri ve kademeli facet cevapları
kategori: string | null;
il: string | null;
tip: "devlet" | "vakif" | null;
kategoriFacet: SihirbazFacetleri | null; // ?kategori= cevabı (iller buradan)
ilFacet: SihirbazFacetleri | null; // ?kategori&il cevabı (tipler buradan)
kategoriSec: (k: string | null) => void;
ilSec: (i: string | null) => void;
tipSec: (t: "devlet" | "vakif" | null) => void;
siraDegistir: (ham: string) => void;
turDegistir: (t: string) => void;
siraMetni: string;
};
const DemoContext = createContext<DemoDurum | null>(null);
function useDemo(): DemoDurum {
const ctx = useContext(DemoContext);
if (!ctx) throw new Error("Demo bileşenleri SiralamaDemo içinde kullanılmalı");
return ctx;
}
async function facetGetir(
sira: number,
tur: string,
secim: { kategori?: string; il?: string; dilimler?: boolean },
signal: AbortSignal,
): Promise<{ facetler: SihirbazFacetleri; dilimToplam?: Record<DilimKey, number> } | null> {
const params = new URLSearchParams({ sira: String(sira), tur });
if (secim.kategori) params.append("kategori", secim.kategori);
if (secim.il) params.append("il", secim.il);
if (secim.dilimler) params.set("dilimler", "1");
try {
const res = await fetch(`/api/facetler?${params}`, { signal });
if (!res.ok) return null;
return (await res.json()) as {
facetler: SihirbazFacetleri;
dilimToplam?: Record<DilimKey, number>;
};
} catch {
return null;
}
}
export function SiralamaDemo({
baslangicSira,
baslangicVeri,
children,
}: {
baslangicSira: number;
baslangicVeri: DemoVeri;
children: ReactNode;
}) {
const [siraMetni, setSiraMetni] = useState(
baslangicSira.toLocaleString("tr-TR"),
);
const [sira, setSira] = useState(baslangicSira);
const [tur, setTur] = useState("say");
const [veri, setVeri] = useState(baslangicVeri);
const [yukleniyor, setYukleniyor] = useState(false);
const [kategori, setKategori] = useState<string | null>(null);
const [il, setIl] = useState<string | null>(null);
const [tip, setTip] = useState<"devlet" | "vakif" | null>(null);
const [kategoriFacet, setKategoriFacet] = useState<SihirbazFacetleri | null>(
null,
);
const [ilFacet, setIlFacet] = useState<SihirbazFacetleri | null>(null);
const zamanlayici = useRef<ReturnType<typeof setTimeout> | null>(null);
// Sıralama/tür değişti → ana veriyi tazele, huni seçimlerini sıfırla
useEffect(() => {
if (sira === baslangicSira && tur === "say" && veri === baslangicVeri) {
return; // ilk render: sunucudan gelen veri zaten güncel
}
const ctrl = new AbortController();
// eslint-disable-next-line react-hooks/set-state-in-effect -- fetch başlangıç işareti
setYukleniyor(true);
setKategori(null);
setIl(null);
setTip(null);
setKategoriFacet(null);
setIlFacet(null);
facetGetir(sira, tur, { dilimler: true }, ctrl.signal)
.then((cevap) => {
if (!cevap?.dilimToplam) return;
setVeri({ facetler: cevap.facetler, dilimToplam: cevap.dilimToplam });
})
.finally(() => setYukleniyor(false));
return () => ctrl.abort();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sira, tur]);
// Kategori seçildi → o kategorinin illerini getir
useEffect(() => {
if (!kategori) return;
const ctrl = new AbortController();
facetGetir(sira, tur, { kategori }, ctrl.signal).then((cevap) => {
if (cevap) setKategoriFacet(cevap.facetler);
});
return () => ctrl.abort();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [kategori]);
// İl seçildi → kategori+il ile tipleri getir
useEffect(() => {
if (!kategori || !il) return;
const ctrl = new AbortController();
facetGetir(sira, tur, { kategori, il }, ctrl.signal).then((cevap) => {
if (cevap) setIlFacet(cevap.facetler);
});
return () => ctrl.abort();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [kategori, il]);
function siraDegistir(ham: string) {
const rakamlar = ham.replace(/\D/g, "").slice(0, 7);
setSiraMetni(rakamlar ? Number(rakamlar).toLocaleString("tr-TR") : "");
if (zamanlayici.current) clearTimeout(zamanlayici.current);
const deger = Number(rakamlar);
if (!deger || deger < 1 || deger > 4_000_000) return;
zamanlayici.current = setTimeout(() => setSira(deger), 450);
}
const durum: DemoDurum = {
sira,
tur,
veri,
yukleniyor,
kategori,
il,
tip,
kategoriFacet,
ilFacet,
kategoriSec: (k) => {
setKategori(k);
setIl(null);
setTip(null);
setKategoriFacet(null);
setIlFacet(null);
},
ilSec: (i) => {
setIl(i);
setTip(null);
setIlFacet(null);
},
tipSec: setTip,
siraDegistir,
turDegistir: setTur,
siraMetni,
};
return <DemoContext.Provider value={durum}>{children}</DemoContext.Provider>;
}
/** Sıralama girişi + puan türü — iki diyagramı birden süren tek kumanda. */
export function DemoKumanda() {
const { siraMetni, siraDegistir, tur, turDegistir, sira, yukleniyor } =
useDemo();
return (
<div className="rounded-2xl border border-primary/20 bg-primary/5 p-5">
<label
htmlFor="demo-sira"
className="font-heading text-sm font-bold text-slate-900"
>
Kendi sıralamanı gir, aşağıdaki görseller sana göre değişsin
</label>
<div className="mt-3 flex flex-col gap-3 sm:flex-row sm:items-center">
<input
id="demo-sira"
inputMode="numeric"
autoComplete="off"
value={siraMetni}
onChange={(e) => siraDegistir(e.target.value)}
placeholder="ör. 85.000"
className="h-11 w-full rounded-xl border border-slate-200 bg-white px-4 text-base font-medium tabular-nums outline-none transition-colors focus:border-primary sm:w-44"
/>
<div
role="radiogroup"
aria-label="Puan türü"
className="flex flex-wrap gap-1.5"
>
{TUR_SECENEKLERI.map((t) => (
<button
key={t.deger}
type="button"
role="radio"
aria-checked={tur === t.deger}
onClick={() => turDegistir(t.deger)}
className={
tur === t.deger
? "cursor-pointer rounded-full border border-primary bg-primary px-3 py-1.5 text-xs font-medium text-white"
: "cursor-pointer rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs text-slate-600 transition-colors duration-200 hover:border-slate-300"
}
>
{t.etiket}
</button>
))}
</div>
</div>
<p
className={`mt-2 text-xs text-slate-500 ${yukleniyor ? "animate-pulse" : ""}`}
aria-live="polite"
>
{yukleniyor
? "Hesaplanıyor…"
: `Aşağıdaki tüm sayılar ${sira.toLocaleString("tr-TR")}. sıradaki bir aday için gerçek YÖK Atlas verisidir.`}
</p>
</div>
);
}
/** Sıralama ekseni: girilen sıraya göre dilim sınırları ve gerçek adetler. */
export function DilimSeridiCanli() {
const { sira, veri, yukleniyor } = useDemo();
const t = veri.dilimToplam;
const dengeliUst = Math.round(sira * 1.4);
const fmt = (n: number) => n.toLocaleString("tr-TR");
return (
<figure className={`mt-6 ${yukleniyor ? "animate-pulse opacity-60" : ""}`}>
<svg
viewBox="0 0 640 168"
role="img"
aria-label={`Sıralama ekseni: ${fmt(sira)}. sıradaki aday için Hayal diliminde ${fmt(t.hayal)}, Dengeli diliminde ${fmt(t.dengeli)}, Garanti diliminde ${fmt(t.garanti)} program var.`}
className="w-full"
>
{/* eksen */}
<line
x1="20"
y1="86"
x2="620"
y2="86"
stroke="currentColor"
className="text-slate-300"
strokeWidth="2"
/>
<text x="20" y="150" className="fill-slate-400 text-[11px]">
1. sıra (en iyi)
</text>
<text
x="620"
y="150"
textAnchor="end"
className="fill-slate-400 text-[11px]"
>
taban sıralaması büyüdükçe →
</text>
{/* hayal */}
<rect x="20" y="70" width="150" height="32" rx="4" className="fill-red-100" />
<text x="95" y="40" textAnchor="middle" className="fill-red-600 text-[12px] font-semibold">
Hayal
</text>
<text x="95" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.hayal)} program
</text>
<text x="95" y="123" textAnchor="middle" className="fill-slate-500 text-[10px]">
tabanı senden iyi
</text>
{/* aday işareti */}
<line x1="172" y1="24" x2="172" y2="112" stroke="currentColor" className="text-slate-900" strokeWidth="2" strokeDasharray="4 3" />
<text x="172" y="16" textAnchor="middle" className="fill-slate-900 text-[12px] font-bold">
SEN · {fmt(sira)}.
</text>
{/* dengeli */}
<rect x="174" y="70" width="120" height="32" rx="4" className="fill-amber-100" />
<text x="234" y="40" textAnchor="middle" className="fill-amber-600 text-[12px] font-semibold">
Dengeli
</text>
<text x="234" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.dengeli)} program
</text>
<text x="234" y="123" textAnchor="middle" className="fill-slate-500 text-[10px]">
{fmt(sira)}. – {fmt(dengeliUst)}. arası taban
</text>
{/* garanti */}
<rect x="296" y="70" width="324" height="32" rx="4" className="fill-emerald-100" />
<text x="458" y="40" textAnchor="middle" className="fill-emerald-700 text-[12px] font-semibold">
Garanti
</text>
<text x="458" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.garanti)} program
</text>
<text x="458" y="123" textAnchor="middle" className="fill-slate-500 text-[10px]">
{fmt(dengeliUst + 1)}. sonrası — sonu yok, sayfaladıkça uzar
</text>
</svg>
<figcaption className="mt-2 text-xs text-slate-500">
Liste her dilimde{" "}
<span className="font-medium text-slate-700">
sana en yakın tabandan uzağa doğru
</span>{" "}
sıralanır; &ldquo;Daha fazla göster&rdquo; dedikçe uzaktakiler gelir.
</figcaption>
</figure>
);
}
function HuniCubugu({
etiket,
adet,
oran,
}: {
etiket: string;
adet: number;
oran: number;
}) {
return (
<div className="min-w-0 flex-1">
<div
className="flex h-9 min-w-36 items-center justify-between gap-2 rounded-lg bg-primary/85 px-3 transition-[width] duration-300"
style={{ width: `${Math.min(Math.max(oran * 100, 36), 100)}%` }}
>
<span className="truncate text-xs font-medium text-white">{etiket}</span>
<span className="shrink-0 text-xs font-bold tabular-nums text-white">
{adet.toLocaleString("tr-TR")}
</span>
</div>
</div>
);
}
function SecimCipleri<T extends { anahtar: string; etiket: string; adet: number }>({
secenekler,
secili,
onSec,
}: {
secenekler: T[];
secili: string | null;
onSec: (anahtar: string | null) => void;
}) {
return (
<div className="flex flex-wrap gap-1.5">
{secenekler.map((s) => (
<button
key={s.anahtar}
type="button"
aria-pressed={secili === s.anahtar}
onClick={() => onSec(secili === s.anahtar ? null : s.anahtar)}
className={
secili === s.anahtar
? "cursor-pointer rounded-full border border-orange-500 bg-orange-500 px-3 py-1.5 text-xs font-medium text-white"
: "cursor-pointer rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs text-slate-600 transition-colors duration-200 hover:border-slate-300"
}
>
{s.etiket}
<span className="ml-1 text-[10px] opacity-70 tabular-nums">
{s.adet.toLocaleString("tr-TR")}
</span>
</button>
))}
</div>
);
}
// AI listesinin dilim iskeleti: üstte hayal, ortada dengeli, sonda garanti.
// Ürünün risk renkleriyle boyanır; sayılar prompt'taki kuralın orta değeri.
const LISTE_ISKELETI: { dilim: string; adet: number; renk: string }[] = [
{ dilim: "hayal", adet: 5, renk: "bg-red-400" },
{ dilim: "dengeli", adet: 13, renk: "bg-amber-400" },
{ dilim: "garanti", adet: 6, renk: "bg-emerald-500" },
];
/** Huninin finali: kalan havuzun yapay zekâya gidişi ve 24'lük listenin
iskeleti. Havuz 24'ün altına düşerse gevşetme kuralını canlı gösterir. */
function YapayZekaAsamasi({ havuz }: { havuz: number }) {
const dar = havuz < 24;
return (
<div className="border-t border-slate-100 pt-4">
<p className="text-xs font-semibold text-slate-500">
Sonra sıra yapay zekâda
</p>
<p className="mt-1.5 text-xs leading-5 text-slate-600">
Seçimlerinden geriye kalan{" "}
<span className="font-bold tabular-nums text-slate-900">
{havuz.toLocaleString("tr-TR")} programlık havuz
</span>{" "}
yapay zekâya gider; o da bu havuzdan tam 24 tercih seçer ve şu iskelete
oturtur:
</p>
{/* 24 hücrelik liste şeridi — renk + metin birlikte (renk tek başına
anlam taşımaz) */}
<div
role="img"
aria-label="24 tercihlik listenin yapısı: en üstte yaklaşık 5 hayal, ortada 13 dengeli, sonda 6 garanti tercih."
className="mt-3"
>
<div className="flex gap-1">
{LISTE_ISKELETI.flatMap((b) =>
Array.from({ length: b.adet }, (_, i) => (
<span
key={`${b.dilim}-${i}`}
className={`h-6 min-w-0 flex-1 rounded ${b.renk}`}
/>
)),
)}
</div>
<div className="mt-1.5 flex justify-between text-[11px] text-slate-500">
<span>
üstte 4–6 <span className="font-semibold text-red-600">hayal</span>
</span>
<span>
ortada 12–14{" "}
<span className="font-semibold text-amber-600">dengeli</span>
</span>
<span>
sonda 5–7{" "}
<span className="font-semibold text-emerald-600">garanti</span>
</span>
</div>
</div>
<ul className="mt-3 space-y-1 text-xs leading-5 text-slate-600">
<li>
· Havuzda olmayan bir bölümü yazamaz — listedeki her satırın kimliği
havuzla karşılaştırılır, uymayan liste yeniden ürettirilir.
</li>
<li>
· Her satıra tek cümlelik gerekçe ve bir risk notu ekler; sıraya neyi
neden koyduğu görünür.
</li>
<li>
· Önceliklerin (iş garantisi, maaş, prestij…) hangi programın öne
geçeceğini belirler.
</li>
<li>
· Havuz 24&apos;ün altına düşerse filtreler adım adım gevşetilir —
önce il, sonra alan — ve bu, listende açıkça belirtilir.
</li>
</ul>
{dar ? (
<p className="mt-3 rounded-lg bg-amber-50 px-3 py-2 text-xs leading-5 text-amber-700">
Bu seçimle havuz 24&apos;ün altına düştü. Gerçek sihirbaz bu durumda
filtreleri adım adım gevşetir — önce il, sonra alan tercihi esnetilir
— ve bunu listende açıkça belirtir; liste her zaman 24&apos;e
tamamlanır.
</p>
) : null}
</div>
);
}
/** Kademeli filtre hunisi: gerçek sihirbaz mantığının oynanabilir kopyası. */
export function HuniCanli() {
const {
veri,
yukleniyor,
kategori,
il,
tip,
kategoriFacet,
ilFacet,
kategoriSec,
ilSec,
tipSec,
} = useDemo();
const toplam = veri.facetler.toplam;
const kategoriAdet =
kategori != null
? (veri.facetler.kategoriler.find((k) => k.ad === kategori)?.adet ?? 0)
: null;
const ilAdet =
il != null && kategoriFacet
? (kategoriFacet.iller.find((i) => i.il === il)?.adet ?? 0)
: null;
const tipAdet =
tip != null && ilFacet
? (ilFacet.uniturler.find((u) => u.grup === tip)?.adet ?? 0)
: null;
const kategoriSecenekleri = veri.facetler.kategoriler.slice(0, 6).map((k) => ({
anahtar: k.ad,
etiket: k.ad,
adet: k.adet,
}));
const ilSecenekleri = (kategoriFacet?.iller ?? []).slice(0, 6).map((i) => ({
anahtar: i.il,
etiket: i.il.toLocaleLowerCase("tr-TR"),
adet: i.adet,
}));
const tipSecenekleri = (ilFacet?.uniturler ?? []).map((u) => ({
anahtar: u.grup,
etiket: u.grup === "devlet" ? "Devlet" : "Vakıf",
adet: u.adet,
}));
// Yapay zekâya giden havuz: huninin en derin (en son seçilmiş) katmanı
const havuz = tipAdet ?? ilAdet ?? kategoriAdet ?? toplam;
return (
<div
className={`mt-6 space-y-4 rounded-2xl border border-slate-200 bg-white p-5 ${
yukleniyor ? "animate-pulse opacity-60" : ""
}`}
>
{/* Huni çubukları — her seçim bir çubuk daha ekler */}
<div className="space-y-2">
<div className="flex items-center gap-3">
<span className="w-6 shrink-0" />
<HuniCubugu
etiket="Sıralamanla açılan tüm programlar"
adet={toplam}
oran={1}
/>
</div>
{kategori != null && kategoriAdet != null ? (
<div className="flex items-center gap-3">
<span className="w-6 shrink-0 text-right text-xs font-bold text-slate-400">
1.
</span>
<HuniCubugu
etiket={`“${kategori}” seçince`}
adet={kategoriAdet}
oran={toplam > 0 ? kategoriAdet / toplam : 0}
/>
</div>
) : null}
{il != null && ilAdet != null ? (
<div className="flex items-center gap-3">
<span className="w-6 shrink-0 text-right text-xs font-bold text-slate-400">
2.
</span>
<HuniCubugu
etiket={`+ “${il.toLocaleLowerCase("tr-TR")}” seçince`}
adet={ilAdet}
oran={toplam > 0 ? ilAdet / toplam : 0}
/>
</div>
) : null}
{tip != null && tipAdet != null ? (
<div className="flex items-center gap-3">
<span className="w-6 shrink-0 text-right text-xs font-bold text-slate-400">
3.
</span>
<HuniCubugu
etiket={`+ “${tip === "devlet" ? "Devlet" : "Vakıf"}” seçince`}
adet={tipAdet}
oran={toplam > 0 ? tipAdet / toplam : 0}
/>
</div>
) : null}
</div>
{/* Seçim adımları — sihirbazın küçük, oynanabilir hali */}
<div className="space-y-3 border-t border-slate-100 pt-4">
<div>
<p className="mb-1.5 text-xs font-semibold text-slate-500">
1. Bir alan seç
</p>
<SecimCipleri
secenekler={kategoriSecenekleri}
secili={kategori}
onSec={kategoriSec}
/>
</div>
{kategori != null ? (
<div>
<p className="mb-1.5 text-xs font-semibold text-slate-500">
2. Bir il seç{" "}
<span className="font-normal text-slate-400">
(iller artık yalnızca “{kategori}” programlarını sayıyor)
</span>
</p>
{ilSecenekleri.length > 0 ? (
<SecimCipleri
secenekler={ilSecenekleri}
secili={il}
onSec={ilSec}
/>
) : (
<p className="text-xs text-slate-400">Yükleniyor…</p>
)}
</div>
) : null}
{kategori != null && il != null ? (
<div>
<p className="mb-1.5 text-xs font-semibold text-slate-500">
3. Üniversite tipi seç{" "}
<span className="font-normal text-slate-400">
(sayılar hem alanı hem ili hesaba katıyor)
</span>
</p>
{tipSecenekleri.length > 0 ? (
<SecimCipleri
secenekler={tipSecenekleri}
secili={tip}
onSec={(t) => tipSec(t as "devlet" | "vakif" | null)}
/>
) : (
<p className="text-xs text-slate-400">Yükleniyor…</p>
)}
</div>
) : null}
</div>
<YapayZekaAsamasi havuz={havuz} />
</div>
);
}

View File

@@ -0,0 +1,189 @@
import type { Metadata } from "next";
import Link from "next/link";
import { ArrowRight } from "lucide-react";
import { Parallax } from "@/components/parallax";
import { PagePixelDivider } from "@/components/pixel-decor";
import { dilimAra, rankWindowFacets, type DilimKey } from "@/lib/db";
import {
DemoKumanda,
DilimSeridiCanli,
HuniCanli,
SiralamaDemo,
type DemoVeri,
} from "./demo";
export const metadata: Metadata = {
title: "Meraklısına: KolayTercih nasıl çalışır?",
alternates: { canonical: "/meraklisina" },
description:
"Sıralamanı girdiğinde arka planda ne oluyor? Dilimler, risk renkleri ve sihirbazın adım adım daralan filtreleri — öğrenci diliyle, kendi sıralamanla deneyebileceğin canlı görsellerle.",
};
/**
* Algoritmanın öğrenci diline çevrilmiş anlatımı. Teknik detay (SQL, çarpan
* mutfağı) bilerek verilmez; amaç güven: veri gerçek, kurallar şeffaf.
* Görseller canlıdır: kullanıcı sıralamasını girer, dilim şeridi ve filtre
* hunisi o sıralamanın gerçek sayılarıyla güncellenir (bkz. demo.tsx).
* Diyagramlar ürünün risk renk dilini kullanır (yeşil/sarı/kırmızı) ve her
* bölge metinle de etiketlenir — renk tek başına anlam taşımaz.
*/
// Demo ilk açılışta bu sıralamayla dolu gelir; SSR'da gerçek veriyle render
// edilir ki kullanıcı girmeden de sayfa anlamlı olsun.
const VARSAYILAN_SIRA = 100_000;
export default function MeraklisinaPage() {
const dilimToplam = Object.fromEntries(
(["hayal", "dengeli", "garanti"] as DilimKey[]).map((d) => [
d,
dilimAra(VARSAYILAN_SIRA, "say", d, { limit: 0 }).toplam,
]),
) as Record<DilimKey, number>;
const baslangicVeri: DemoVeri = {
facetler: rankWindowFacets(VARSAYILAN_SIRA, "say"),
dilimToplam,
};
return (
<main className="mx-auto w-full max-w-2xl px-4 py-16">
<Parallax fromStart strength={10}>
<p className="text-sm font-semibold tracking-wide text-primary">
Meraklısına
</p>
<h1 className="mt-1 font-heading text-3xl font-bold">
Sıralamanı girince arka planda ne oluyor?
</h1>
<p className="mt-3 text-slate-600">
Sihir yok, kara kutu yok: KolayTercih&apos;in önerdiği her satır resmî
YÖK Atlas verisinden gelir ve hangi kurala göre önüne geldiği bellidir.
Bu sayfa o kuralları öğrenci diliyle anlatır — üstelik görseller
canlı: kendi sıralamanı gir, sayılar sana göre değişsin.
</p>
</Parallax>
<PagePixelDivider seed={73} className="mt-6" />
<SiralamaDemo
baslangicSira={VARSAYILAN_SIRA}
baslangicVeri={baslangicVeri}
>
<Parallax
fromStart
strength={4}
className="mt-8 space-y-10 text-sm leading-7 text-slate-700"
>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
1. Her şey taban sıralamasıyla başlar
</h2>
<p className="mt-2">
Bir bölümün <strong>taban sıralaması</strong>, geçen yıl o bölüme
yerleşen <em>son</em>{" "}
öğrencinin Türkiye sıralamasıdır. Senin sıralaman bu sayıdan
küçükse (yani daha iyiysen), geçen yılın koşullarında o bölüme
yerleşebilirdin demektir. Sistemde her programın en güncel taban
sıralaması kayıtlıdır; bir bölümün 2025 verisi henüz oluşmamışsa
bir önceki yılınki kullanılır.
</p>
</section>
<DemoKumanda />
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
2. Programlar üç dilime ayrılır
</h2>
<p className="mt-2">
Sıralamanı girdiğinde tüm programlar senin konumuna göre üç kümeye
ayrılır: tabanı senden <strong>daha iyi</strong> olanlar{" "}
<span className="font-semibold text-red-600">Hayal</span> (şansını
denediğin satırlar), tabanı sıralamana{" "}
<strong>yakın</strong> olanlar{" "}
<span className="font-semibold text-amber-600">Dengeli</span>{" "}
(listenin bel kemiği — sıralamanın yaklaşık yüzde kırk fazlasına
kadar pay bırakılır), tabanı{" "}
<strong>belirgin şekilde altında</strong> kalan her şey ise{" "}
<span className="font-semibold text-emerald-600">Garanti</span>{" "}
dilimidir.
</p>
<DilimSeridiCanli />
<p className="mt-4">
Garanti diliminin bir sonu yok: 87. sıradaki bir adayın da 500
bininci sıradaki bir adayın da ulaşabildiği <em>bütün</em>{" "}
programlar listededir. Liste sana en yakın tabandan başlar; aşağı
indikçe ve &ldquo;Daha fazla göster&rdquo;e bastıkça senden
uzaklaşan seçenekler gelir. Böylece ilk gördüklerin her zaman en
isabetli adaylardır ama hiçbir seçenek senden saklanmaz.
</p>
</section>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
3. Risk renkleri her yerde aynı dili konuşur
</h2>
<p className="mt-2">
Tabloda, haritada ve yapay zekâ listesinde gördüğün nokta ve
renkler tek bir kurala bağlıdır:{" "}
<span className="font-semibold text-emerald-600">yeşil</span>{" "}
tabanı sıralamanın belirgin altında (güvenli),{" "}
<span className="font-semibold text-amber-600">sarı</span>{" "}
sıralamana yakın (az riskli),{" "}
<span className="font-semibold text-red-600">kırmızı</span>{" "}
tabanı senden iyi (riskli). Renk hangi sayfada olursa olsun aynı
hesaptan çıkar; bir satır sekme değiştirdi diye renk değiştirmez.
</p>
</section>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
4. Sihirbaz süzer, yapay zekâ kurar
</h2>
<p className="mt-2">
&ldquo;Listemi oluştur&rdquo; sihirbazındaki üç adım birbirinden
bağımsız değildir. İlk adımda yalnızca{" "}
<strong>sıralamanla ulaşabildiğin</strong>{" "}
alanlar listelenir; ikinci adımdaki iller, seçtiğin alanlardaki
program sayısına göre yeniden hesaplanır; üçüncü adımdaki
devlet/vakıf sayıları da hem alan hem il seçimini hesaba katar.
Adımlar bitince elde kalan gerçek programlar bir{" "}
<strong>aday havuzu</strong>{" "}
olur ve yapay zekâya öyle gider: ona boş bir sayfa değil, bu havuz
verilir. Aşağıda kendin dene — her seçimin havuzu nasıl
daralttığını ve havuzun 24&apos;lük listeye nasıl dönüştüğünü huni
canlı gösterir.
</p>
<HuniCanli />
</section>
<section>
<h2 className="font-heading text-lg font-bold text-slate-900">
5. Dürüst olalım: bu bir tahmin aracıdır
</h2>
<p className="mt-2">
Tüm bu hesaplar <strong>geçen yılların</strong>{" "}
yerleştirme sonuçlarına dayanır. Kontenjanlar, tercih davranışları
ve puanlar her yıl değişir; geçen yıl &ldquo;garanti&rdquo;
görünen bir bölüm bu yıl dolabilir. Bu yüzden satırlarda son beş
yılın taban seyrini de gösteririz — çizgi yukarı tırmanıyorsa
bölüm zorlaşıyor demektir. KolayTercih karar <em>destek</em>{" "}
aracıdır; listenin son hâli ve sorumluluğu her zaman sana aittir.
</p>
</section>
<div className="rounded-2xl border border-slate-200 bg-white p-6 text-center">
<p className="font-heading text-base font-bold text-slate-900">
Kuralları öğrendin — şimdi kendi sıralamanla dene.
</p>
<Link
href="/"
className="mt-3 inline-flex items-center gap-1.5 rounded-full bg-orange-500 px-5 py-2.5 text-sm font-medium text-white transition-colors duration-200 hover:bg-orange-600"
>
Sıralamanı gir
<ArrowRight className="size-4" aria-hidden />
</Link>
</div>
</Parallax>
</SiralamaDemo>
</main>
);
}