- lib/tema-gecisi.ts: View Transitions + CSS maskesi (kolay-tercih-mark.svg), merkez header'daki işaret; reduced-motion ve desteksiz tarayıcıda düz geçiş - tema-kisayolu.tsx: D tuşu açık ↔ koyu (yazı alanı/değiştirici tuşta pasif) - tema-secici.tsx: seçim de maskeyle oynar, altında Kbd ile D ipucu - /surum-notlari: beta açıklaması, geri bildirim (destek@kolaytercih.com), sürüm günlüğü; Beta rozeti ve footer buraya bağlanır, sitemap'e eklendi - DESIGN.md §2.3 notu Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
57 lines
2.1 KiB
TypeScript
57 lines
2.1 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şaretinin biçiminde logodan
|
||
// başlayıp büyüyerek ekrana yayılır (View Transitions API + CSS maskesi,
|
||
// globals.css `.kt-tema-gecis`). Tarayıcı View Transitions bilmiyorsa ya da
|
||
// kullanıcı hareketi azaltmışsa tema düz değişir.
|
||
|
||
/** Header'daki işaretin kök elemanı (site-header.tsx, AnimasyonluMark). */
|
||
export const TEMA_ODAK_ID = "kt-tema-odak";
|
||
|
||
/** Geçiş sırasında <html>'de duran sınıf ve maskenin merkez değişkenleri. */
|
||
const GECIS_SINIFI = "kt-tema-gecis";
|
||
|
||
let suruyor = false;
|
||
|
||
/**
|
||
* `uygula` temayı değiştiren çağrıdır (ör. `setTheme("dark")`). Geçiş
|
||
* destekleniyorsa yeni tema işaretin bulunduğu noktadan maskeyle açılır;
|
||
* işaret ekranda değilse (krom gizli sayfalar) sol üst köşeden açılır.
|
||
*/
|
||
export function temayiGecisle(uygula: () => void) {
|
||
if (typeof document === "undefined") {
|
||
uygula();
|
||
return;
|
||
}
|
||
const azHareket = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||
if (!document.startViewTransition || azHareket || suruyor) {
|
||
uygula();
|
||
return;
|
||
}
|
||
|
||
const odak = document.getElementById(TEMA_ODAK_ID)?.getBoundingClientRect();
|
||
const kok = document.documentElement;
|
||
const x = odak && odak.width > 0 ? odak.left + odak.width / 2 : 40;
|
||
const y = odak && odak.height > 0 ? odak.top + odak.height / 2 : 48;
|
||
// Maske merkezden ekranın en uzak köşesine kadar büyümeli.
|
||
const uzak = 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`);
|
||
// İşaretin görünür karesi viewBox'ın ~%67'si; kenar bu oranla çarpılır ki
|
||
// en büyük hâlde köşe karesi bile ekranı aşsın.
|
||
kok.style.setProperty("--kt-tema-son", `${Math.ceil(uzak * 3.4)}px`);
|
||
kok.classList.add(GECIS_SINIFI);
|
||
suruyor = true;
|
||
|
||
const gecis = document.startViewTransition(uygula);
|
||
gecis.finished
|
||
.catch(() => {})
|
||
.finally(() => {
|
||
kok.classList.remove(GECIS_SINIFI);
|
||
suruyor = false;
|
||
});
|
||
}
|