refactor(tema): logo maskesi kaldırıldı, tema geçişi sade crossfade (640 ms)
Bilal'in kararı (9 Eki 2026): SVG maskeli yayılma şimdilik yok; tüm sayfa tek parça crossfade ile geçer, mursela-nextjs'teki tema geçişiyle aynı süre ve eğri (640 ms, cubic-bezier(0.6, 0, 0.2, 1)). motion bağımlılığı ve maske değişkenleri tema-gecisi.ts'ten çıktı; DESIGN §2.3 notu güncel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,33 +1,20 @@
|
||||
// Tema geçişi (DESIGN.md §2.3): açık ↔ koyu değişimi ekranı bir anda
|
||||
// çevirmez; yeni tema, KolayTercih işaretinin biçiminde önce ekranın altından
|
||||
// ortaya süzülür, sonra merkezden büyüyerek ekranı kaplar. View Transitions
|
||||
// API + CSS maskesi (globals.css `.kt-tema-gecis`) eski/yeni görüntü çiftini
|
||||
// kurar; maskenin konumu, boyu ve son dolgu motion ile sürülür. Tarayıcı View Transitions bilmiyorsa ya da kullanıcı hareketi
|
||||
// azaltmışsa tema düz değişir.
|
||||
// çevirmez; tüm sayfa tek parça, yumuşak bir crossfade ile yeni temaya geçer
|
||||
// (View Transitions API; süre ve eğri globals.css `.kt-tema-gecis`
|
||||
// bloğunda, mursela-nextjs'teki tema geçişiyle aynı: 640 ms ease-in-out).
|
||||
// Tarayıcı View Transitions bilmiyorsa ya da kullanıcı hareketi azaltmışsa
|
||||
// tema düz değişir.
|
||||
|
||||
import { animate, type AnimationPlaybackControls } from "motion";
|
||||
|
||||
/** Geçiş sırasında <html>'de duran sınıf (globals.css). */
|
||||
/** Geçiş sırasında <html>'de duran sınıf: crossfade stili yalnız tema
|
||||
* değişimine uygulanır, başka view transition'lara karışmaz. */
|
||||
const GECIS_SINIFI = "kt-tema-gecis";
|
||||
|
||||
// Saniye. Faz 1 (uçuş): işaret ekranın altından ortaya gelir. Faz 2
|
||||
// (kaplama): merkezden büyüyerek ekranı aşar; DOLGU_BASI'ndan sonra tam ekran
|
||||
// dolgu alfası yükselir ve kareler arasında / kenarlarda kalan eski görüntü
|
||||
// yeni temaya solar. Ekranda tek silüet vardır, ikinci bir şekil büyümez.
|
||||
const UCUS_SURE = 0.45;
|
||||
const KAPLAMA_SURE = 0.6;
|
||||
const DOLGU_BASI = 0.5;
|
||||
const EASE = [0.65, 0, 0.35, 1] as const;
|
||||
// CSS'teki kt-tema-omur'un süresi: motion bitmeden pseudo eleman kalkmasın
|
||||
// diye toplamın biraz üstü (globals.css'te --kt-tema-sure ile okunur).
|
||||
const GECIS_SURESI = UCUS_SURE + KAPLAMA_SURE + 0.1;
|
||||
|
||||
let suruyor = false;
|
||||
|
||||
/**
|
||||
* `uygula` temayı değiştiren çağrıdır (ör. `setTheme("dark")`). Geçiş
|
||||
* destekleniyorsa işaret ekranın altından ortaya süzülür ve oradan büyüyerek
|
||||
* yeni temayı açar.
|
||||
* 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") {
|
||||
@@ -39,66 +26,12 @@ export function temayiGecisle(uygula: () => void) {
|
||||
uygula();
|
||||
return;
|
||||
}
|
||||
// Geçiş sürerken gelen istek yok sayılır (uygulanmaz): ara anahtarlamalar
|
||||
// hem koreografiyi bozar hem de ekrandaki görüntü ile tema durumu birbirine
|
||||
// girer; D'ye art arda basınca görünen "sıçrama" budur.
|
||||
if (suruyor) return;
|
||||
|
||||
const en = window.innerWidth;
|
||||
const boy = window.innerHeight;
|
||||
const kok = document.documentElement;
|
||||
|
||||
// Uçuş boyunca işaretin maskeden çıkan kenarı: ekranı kaplamayacak ama
|
||||
// belirgin bir işaret olacak kadar (min ekran kenarının %22'si; işaretin
|
||||
// görünür karesi bunun ~%67'si).
|
||||
const ucusKenar = Math.round(Math.min(en, boy) * 0.22);
|
||||
// Uçuş ve kaplamanın ortak ekseni ekranın ortası; başlangıçta işaret
|
||||
// tamamen ekranın altında durur (alttan gelir).
|
||||
const merkezX = en / 2;
|
||||
const merkezY = boy / 2;
|
||||
const baslangicY = boy + ucusKenar / 2;
|
||||
// Kaplama merkezden ekranın en uzak köşesine kadar büyümeli. İşaretin
|
||||
// görünür karesi viewBox'ın ~%67'si; kenar bu oranla çarpılır ki kareler
|
||||
// ekranı geniş ölçüde kaplasın — kalan boşlukları dolgu solması kapatır.
|
||||
const sonKenar = Math.ceil(Math.hypot(merkezX, merkezY) * 3);
|
||||
|
||||
kok.style.setProperty("--kt-tema-x", `${merkezX}px`);
|
||||
kok.style.setProperty("--kt-tema-y", `${baslangicY}px`);
|
||||
kok.style.setProperty("--kt-tema-kenar", `${ucusKenar}px`);
|
||||
kok.style.setProperty("--kt-tema-dolgu", "0");
|
||||
kok.style.setProperty("--kt-tema-sure", `${GECIS_SURESI}s`);
|
||||
kok.classList.add(GECIS_SINIFI);
|
||||
suruyor = true;
|
||||
|
||||
const kontroller: AnimationPlaybackControls[] = [
|
||||
// Faz 1 — uçuş: alttan ortaya, x sabit.
|
||||
animate(0, 1, {
|
||||
duration: UCUS_SURE,
|
||||
ease: EASE,
|
||||
onUpdate: (p) => {
|
||||
kok.style.setProperty(
|
||||
"--kt-tema-y",
|
||||
`${baslangicY + (merkezY - baslangicY) * p}px`,
|
||||
);
|
||||
},
|
||||
}),
|
||||
// Faz 2 — kaplama: merkezden ekranı aşana kadar.
|
||||
animate(ucusKenar, sonKenar, {
|
||||
duration: KAPLAMA_SURE,
|
||||
delay: UCUS_SURE,
|
||||
ease: EASE,
|
||||
onUpdate: (kenar) => kok.style.setProperty("--kt-tema-kenar", `${kenar}px`),
|
||||
}),
|
||||
// Dolgu: büyümenin ikinci yarısında kareler arasında ve ekran
|
||||
// kenarlarında kalan eski görüntü yeni temaya solar.
|
||||
animate(0, 1, {
|
||||
duration: KAPLAMA_SURE * (1 - DOLGU_BASI),
|
||||
delay: UCUS_SURE + KAPLAMA_SURE * DOLGU_BASI,
|
||||
ease: EASE,
|
||||
onUpdate: (dolgu) => kok.style.setProperty("--kt-tema-dolgu", `${dolgu}`),
|
||||
}),
|
||||
];
|
||||
|
||||
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.
|
||||
@@ -106,7 +39,6 @@ export function temayiGecisle(uygula: () => void) {
|
||||
gecis.finished
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
kontroller.forEach((k) => k.stop());
|
||||
kok.classList.remove(GECIS_SINIFI);
|
||||
suruyor = false;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user