diff --git a/docs/tasarim/DESIGN.md b/docs/tasarim/DESIGN.md index 0eb0784..418e5c4 100644 --- a/docs/tasarim/DESIGN.md +++ b/docs/tasarim/DESIGN.md @@ -138,7 +138,8 @@ tema header'daki logodan **yumuşak bir halka** gibi açılır: kenarı keskin d tüylü (ışık yayılır gibi), 1100 ms, yumuşak kalkıp yumuşak durur. Aynı anda logonun kareleri yeni temanın biçimine dönüşür: koyuya geçişte şeftali kare hilale, mavi ve turuncu kareler iki yıldıza; açığa geçişte turuncu kare güneşe, şeftali kare halesine. Kısa bir an durur, yeniden -logoya toplanır (`animasyonlu-mark.tsx` `temaSekli`, 1,7 sn; yalnız header'daki logo). Tema +logoya toplanır (`animasyonlu-mark.tsx` `temaSekli`, 1,7 sn; yalnız header'daki logo; hover döngüsünden +önceliklidir, biçim bitince imleç üzerindeyse döngü kaldığı yerden değil yerinden sürer). Tema seçicinin ikonları aynı biçimlerin durağan hâlidir (`tema-ikonu.tsx`: güneş, ay, Sistem için logonun üç karesi); burada lucide ikonu kullanılmaz. View Transitions + radyal degrade maskesi: `src/lib/tema-gecisi.ts`, `globals.css` `.kt-tema-gecis`; hareket azaltılmışsa düz diff --git a/src/components/animasyonlu-mark.tsx b/src/components/animasyonlu-mark.tsx index 2108a1b..2c45c50 100644 --- a/src/components/animasyonlu-mark.tsx +++ b/src/components/animasyonlu-mark.tsx @@ -268,19 +268,11 @@ export function AnimasyonluMark({ ); }; - const ayarla = (yeni: Varyant | null, cevik = false) => { - if (yeni === hedef) return; - hedef = yeni; - // Hover döngüsü biçimin üstüne binmesin: güneş/ay yarıda kesilir. - if (yeni !== null) { - sekil.forEach((a) => a.cancel()); - sekil = []; - } - if (aktif !== null) yerles(cevik); - if (yeni === null || azHareket.matches) return; - // Kareler hâlâ yerine dönüyorsa dönüşün bitmesi beklenir; döngü hep - // yerinden başlar, sıçrama olmaz. - Promise.all(donus.map((a) => a.finished)) + /** `yeni` döngüsünü, süren dönüş ve tema biçimi bitince yerinden başlatır. */ + const donguyuSiraya = (yeni: Varyant) => { + // Kareler hâlâ yerine dönüyorsa (ya da güneş/ay oynuyorsa) bitmesi + // beklenir; döngü hep yerinden başlar, sıçrama olmaz. + Promise.all([...donus, ...sekil].map((a) => a.finished)) .then(() => { if (sokuldu || hedef !== yeni || aktif !== null) return; dongu = kareler.flatMap((el, i) => donguyuBaslat(el, i, yeni)); @@ -289,16 +281,39 @@ export function AnimasyonluMark({ .catch(() => {}); }; + const ayarla = (yeni: Varyant | null, cevik = false) => { + if (yeni === hedef) return; + hedef = yeni; + if (aktif !== null) yerles(cevik); + if (yeni === null || azHareket.matches) return; + donguyuSiraya(yeni); + }; + /** * Tema geçişi biçimi: kareler güneşe ya da aya dönüşür, durur, logoya - * döner. Döngü oynarken (hover) ya da hareket azaltılmışken çalışmaz. + * döner. Hover döngüsünden önceliklidir: döngü oynuyorsa kesilir, kareler + * o an neredeyse oradan biçime geçer; biçim bitince imleç hâlâ + * üzerindeyse döngü yerinden yeniden başlar. Hareket azaltılmışsa çalışmaz. * Hilal, kareyi kesen ikinci bir şekille değil karenin kendi iç gölgesiyle * çizilir (zemin şeffaf, renk iç gölgede): arkadaki zemin ne olursa olsun * doğru görünür. */ const temaSekli = (koyu: boolean) => { - if (aktif !== null || hedef !== null || azHareket.matches) return; - sekil.forEach((a) => a.cancel()); + if (azHareket.matches) return; + // Karelerin o anki hâli: döngü ya da önceki biçim yarıdaysa oradan çıkılır. + const anlik = kareler.map((el) => { + const cs = getComputedStyle(el); + return { + translate: cs.translate, + scale: cs.scale, + opacity: cs.opacity, + borderRadius: cs.borderRadius, + }; + }); + [...dongu, ...donus, ...sekil].forEach((a) => a.cancel()); + dongu = []; + donus = []; + aktif = null; sekil = kareler.flatMap((el, i) => { const k = KARELER[i]; const ev = { @@ -312,7 +327,7 @@ export function AnimasyonluMark({ const animasyonlar = [ el.animate( [ - { ...ev, easing: DONUS }, + { ...anlik[i], easing: DONUS }, { ...bicim, easing: "linear" }, { ...bicim, easing: YERLES }, ev, @@ -340,6 +355,8 @@ export function AnimasyonluMark({ } return animasyonlar; }); + // İmleç hâlâ üzerindeyse hover döngüsü biçimden sonra sürer. + if (hedef !== null) donguyuSiraya(hedef); }; const kontrol = { ayarla, temaSekli };