Files
kolaytercih/src/lib/tema-gecisi.ts
bilalgursen 8c48303051 feat(tema): geçişte logo kareleri güneşe ya da aya dönüşür
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>
2026-10-09 00:29:03 +03:00

80 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;
});
}