feat(tasarim): üniversite sayfası "şişko ve sade" dile göre baştan, DESIGN.md know-how'ı

Üniversite sayfası (canlı referans ekran /universite/ankara-universitesi):
- Program listesi: ad kesilmez/sarar, telefonda taban sıra alt satıra iner,
  satır butonları 44 px, tür çipi okunur boyda
- Başlık bloğu lg altında ortalı (logo başlığın üstünde), kimlik hapları
  (Devlet/Ankara) navbar ölçüsünde, ikon + metin
- Harita yanında 4 özet kartı (OzetKart): sayı solda iri, ikon sağda;
  4. kart URAP Türkiye sırası + piksel sıra şeridi (PixelSira)
- Akademik göstergeler (URAP + YÖK İstatistik) sayfadan "Akademik
  göstergeler ›" satırının açtığı alt sayfaya taşındı: kartsız, ortalı,
  masonry gösterge kareleri, tek ekrana sığar
- Hover tek turuncu (orange-500); liste satırı adı mavi kalır
- Üst çubuk başlık geçişi (NavBaslik): h1 kaydırılınca üst çubukta logo +
  ad belirir; bölüm sayfasında da (yalnız ad)

Tasarım dili:
- DESIGN.md: temel his (§1.1), hover kuralı (§2.1), yazı alt sınırları,
  yeni tek kaynak parçalar (§4.8–4.15), lg altı ortala (§5.2), reddedilen
  denemeler (§7), ölç-tahmin-etme ve tuzaklar (§9)
- Denetim: gösterge karesi renk istisnası (bg-indigo-500, bg-green-600) ve
  site taraması için dört uyarı (minik-yazi, buyuk-harf-etiket, mavi-hover,
  iri-sayi-tabular)

Not: universite-icerik.tsx'teki akademik göstergeler bölümü (URAP/YÖK
kartları) Bilal'in commit'lenmemiş işiydi; tasarım değişiklikleriyle aynı
dosyada iç içe olduğu için bu commit'e girdi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-09-24 00:01:41 +03:00
parent 5df0af0d38
commit 6a9af19ef2
11 changed files with 1092 additions and 202 deletions

View File

@@ -298,6 +298,65 @@ export function PixelCorner({ className }: { className?: string }) {
);
}
/**
* Bir sıranın yerini tek satır piksel şeridinde gösteren sessiz gösterge
* (ör. URAP'ta 198 üniversite içinde 5.). Şerit soldan (1.) sağa
* (sonuncu) dilimlere bölünür; sıranın düştüğü dilim hero'daki şehirler
* gibi turuncu yanar, geri kalanı hero dokusunda durur ve imleç fırçasına
* katılır. Dekoratiftir: anlamı yanındaki metin taşır (renk tek başına
* anlam taşımaz), bu yüzden aria-hidden.
*/
export function PixelSira({
sira,
toplam,
hucre = 8,
zemin = "acik",
className,
}: {
sira: number;
toplam: number;
hucre?: number;
/** "koyu": renkli dolu zemin üstünde (ör. turuncu gösterge karesi) —
* işaret beyaz yanar, doku zeminin üstünde beyaz kalır. */
zemin?: "acik" | "koyu";
className?: string;
}) {
const svgRef = useRef<SVGSVGElement>(null);
// Isı fırçası turuncuya ısıtır; turuncu zeminde görünmez, orada kapalı.
usePixelHeat(svgRef, { radius: zemin === "koyu" ? 0 : 28 });
const yer = Math.min(
hucre - 1,
Math.max(0, Math.floor(((sira - 1) / toplam) * hucre)),
);
return (
<svg
ref={svgRef}
viewBox={`0 0 ${hucre * CELL} ${CELL}`}
aria-hidden="true"
focusable="false"
className={cn("h-3.5 w-auto shrink-0 text-primary", className)}
>
{Array.from({ length: hucre }, (_, i) =>
i === yer ? (
<rect
key={i}
x={i * CELL + INSET}
y={INSET}
width={DOT}
height={DOT}
rx={2}
className={zemin === "koyu" ? "fill-white" : "fill-orange-500"}
fillOpacity={zemin === "koyu" ? 1 : 0.85}
/>
) : (
<g key={i}>{fixedPixel(i * CELL, 0, opacityFor(i, 0) + 0.1)}</g>
),
)}
</svg>
);
}
/** Bölüm başlıklarının üstünde duran piksel imzalı eyebrow rozeti. */
export function SectionEyebrow({
children,

View File

@@ -10,23 +10,34 @@ export function SiteHeader() {
<header className="sticky top-4 z-50 mt-4 sm:top-6 sm:mt-6 print:hidden">
{/* lg altında 2 satır: logo+UserNav / sıralama+ara. lg+: tek satır, ortada nav. */}
<div className="relative mx-auto flex max-w-6xl flex-wrap items-center justify-between gap-x-2 gap-y-2 px-3 sm:gap-x-3 sm:px-4 lg:h-16 lg:flex-nowrap">
<Link
href="/"
aria-label="KolayTercih"
className="group order-1 flex min-w-0 shrink items-center font-bricolage"
>
{/* Inline animasyonlu mark: Link'teki `group` sayesinde hover'da
kareler danışman panelindeki nabız animasyonuyla canlanır. */}
<AnimasyonluMark sadeceHover className="size-8 sm:size-11" />
<span className="truncate">
<span className="text-lg font-light tracking-tighter sm:text-3xl">
Kolay
{/* Sayfa başlığı yuvası (NavBaslik): bir sayfa <html>'e
data-nav-baslik koyunca yazı logosu yukarı kayıp söner, yuvaya
sayfanın başlığı (ör. üniversite logosu + adı) gelir. Yuva Link'in
dışında: içine gelen düğme bağlantı içinde bağlantı olmasın.
lg'de ortadaki nav hapına taşmasın diye genişliği sınırlı. */}
<div className="relative order-1 flex min-w-0 flex-1 items-center lg:flex-none">
<Link
href="/"
aria-label="KolayTercih"
className="group flex min-w-0 shrink items-center font-bricolage"
>
{/* Inline animasyonlu mark: Link'teki `group` sayesinde hover'da
kareler danışman panelindeki nabız animasyonuyla canlanır. */}
<AnimasyonluMark sadeceHover className="size-8 sm:size-11" />
<span className="truncate transition-[opacity,translate] duration-300 ease-out in-data-[nav-baslik]:pointer-events-none in-data-[nav-baslik]:-translate-y-2 in-data-[nav-baslik]:opacity-0 motion-reduce:transition-opacity">
<span className="text-lg font-light tracking-tighter sm:text-3xl">
Kolay
</span>
<span className="text-lg font-semibold tracking-tighter sm:text-3xl">
Tercih
</span>
</span>
<span className="text-lg font-semibold tracking-tighter sm:text-3xl">
Tercih
</span>
</span>
</Link>
</Link>
<div
id="nav-baslik-yuvasi"
className="pointer-events-none absolute inset-y-0 right-0 left-9 flex min-w-0 items-center sm:left-12 lg:right-auto lg:w-52 xl:w-72"
/>
</div>
<KatalogArama rehberler={getRehberAramaKayitlari()} />
{/* UserNav session+DB bekler; Suspense dışına taşarsa tüm kabuk bloklanır */}
<Suspense fallback={<UserNavFallback />}>