feat(ui): 11 Ekim gece işi — program ayrıntıda açılan gösterge kareleri, veri akışı sahnesi, haritada kenar eritme

- program-ayrinti: kontenjan türleri, netler ve mezun istihdamı kapalıyken
  gösterge karesi; dokununca kare panele dönüşüp bölümün tamamını açar.
  Kontenjan türü satırlarına "kime açık" alt satırı (KONTENJAN_TURU_KIME).
- veri-akisi: üstte öğrencinin üç seçimi, altta YÖK Atlas'ın üç verisi,
  ortada DanışmanlaKonuş çekirdeği; kayıtlar kıvrımlı yollardan çekirdeğe
  akar (kt-akis-* kuralları globals.css'te).
- tercih-haritasi: il'e yakınlaşınca kenarlar iki katlı mask'la erir; tam
  görünümde mask yok, ülke uçları solmaz.
- DESIGN.md: ilgili bölümler güncellendi (§4.19, §4.28).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-10-11 01:30:59 +03:00
parent 8e2790ec6f
commit 52f565ea4a
6 changed files with 931 additions and 208 deletions

View File

@@ -455,39 +455,277 @@
}
/* Veri akışı (veri-akisi.tsx, DESIGN.md §4.28): kare, çizgi boyunca karodan
merkeze akar. Uç noktalar satır içi --x1/--y1/--x2/--y2 ile gelir (SVG
içinde px = viewBox birimi). Yalnız ekrandayken oynar. */
@keyframes kt-akis {
/* Veri akışı (veri-akisi.tsx, DESIGN.md §4.28). Üstte üç kutu, ortada
çekirdek, altta üç kutu; yollar SVG, kayıtlar HTML (yalnız translate /
scale / opacity oynar).
Geometri: yatay eksen kabın eninin yüzdesi (kap `@container`, x'ler cqw),
dikey eksen rem: kutular 5rem, çekirdek 10,5–14,5rem arası, sahne 25rem.
Kaydın iki ucu satır içi gelir (--x0/--y0 port, --x1/--y1 çekirdek kenarı).
Eğri: yol, iki ucu dikey çıkan S kıvrımıdır — C(x0 ym, x1 ym), ym orta
yükseklik. Bu eğride parametre zamanla doğrusal ilerlerken x tam olarak
cubic-bezier(1/3, 0, 2/3, 1), y tam olarak cubic-bezier(1/3, .5, 2/3, .5)
izler. Kayıt bu yüzden iç içe iki öğedir: dıştaki yatay, içteki dikey
kayar; ikisi birlikte çizginin tam üstünde yürür, ölçüm ya da JS gerekmez.
Bu iki eğri hareket zevki değil yolun geometrisidir (--akis-x / --akis-y);
yol değişirse onlar da değişir. İz, aynı iki kaymayı --ek kadar gecikmeyle
yapan iki küçük noktadır; böylece o da çizginin üstünde kalır.
Döngü 6 sn, altı kayıt 1 sn arayla (--g satır içi gecikme). Bir kaydın ömrü:
0 → 20 % yol (1,2 sn)
0 → 4 % kalkış: porttan küçük ve soluk çıkar (ölçek 0,6 → 1)
13 → 17 % işlenir: içi boş nokta şişer (1 → 1,2), dolar ve piksel kareye döner
15 → 19 % iz çekirdek kenarına varmadan söner
20 → 23 % kayıt kenarda sönerek içeri alınır
20 → 32 % çekirdek nabzı: çerçeve kaydın renginde yanar, genişleyip söner
0 → 10 % kaynak vurgusu: kutunun çerçevesi ve port kısa bir an yanar
Eğri öğenin `animation` kısayolundadır, keyframe'in içinde değil: tarayıcı
`@keyframes` içindeki `animation-timing-function: var(--…)` değerini çözmez
(doğrusala düşer). Kısayoldaki eğri her durak aralığına ayrı ayrı uygulanır.
Yalnız ekrandayken oynar (data-oynuyor). Hareketi azalt'ta her yolda bir
ham kayıt durağan durur. */
.kt-akis-sahne {
height: 25rem;
--akis-x: cubic-bezier(0.3333, 0, 0.6667, 1);
--akis-y: cubic-bezier(0.3333, 0.5, 0.6667, 0.5);
}
.kt-akis-kayit-kap {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
pointer-events: none;
}
/* Port: yolun kutudan çıktığı nokta; kayıt buradan doğar. */
.kt-akis-port {
position: absolute;
top: -3.5px;
left: -3.5px;
width: 7px;
height: 7px;
border: 1px solid var(--color-slate-300);
border-radius: 9999px;
background: var(--card);
translate: var(--x0) var(--y0);
}
.kt-akis-port > .kt-akis-vurgu {
position: absolute;
inset: 1px;
border-radius: inherit;
background: var(--renk);
}
.kt-akis-x,
.kt-akis-y {
position: absolute;
top: 0;
left: 0;
}
.kt-akis-x {
translate: var(--x0) 0;
animation: kt-akis-x 6s var(--akis-x) calc(var(--g, 0s) + var(--ek, 0s)) infinite;
}
.kt-akis-y {
translate: 0 var(--y0);
animation: kt-akis-y 6s var(--akis-y) calc(var(--g, 0s) + var(--ek, 0s)) infinite;
}
/* İz noktası: kayıttan küçük, dolu ve soluk. */
.kt-akis-iz {
position: absolute;
top: -2px;
left: -2px;
width: 4px;
height: 4px;
border-radius: 9999px;
background: var(--renk);
opacity: 0;
animation: kt-akis-iz 6s var(--egri-standart) calc(var(--g, 0s) + var(--ek, 0s)) infinite;
}
/* Ham kayıt: içi boş nokta. */
.kt-akis-kare {
position: absolute;
top: -5px;
left: -5px;
box-sizing: border-box;
width: 10px;
height: 10px;
border: 1.5px solid var(--renk);
border-radius: 50%;
background: var(--card);
opacity: 0;
scale: 0.6;
animation: kt-akis-kare 6s var(--egri-standart) var(--g, 0s) infinite;
}
/* İşlenmiş kayıt: aynı kutunun dolusu, üstüne solarak gelir. */
.kt-akis-dolgu {
position: absolute;
inset: 0;
border-radius: inherit;
background: var(--renk);
opacity: 0;
animation: kt-akis-dolgu 6s var(--egri-standart) var(--g, 0s) infinite;
}
.kt-akis-nabiz,
.kt-akis-vurgu {
border-color: var(--renk);
opacity: 0;
}
.kt-akis-nabiz {
animation: kt-akis-nabiz 6s var(--egri-guclu-cikis) var(--g, 0s) infinite;
}
.kt-akis-vurgu {
animation: kt-akis-vurgu 6s var(--egri-standart) var(--g, 0s) infinite;
}
@keyframes kt-akis-x {
0% {
translate: var(--x1) var(--y1);
translate: var(--x0) 0;
}
20%,
100% {
translate: var(--x1) 0;
}
}
@keyframes kt-akis-y {
0% {
translate: 0 var(--y0);
}
20%,
100% {
translate: 0 var(--y1);
}
}
@keyframes kt-akis-iz {
0%,
3% {
opacity: 0;
}
12%,
82% {
opacity: 1;
7%,
15% {
opacity: 0.4;
}
19%,
100% {
translate: var(--x2) var(--y2);
opacity: 0;
}
}
.kt-akis-kare {
translate: var(--x1) var(--y1);
opacity: 0;
animation: kt-akis 2.4s cubic-bezier(0.45, 0, 0.55, 1) infinite;
@keyframes kt-akis-kare {
0% {
scale: 0.6;
opacity: 0;
border-radius: 50%;
}
4%,
13% {
scale: 1;
opacity: 1;
border-radius: 50%;
}
17% {
scale: 1.2;
opacity: 1;
border-radius: 25%;
}
20% {
scale: 1;
opacity: 1;
border-radius: 25%;
}
23%,
100% {
scale: 0.8;
opacity: 0;
border-radius: 25%;
}
}
@keyframes kt-akis-dolgu {
0%,
13% {
opacity: 0;
}
17%,
100% {
opacity: 1;
}
}
/* Çekirdek geniş bir dikdörtgen: yatayda az, dikeyde çok büyür ki halka her
yanda aynı kadar (≈6 px) açılsın. */
@keyframes kt-akis-nabiz {
0%,
19.9% {
scale: 1;
opacity: 0;
}
20% {
scale: 1;
opacity: 0.5;
}
32%,
100% {
scale: 1.06 1.2;
opacity: 0;
}
}
@keyframes kt-akis-vurgu {
0% {
opacity: 0;
}
2% {
opacity: 0.5;
}
10%,
100% {
opacity: 0;
}
}
/* Oynatma durumu `animation` kısayolundan sonra gelmeli (kısayol sıfırlar). */
:is(.kt-akis-x, .kt-akis-y, .kt-akis-iz, .kt-akis-kare, .kt-akis-dolgu, .kt-akis-nabiz, .kt-akis-vurgu) {
animation-play-state: paused;
}
[data-oynuyor] .kt-akis-kare {
[data-oynuyor]
:is(.kt-akis-x, .kt-akis-y, .kt-akis-iz, .kt-akis-kare, .kt-akis-dolgu, .kt-akis-nabiz, .kt-akis-vurgu) {
animation-play-state: running;
}
@media (prefers-reduced-motion: reduce) {
.kt-akis-kare {
:is(.kt-akis-x, .kt-akis-y, .kt-akis-iz, .kt-akis-kare, .kt-akis-dolgu, .kt-akis-nabiz, .kt-akis-vurgu) {
animation: none;
}
/* Durağan kare: yolun ortasında ham kayıt — bilgi eksilmez. */
.kt-akis-x {
translate: calc((var(--x0) + var(--x1)) / 2) 0;
}
.kt-akis-y {
translate: 0 calc((var(--y0) + var(--y1)) / 2);
}
.kt-akis-kare {
opacity: 1;
scale: 1;
}
}
/* Tema geçişi (DESIGN.md §2.3, lib/tema-gecisi.ts): yeni tema header'daki