diff --git a/docs/tasarim/DESIGN.md b/docs/tasarim/DESIGN.md index 27d8b07..b3e4df4 100644 --- a/docs/tasarim/DESIGN.md +++ b/docs/tasarim/DESIGN.md @@ -369,9 +369,11 @@ Parçalar: `AltSayfa` (kök) · `AltSayfaTetik` · `AltSayfaIcerik` (perde + yü `AltSayfaSurukle` (kaydırmayan başlık alanı) · `AltSayfaBaslik` / `AltSayfaAciklama` · `AltSayfaKapat`. Yüzey sınıfı bileşenin içindedir (`rounded-t-3xl border border-b-0 border-slate-200 bg-card shadow-2xl sm:max-w-2xl`, tavan `92dvh`); kullanım yerinde kap sınıfı -**yazılmaz**. Boy içeriğe göredir. `duraklar` (ekran yüksekliğinin oranı) yalnız uzun, kaydırılan -içerikte verilir: program ayrıntısı `[0.6, 0.92]` ile %60'ta açılır, yukarı çekince ya da -kaydırınca tam boya çıkar (§4.19). İçinde kendi sürüklemesi olan öğe (sıralama tutamağı) +**yazılmaz**. Boy içeriğe göredir. `duraklar` (ekran yüksekliğinin oranı) bugün hiçbir yerde +verilmez; her çekmece varsayılan tek durakta (0,92) açılır. Program ayrıntısı 7 Eki 2026'ya +kadar `[0.6, 0.92]` ile %60'ta açılıyordu; kısık durakta gövde kaydırılamadığı ve veri gelince +boy değiştiği için "takılmış" görünüyordu, tek durağa döndü (§4.19). Yeni bir çift durak +istiyorsan açılışta içerik boyunun sabit olduğundan emin ol. İçinde kendi sürüklemesi olan öğe (sıralama tutamağı) `data-alt-sayfa-yoksay` alır. Bildirimdeki düğmeye basmak sayfayı kapatmaz. Hareketi azalt: kayma yok, yalnız opaklık. @@ -638,8 +640,7 @@ sihirbaz modalı içindir; yeni bir ayrıntı için `Dialog` açılmaz. tek çekmece açar; veri `/api/program-ayrinti`. Sıra: başlık = program adı, bağlam = üniversite · il · fakülte; **künye hapları** (§4.12 ölçüsü, link değil: süre + tür, dil, öğretim türü (örgün değilse), burs/ücret, akreditasyon, baraj, öğretim üyesi sayısı, - yalnız kız/erkek koşulu, kampüs ilçesi — yalnız verisi olanlar); "Yıllara göre" tablosu - (yıl, taban sıra, puan, kontenjan, yerleşen); "Kontenjan türleri (yıl)" `dl` satırları + yalnız kız/erkek koşulu, kampüs ilçesi — yalnız verisi olanlar); "Kontenjan türleri (yıl)" `dl` satırları (yalnız >0 olanlar; özel kontenjanın ayrı taban sırasının elimizde olmadığı notu); "Son yerleşenin netleri" (eski tablo + OBP katsayısı satırı; 0,18 = meslek lisesi ek puanı notu); "Yerleşme koşulları (N)" yerel `details` ile kapalı başlar; "Mezun @@ -648,6 +649,16 @@ sihirbaz modalı içindir; yeni bir ayrıntı için `Dialog` açılmaz. süs ayraç yok, kart yok. İçerik uzun olduğu için çekmece **kaydırılır** (liste çekmecesi gibi; §4.10 tek ekran kuralının ikinci istisnası). Açık listem satırında aynı çekmece `varyant="metin"` ile "Program ayrıntısı" metin düğmesinden açılır ("Haritada gör" kalıbı). +- **7 Eki 2026 — tek durak, sabit iskelet, logo → içerik:** çekmece varsayılan tek durakta + (0,92) açılır; `duraklar`/`ilkDurak` verilmez. Yükleme iskeleti `min-h-[70dvh]` sarmalda + açılır ki veri gelince sayfa yalnız büyüsün, konum sıçramasın. "Yıllara göre" yıl tablosu + kaldırıldı (API `gecmis` alanı duruyor; backlog). Açılış koreografisi `AcilisSahnesi` + kartsız modu (`src/components/ui/acilis-sahnesi.tsx`, `hazir={durum === "hazir"}`): veri + gelince başlığın altında üç logo karesi (`data-logo` kabı, `relative mx-auto h-16 w-16`) + belirir, kısa durur, sönerek kaybolur (scale 0.6 + opacity 0; kap sıfır boya iner), içerik + blokları (`data-sonra`: künye, kontenjan türleri, netler, koşullar, istihdam, üniversite, + kaynak) 0,08 s arayla bulanıktan netleşir; toplam ≈ 1 s. Hareketi azalt: logo yok, 0,25 s + solma (§6). Akademik göstergeler çekmecesi (§4.9) aynı bileşenin kartlı modunu kullanır. ### 4.20 Danışman sohbeti — `sohbet-client.tsx`, `arac-pilleri.tsx` Sohbet kabuğu **prompt-kit** bileşenleridir (`src/components/ui/`: `prompt-input`, `message`, diff --git a/src/features/katalog/components/program-ayrinti.tsx b/src/features/katalog/components/program-ayrinti.tsx index 8131e6c..9f8e439 100644 --- a/src/features/katalog/components/program-ayrinti.tsx +++ b/src/features/katalog/components/program-ayrinti.tsx @@ -3,13 +3,18 @@ // Program satırındaki "ayrıntı" düğmesi: programın tüm açık verisini alttan // açılan sayfada gösterir (DESIGN.md §4.10 çekmece, §4.19 program ayrıntı // çekmecesi). Veri /api/program-ayrinti'den gelir: künye (dil, öğretim türü, -// burs/ücret, akreditasyon, baraj, kadro, kampüs, cinsiyet koşulu), yıllara -// göre sıra/puan/kontenjan/yerleşen, kontenjan türleri, son yerleşenin -// netleri, yerleşme koşulları, TÜİK mezun istihdamı, üniversite özeti. +// burs/ücret, akreditasyon, baraj, kadro, kampüs, cinsiyet koşulu), kontenjan +// türleri, son yerleşenin netleri, yerleşme koşulları, TÜİK mezun istihdamı, +// üniversite özeti. API'nin `gecmis` (yıllara göre sıra/puan/kontenjan) +// alanı burada gösterilmez (Bilal, 7 Eki 2026: yıl tablosu kaldırıldı; +// backlog). Açılış: veri gelince logo kareleri belirir, söner, içerik +// bloklar hâlinde netleşir (AcilisSahnesi kartsız modu). // Kadın-erkek dağılımı program düzeyinde bilinçli olarak yok: YÖK Atlas 2026 // SPA'sına geçerken cinsiyet panelini yayından kaldırdı (bkz. scripts/detay.ts). // Çekmece içerik ağırlıklı olduğu için liste çekmecesi gibi kaydırılır (§4.10 -// tek ekran kuralının ikinci istisnası). +// tek ekran kuralının ikinci istisnası). Tek durak (varsayılan 0,92): çift +// durakla açılış, kısık durakta gövde kaydırılamadığı ve veri gelince boy +// değiştiği için takılmış görünüyordu (7 Eki 2026). import { SATIR_BASLIK, SATIR_DUGME_BOYU } from "@/components/liste-satiri"; import { useState } from "react"; @@ -45,6 +50,11 @@ import { AltSayfaBaslik, AltSayfaTetik, } from "@/components/ui/alt-sayfa"; +import { + AcilisSahnesi, + LOGO_SLOTLARI, + logoKareStili, +} from "@/components/ui/acilis-sahnesi"; import { Table, TableBody, @@ -163,13 +173,10 @@ export function ProgramAyrintiButonu({ )} {/* Alt sayfa kabı tek kaynak (alt-sayfa.tsx), çarpı §4.3. İçerik uzun: - sayfa ekranın %60'ında açılır (başlık + künye), yukarı çekince ya da - kaydırınca tam boya çıkar (§4.19). */} - e.stopPropagation()} - > + tek durakta tam boya açılır, gövde kaydırılır (§4.19). İskelet + min-h-[70dvh] ile açılır ki veri gelince sayfa yalnız büyüsün, + konum sıçramasın (alt-sayfa.tsx ResizeObserver). */} + e.stopPropagation()}> Kapat @@ -189,9 +196,12 @@ export function ProgramAyrintiButonu({ .join(" · ") : (universite ?? "Programın tüm açık verisi")} -
+ -
+
@@ -215,22 +225,31 @@ function AyrintiIcerik({ durum, veri }: { durum: Durum; veri: ProgramAyrintisi |

); } + // Sıra = AcilisSahnesi'nin `data-sonra` sırası: logo söner, bloklar + // yukarıdan aşağıya 0,08 s arayla netleşir. return ( <> + {/* Logo kareleri: sahne sırasında görünür, sönünce kap sıfır boya iner. */} +
+ {LOGO_SLOTLARI.map((slot) => ( + + ))} +
- -

Son yerleşenin netleri

-

- Bölüme en düşük puanla yerleşen adayın sınav netleri (YÖK Atlas). -

-
- +
+

Son yerleşenin netleri

+

+ Bölüme en düşük puanla yerleşen adayın sınav netleri (YÖK Atlas). +

+
+ +
-

+

Kaynaklar: YÖK Atlas (yerleştirme, kontenjan, netler, koşullar; {SON_YIL}{" "} yerleştirmesi), TÜİK (mezun istihdamı), URAP ve YÖK İstatistik (üniversite).

@@ -270,7 +289,7 @@ function Kunye({ veri }: { veri: ProgramAyrintisi }) { if (o?.ilce) haplar.push({ ikon: MapPin, metin: `${trBaslikDuzeni(o.ilce)} kampüsü` }); if (haplar.length === 0) return null; return ( -
    +
      {haplar.map((h) => (
    • @@ -281,59 +300,6 @@ function Kunye({ veri }: { veri: ProgramAyrintisi }) { ); } -function YillaraGore({ veri }: { veri: ProgramAyrintisi }) { - const satirlar = veri.gecmis.filter( - (g) => g.sira != null || g.puan != null || g.kontenjan != null || g.yerlesen != null, - ); - if (satirlar.length === 0) return null; - const sonYil = satirlar[0].yil; - const hucre = (yil: number) => - cn( - "py-2.5 text-right text-sm tabular-nums", - yil === sonYil ? "font-semibold text-slate-800" : "text-slate-500", - ); - return ( - <> -

      Yıllara göre

      -

      - Taban sırası (ve geniş ekranda puanı) o yıl yerleşen son adayınki; - kontenjan ve yerleşen o yılın yerleştirmesi. Sırası boş yıl: program o - yıl dolmadı ya da yoktu. -

      - - - - Yıl - Taban sıra - {/* Telefonda beş sütun 375 px'e sığmıyor (yatay kaydırma yok, §5.2.3): puan sm'den itibaren */} - Puan - Kontenjan - Yerleşen - - - - {satirlar.map((g) => ( - - - {g.yil} - - {g.sira != null ? sayi(g.sira) : "—"} - {g.puan != null ? ondalik(g.puan) : "—"} - {g.kontenjan != null ? sayi(g.kontenjan) : "—"} - {g.yerlesen != null ? sayi(g.yerlesen) : "—"} - - ))} - -
      - - ); -} - function KontenjanTurleriBolumu({ veri }: { veri: ProgramAyrintisi }) { const k = veri.kontenjanTurleri; if (!k) return null; @@ -341,7 +307,7 @@ function KontenjanTurleriBolumu({ veri }: { veri: ProgramAyrintisi }) { if (satirlar.length === 0) return null; const ozelVar = satirlar.some((t) => t !== "genel"); return ( - <> +

      Kontenjan türleri ({k.yil})

      {ozelVar @@ -362,7 +328,7 @@ function KontenjanTurleriBolumu({ veri }: { veri: ProgramAyrintisi }) {

      ))} - +
); } @@ -476,7 +442,7 @@ function NetlerIcerik({ netler }: { netler: ProgramNetSatiri[] }) { function Kosullar({ veri }: { veri: ProgramAyrintisi }) { if (veri.kosullar.length === 0) return null; return ( -
+
Yerleşme koşulları ({veri.kosullar.length}) Göster @@ -509,13 +475,13 @@ function Istihdam({ veri }: { veri: ProgramAyrintisi }) { if (parcalar.length === 0) return null; const ort = v.ortalama.istihdam != null ? ` Türkiye ortalaması %${ondalik(v.ortalama.istihdam)}.` : ""; return ( - <> +

Mezun istihdamı

{parcalar.join(", ")} (TÜİK {v.yil}, ülke geneli, {v.duzey === "lisans" ? "lisans" : "ön lisans"}{" "} mezunları; üniversiteye göre değişir, kırılım yok).{ort}

- +
); } @@ -529,7 +495,7 @@ function UniversiteOzeti({ veri }: { veri: ProgramAyrintisi }) { : null, ].filter(Boolean); return ( - <> +

Üniversite

{parcalar.join(" · ")}.{" "} @@ -540,6 +506,6 @@ function UniversiteOzeti({ veri }: { veri: ProgramAyrintisi }) { Üniversite sayfası

- +
); }