// Tema geçişi (DESIGN.md §2.3): açık ↔ koyu değişimi ekranı bir anda // çevirmez; yeni tema header'daki KolayTercih işaretinden yumuşak bir halka // gibi açılır — kenarı keskin değil, geniş ve tüylü; ışık yayılır gibi. // Aynı anda logonun kareleri yeni temanın biçimine dönüşür (koyuya: ay ve // yıldızlar; açığa: güneş), kısa bir an durur ve yeniden logoya toplanır. // Markanın yumuşak, oyunsu diline uysun diye sert kenar, piksel ya da ikinci // bir şekil yok (9 Eki 2026). // // Nasıl: View Transitions API eski/yeni görüntü çiftini verir; yeni görüntü // radyal degrade maskesiyle açılır. Yarıçapı CSS sürer (globals.css // `.kt-tema-gecis`), buradan yalnız merkez ve son yarıçap verilir. Tarayıcı // View Transitions bilmiyorsa ya da hareket azaltılmışsa tema düz değişir. /** Geçiş sırasında 'de duran sınıf (globals.css). */ const GECIS_SINIFI = "kt-tema-gecis"; /** Geçiş başlarken pencereye atılan olay; header'daki logo bunu dinleyip * karelerini güneşe ya da aya dönüştürür (animasyonlu-mark.tsx). */ export const TEMA_GECIS_OLAYI = "kt-tema-gecis"; // Maskenin tam opak çekirdeği yarıçapın bu oranında biter, kalanı tüydür // (globals.css'teki --kt-tema-cekirdek ile aynı olmalı): son yarıçap, çekirdek // en uzak köşeyi de örtecek kadar büyük seçilir. const CEKIRDEK = 0.55; let suruyor = false; /** * `uygula` temayı değiştiren çağrıdır (ör. `setTheme("dark")`). Geçiş * sürerken gelen istek yok sayılır: art arda D'ye basınca ekrandaki görüntü * ile tema durumu birbirine girmesin. */ export function temayiGecisle(uygula: () => void) { if (typeof document === "undefined") { uygula(); return; } const azHareket = window.matchMedia("(prefers-reduced-motion: reduce)").matches; if (!document.startViewTransition || azHareket) { uygula(); return; } if (suruyor) return; const kok = document.documentElement; // Halkanın merkezi header'daki logo; krom gizli sayfalarda sol üst köşe. const logo = document .querySelector('header a[aria-label="KolayTercih"]') ?.getBoundingClientRect(); const gorunur = logo && logo.width > 0 && logo.bottom > 0; const x = gorunur ? logo.left + logo.height / 2 : 24; const y = gorunur ? logo.top + logo.height / 2 : 24; const enUzak = Math.hypot( Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y), ); kok.style.setProperty("--kt-tema-x", `${x}px`); kok.style.setProperty("--kt-tema-y", `${y}px`); kok.style.setProperty("--kt-tema-son", `${Math.ceil(enUzak / CEKIRDEK)}px`); kok.classList.add(GECIS_SINIFI); suruyor = true; const gecis = document.startViewTransition(uygula); // Sekme gizliyken / yeniden boyutlanırken tarayıcı geçişi iptal eder: // `ready` reddedilir, tema yine uygulanmıştır; konsola hata düşmesin. gecis.ready .then(() => window.dispatchEvent(new Event(TEMA_GECIS_OLAYI))) .catch(() => {}); gecis.finished .catch(() => {}) .finally(() => { kok.classList.remove(GECIS_SINIFI); kok.style.removeProperty("--kt-tema-x"); kok.style.removeProperty("--kt-tema-y"); kok.style.removeProperty("--kt-tema-son"); suruyor = false; }); }