diff --git a/docs/tasarim/DESIGN.md b/docs/tasarim/DESIGN.md index 8e3d553..18df9ce 100644 --- a/docs/tasarim/DESIGN.md +++ b/docs/tasarim/DESIGN.md @@ -474,14 +474,20 @@ bulunulan şehir `border-primary bg-primary text-white` + `aria-current="page"`. çok kötü"; "harita bulunduğu yerin tamamını kaplasın"). Şehir sayfasında `SehirYuzeyi` kartını `doldur` (slice) ile kaplar, metin üstünde; kenarlar `mask-image` ile erir — telefonda yukarıdan (metnin altında belirir), lg'de soldan (sağ yarıda belirir). Metin - sütunu lg'de %58, kart en az 26rem; telefonda altta 12–14rem harita payı. Üniversite konum - kartında radyal mask. Sert kenarlı, kırpılmış bir SVG asla görünmez. + sütunu lg'de %58, kart en az 26rem; telefonda altta 12–14rem harita payı. Üniversite + sayfasında harita **dört özet kartın arkasına sarkar** (Bilal, 24 Eyl 2026): ızgara `relative + isolate`, üçüncü sütun yalnız yer tutar, harita `absolute -inset-x-4 -inset-y-8 -z-10` + katmanda; lg'de sağdan sola, telefonda üst satırdan aşağı doğru uzun rampalı mask. Mask + rampaları uzun tutulur (şeffaf → %6 → %30 → siyah); kısa rampa "kanvas" gibi okunur. Sert + kenarlı, kırpılmış bir SVG asla görünmez. - **Yakınlaşma** (Bilal, 24 Eyl 2026: "ilin bulunduğu yere doğru harita büyüsün, sayfa - yüklendikten sonra delay ile motion ile"): SSR tüm ülke; yüklenince 0,7 s sonra viewBox 1,1 s - boyunca güçlü ease-out (`0.23, 1, 0.32, 1`) ile ilin çevresindeki kutuya kayar — en çok 2,4 - kat (ülke haritasında şehir işaretine 1,8 kat). Kutu kabın o anki oranında kurulur ve il + yüklendikten sonra delay ile motion ile"): SSR tüm ülke; yüklenince 0,6 s sonra viewBox + sıçramasız yayla (`spring`, bounce 0, 1,6 s; Apple'ın damping 1'i — ease-out "sert" + duruyordu) ilin çevresindeki kutuya kayar — en çok 2,4 kat (ülke haritasında şehir işaretine + 1,8 kat). Kutu kabın o anki oranında kurulur ve il `odakHiza` ile kabın istenen noktasına gelir (şehir sayfası: lg'de x 0,74 / y 0,5, telefonda - x 0,5 / y 0,78; konum kartı: orta). Kareler büyür, il kadraja gelir; ısı fırçası viewBox'ı + x 0,5 / y 0,78; üniversite sayfası: lg'de x 0,82 / y 0,5 — üçüncü sütun, telefonda y 0,17 — + üst satır). Kareler büyür, il kadraja gelir; ısı fırçası viewBox'ı canlı okur. Hareketi azalt açıkken kutuya doğrudan atlanır. Sayfa başına tek yakınlaşma. ## 5. Yerleşim diff --git a/src/features/katalog/components/sehir-piksel-haritasi.tsx b/src/features/katalog/components/sehir-piksel-haritasi.tsx index e47543a..4721c5c 100644 --- a/src/features/katalog/components/sehir-piksel-haritasi.tsx +++ b/src/features/katalog/components/sehir-piksel-haritasi.tsx @@ -48,11 +48,13 @@ const VIEW_H = SATIR * CELL; // Hero'nun ısı fırçası 640 birimlik viewBox'ta 34; burada aynı oran. const ISI_YARICAPI = 34 * (VIEW_W / 640); // Yakınlaşma: gecikme (s), süre (s), en çok büyütme, ilin çevresinde pay (hücre) -const ODAK_GECIKME = 0.7; -const ODAK_SURE = 1.1; +// Sıçramasız yay (Apple: damping 1): hızlı başlayan ease-out "sert" +// duruyordu (Bilal, 24 Eyl 2026: "geçişler sert"); yay sıfır hızla başlar, +// yumuşak ivmelenir ve sessizce oturur. +const ODAK_GECIKME = 0.6; +const ODAK_SURE = 1.6; const ODAK_ZOOM = 2.4; const ODAK_PAY = 2; -const ODAK_EASE = [0.23, 1, 0.32, 1] as const; type Kutu = readonly [number, number, number, number]; const TAM_KUTU: Kutu = [0, 0, VIEW_W, VIEW_H]; @@ -201,9 +203,10 @@ function PikselSvg({ } const bas = TAM_KUTU; const kontrol = animate(0, 1, { + type: "spring", + bounce: 0, delay: ODAK_GECIKME, duration: ODAK_SURE, - ease: [...ODAK_EASE], onUpdate: (t) => yaz([ bas[0] + (odak[0] - bas[0]) * t, diff --git a/src/features/katalog/components/sehir-yuzeyi.tsx b/src/features/katalog/components/sehir-yuzeyi.tsx index 428bc36..f6b9c9b 100644 --- a/src/features/katalog/components/sehir-yuzeyi.tsx +++ b/src/features/katalog/components/sehir-yuzeyi.tsx @@ -24,9 +24,9 @@ export function SehirYuzeyi({ {harita ? (
-
+
{harita}
diff --git a/src/features/katalog/components/universite-icerik.tsx b/src/features/katalog/components/universite-icerik.tsx index 948c0d8..86b3f1e 100644 --- a/src/features/katalog/components/universite-icerik.tsx +++ b/src/features/katalog/components/universite-icerik.tsx @@ -625,7 +625,10 @@ export function UniversiteIcerik({ {ustSiraSatiri} -
+ {/* relative isolate: konum haritası ızgaranın arkasına serbest + katman olarak yayılır, dört kartın altına sarkar (Bilal, 24 Eyl + 2026); üçüncü sütun yalnız yer tutar. */} +
{/* Şablon tam 4 hücre bırakıyor: masaüstünde harita 3. sütunu iki satır boyunca kaplıyor, 5. kart ızgarayı bozar. Fakülte diff --git a/src/features/katalog/components/universite-konum-haritasi.tsx b/src/features/katalog/components/universite-konum-haritasi.tsx index 62a4752..75a0a24 100644 --- a/src/features/katalog/components/universite-konum-haritasi.tsx +++ b/src/features/katalog/components/universite-konum-haritasi.tsx @@ -8,15 +8,26 @@ import { // Harita il adları modül yükünde bir kez DB biçimine çevrilir. const HARITA_ILLERI = new Set(cities.map((c) => normalizeIlAdi(c.name))); -// Kartı doldurur, kenarları radyal mask ile erir (kesik kanvas yok). -const KART_HARITA_SINIFI = - "absolute inset-0 [mask-image:radial-gradient(ellipse_at_center,black_55%,transparent_100%)]"; +/** + * Harita katmanı ızgaranın tamamını kaplar ve biraz dışına sarkar; kartlar + * (beyaz, opak) üstünde kalır, harita aralıklardan ve üçüncü sütunun boş + * alanından görünür. Mask'lar (dış: kartların tarafına doğru, iç: dik + * yönde iki kenar) hiçbir kenarda kesik kare bırakmaz — geniş ekranda sağdan + * sola, telefonda üst satırdan (harita yeri) aşağı doğru erir. + */ +const KATMAN_SINIFI = + "pointer-events-none absolute -inset-x-4 -inset-y-8 -z-10 [mask-image:linear-gradient(to_bottom,transparent_0%,black_14%,black_34%,rgba(0,0,0,0.12)_58%,transparent_82%)] lg:[mask-image:linear-gradient(to_right,transparent_2%,rgba(0,0,0,0.08)_30%,rgba(0,0,0,0.35)_54%,black_74%,black_92%,transparent_100%)]"; +const IC_MASK_SINIFI = + "h-full w-full [mask-image:linear-gradient(to_right,transparent_0%,black_12%,black_88%,transparent_100%)] lg:[mask-image:linear-gradient(to_bottom,transparent_0%,black_16%,black_84%,transparent_100%)]"; +// İl geniş ekranda üçüncü sütunun ortasına (x≈0,82), telefonda üst satıra gelir. +const ODAK_HIZA = { lg: { x: 0.82, y: 0.5 }, dar: { x: 0.5, y: 0.17 } } as const; /** - * Üniversite sayfasındaki konum kartı: şehir sayfasıyla aynı dot-matrix + * Üniversite sayfasındaki konum haritası: şehir sayfasıyla aynı dot-matrix * harita (DESIGN.md §4.17; Bilal, 24 Eyl 2026: "bu kart kısmına piksel - * dokuları ekle"). Türkiye'de il turuncu noktalarla yanar; KKTC/yurt dışında - * ülke kontürü + kampüs şehrinde iri turuncu piksel. + * dokuları ekle", sonra "4 kartın arkasına sarkabilir"). Türkiye'de il + * turuncu karelerle yanar; KKTC/yurt dışında ülke kontürü + kampüs şehrinde + * iri turuncu kare. Ebeveyn ızgara `relative isolate` olmalı. */ export function UniversiteKonumHaritasi({ universite, @@ -26,55 +37,52 @@ export function UniversiteKonumHaritasi({ il: string | null; }) { const yurtdisi = uniUlkeKonum(universite, il); + let harita: React.ReactNode = null; + let altYazi: React.ReactNode = null; if (yurtdisi) { const konum = yurtdisiUniKonum(universite, il); - return ( - - -

- {yurtdisi.ulkeAd} - {yurtdisi.sehir ? ` · ${yurtdisi.sehir}` : ""} -

-
+ harita = ( + ); - } - - if (!il || !HARITA_ILLERI.has(il)) return null; - - return ( - + altYazi = ( +

+ {yurtdisi.ulkeAd} + {yurtdisi.sehir ? ` · ${yurtdisi.sehir}` : ""} +

+ ); + } else if (il && HARITA_ILLERI.has(il)) { + harita = ( -
- ); -} + ); + } + if (!harita) return null; -function KonumBolumu({ - universite, - children, -}: { - universite: string; - children: React.ReactNode; -}) { return ( -
-

- {universite} kampüs konumu -

-
{children}
-
+ <> + {/* Yer tutucu: telefonda tam genişlikte bir satır, lg'de üçüncü sütun */} +
+

+ {universite} kampüs konumu +

+ {altYazi} +
+
+
{harita}
+
+ ); }