Koyuya geçerken şeftali kare hilale (iç gölgeyle; zemin rengine bağlı değil), mavi ve turuncu kareler iki yıldıza; açığa geçerken turuncu kare güneşe, şeftali kare halesine dönüşür. Kısa bir an durup logoya toplanır (1,7 sn). Yalnız header'daki logo; hover döngüsü biçimi keser. DESIGN §2.3 güncel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.2 KiB
TypeScript
80 lines
3.2 KiB
TypeScript
// 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 <html>'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;
|
||
});
|
||
}
|