feat(v2): 9–10 Ekim çalışma ağacı — deneyim dili 1. dalga, PWA manifest, revizyon niyet modeli, listem/tadımlık bileşen denetimi
9–10 Ekim oturumlarının commit'lenmemiş işi tek parça alındı (raporlar: docs/ekip-raporlari/2026-10-09, 2026-10-10): - Landing deneyim dili 1. dalga: sayfa geçişi (ViewTransition), piksel morf/şerit, sorun sahneleri, adım akışı, sayan sayı, mobil menü, adım göstergesi, logoya tepki; DESIGN.md §11 ve AGENTS.md kuralları, tasarım denetimine yeni kurallar - Tema: tema ikonu, D kısayolu, tema geçişi - PWA: manifest.ts ve ikonlar - Danışman: revizyon niyet modeli (OPENROUTER_NIYET_MODEL), sohbet geçmişi, soru API'si - /listem ve /sonuc tadımlığı bileşen denetimi düzeltmeleri - eslint: .venv-tts/ yok sayılır tsc, eslint ve tasarım denetimi sıfır hata. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
100
src/lib/tema-gecisi.ts
Normal file
100
src/lib/tema-gecisi.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
// 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.
|
||||
// Geçiş kısa ve hafiftir; BİTİNCE logonun kareleri yeni temanın biçimine
|
||||
// dönüşür (koyuya: ay ve yıldız; 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ş bitince 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;
|
||||
|
||||
/** Sayfa geçişi ile logo dönüşümü arasındaki kısa nefes (ms). */
|
||||
const LOGO_NEFESI = 80;
|
||||
|
||||
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 (azHareket) {
|
||||
uygula();
|
||||
return;
|
||||
}
|
||||
if (!document.startViewTransition) {
|
||||
// Sayfa geçişi yok ama logo yine dönüşür; temanın sınıfı <html>'e
|
||||
// yazılsın diye kısa bir an beklenir.
|
||||
uygula();
|
||||
window.setTimeout(
|
||||
() => window.dispatchEvent(new Event(TEMA_GECIS_OLAYI)),
|
||||
LOGO_NEFESI,
|
||||
);
|
||||
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.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;
|
||||
// Sıra: önce sayfa geçişi biter, sonra logo dönüşür — ikisi üst üste
|
||||
// binmez, göz önce temaya sonra logoya gider. Kısa nefes (LOGO_NEFESI):
|
||||
// geçiş iptal olduysa (sekme gizli vb.) `finished` hemen döner ve
|
||||
// temanın sınıfı <html>'e henüz yazılmamış olabilir; logo yanlış
|
||||
// biçime dönüşmesin.
|
||||
window.setTimeout(
|
||||
() => window.dispatchEvent(new Event(TEMA_GECIS_OLAYI)),
|
||||
LOGO_NEFESI,
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user