fix(tema): geçiş maskesinde logo görünmüyordu — SVG katmanları CSS'e gömüldü; alttan uçuş + boşluk kapanışı koreografisi
Chrome, view-transition pseudo elemanında dosyadan url() ile yüklenen ikinci maske katmanını (boyu 0'dan büyükken) tümden şeffaf çiziyor; iki SVG de data URI olarak globals.css'e gömüldü. Koreografi (önceki oturum): işaret ekranın altından ortaya süzülür, merkezden büyür, kareler arası boşluklar dolu çizimle merkezden dışa kapanır; motion sürer. Geçici console tanıları kaldırıldı, iptal edilen geçişin ready reddi yakalanıyor. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -133,9 +133,13 @@ Seçici `src/components/tema-secici.tsx` (footer'da), sağlayıcı `src/componen
|
|||||||
(`next-themes`, `<html class="dark">`). Renklerin tek kaynağı `src/app/globals.css` içindeki
|
(`next-themes`, `<html class="dark">`). Renklerin tek kaynağı `src/app/globals.css` içindeki
|
||||||
`.dark` bloğu.
|
`.dark` bloğu.
|
||||||
|
|
||||||
**Geçiş ve kısayol (7 Eki 2026):** tema değişimi anlık değildir; yeni tema header'daki
|
**Geçiş ve kısayol (7 Eki 2026):** tema değişimi anlık değildir; yeni tema
|
||||||
KolayTercih işaretinin biçiminde logodan büyüyerek açılır (View Transitions + CSS maskesi:
|
KolayTercih işaretinin biçiminde önce ekranın altından ortaya süzülür, sonra
|
||||||
`src/lib/tema-gecisi.ts`, `globals.css` `.kt-tema-gecis`; hareket azaltılmışsa düz değişir).
|
merkezden büyüyerek ekranı kaplar — büyüme boyunca logo normal, boşluklu
|
||||||
|
hâliyle görünür; en büyük haline yaklaştıkça kareler arası boşluklar
|
||||||
|
merkezden dışa doğru yumuşak biçimde kapanır (View Transitions + CSS
|
||||||
|
maskesi, maskeyi motion sürer: `src/lib/tema-gecisi.ts`, `globals.css`
|
||||||
|
`.kt-tema-gecis`; hareket azaltılmışsa düz değişir).
|
||||||
`D` tuşu açık ↔ koyu geçişi yapar (`src/components/tema-kisayolu.tsx`); ipucu seçicinin
|
`D` tuşu açık ↔ koyu geçişi yapar (`src/components/tema-kisayolu.tsx`); ipucu seçicinin
|
||||||
altında `Kbd` ile durur, başka yere kopyalanmaz. Header'daki Beta rozeti `/surum-notlari`na
|
altında `Kbd` ile durur, başka yere kopyalanmaz. Header'daki Beta rozeti `/surum-notlari`na
|
||||||
bağlantıdır.
|
bağlantıdır.
|
||||||
|
|||||||
15
public/kolay-tercih-mark-dolu.svg
Normal file
15
public/kolay-tercih-mark-dolu.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180" role="img" aria-labelledby="title">
|
||||||
|
<title id="title">KolayTercih</title>
|
||||||
|
<!-- Tema geçişi maskesinin KAPANIŞ katmanı (globals.css .kt-tema-gecis):
|
||||||
|
büyüme boyunca normal çizim (kolay-tercih-mark.svg) boşluklu görünür;
|
||||||
|
en büyük hâle yaklaştıkça bu dolu çizim merkezden dışa büyür
|
||||||
|
(boy = --kt-tema-kenar × --kt-tema-kapanis) ve kareler arası boşlukları
|
||||||
|
kapatır. Dış sınırlar orijinalle aynı: x 27–147, y 29–151.
|
||||||
|
Sol kare sağ sütuna girer (27+77=104 > 91) ki birleşim yeri kaymasın;
|
||||||
|
sağ sütun iki kareyi birleştirir (dikey boşluk). --kt-tema-kapanis
|
||||||
|
tam 1 olduğunda siluet orijinalin tam katmanıdır; ara değerlerde
|
||||||
|
merkezden dışa büyür, boşlukların kapanışı kenarlara doğru yumuşak
|
||||||
|
olur. -->
|
||||||
|
<rect x="27" y="56" width="77" height="57" rx="13" fill="#000"/>
|
||||||
|
<rect x="91" y="29" width="56" height="122" rx="13" fill="#000"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1019 B |
@@ -478,21 +478,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Tema geçişi (DESIGN.md §2.3, lib/tema-gecisi.ts): tema değişirken yeni
|
/* Tema geçişi (DESIGN.md §2.3, lib/tema-gecisi.ts): tema değişirken yeni
|
||||||
görüntü, header'daki KolayTercih işaretinin biçiminde logodan büyüyerek
|
görüntü, KolayTercih işaretinin biçiminde önce ekranın ALTINDAN ortaya
|
||||||
açılır. Eski görüntü yerinde durur; yeni görüntünün maskesi iki katman:
|
süzülür, sonra merkezden büyüyerek ekranı kaplar. Eski görüntü yerinde
|
||||||
(1) işaretin SVG'si, merkezi --kt-tema-x/y'de, kenarı 0 → --kt-tema-son;
|
durur; yeni görüntünün maskesi üç katman (hepsi `add` ile toplanır,
|
||||||
(2) aynı merkezden biraz geç kalkan bir daire — işaretin kareleri arasındaki
|
mask-composite varsayılanı add — bu yüzden sıralama yalnızca okunurluk
|
||||||
boşlukları kapatır ki geçiş sonunda eski temadan iz kalmasın. Hareket
|
içindir):
|
||||||
azaltılmışsa JS geçişi hiç başlatmaz, tema düz değişir. */
|
(1) işaretin NORMAL çizimi (kolay-tercih-mark.svg'nin gömülü kopyası — kareler arası boşluk
|
||||||
|
görünür, logo logonun kendisi gibi durur), merkezi --kt-tema-x/y'de,
|
||||||
|
boyu --kt-tema-kenar: uçuş ve büyüme boyunca bu görünür;
|
||||||
|
(2) aynı geometride BOŞLUKLARI DOLU çizim (kolay-tercih-mark-dolu.svg),
|
||||||
|
boyu --kt-tema-kenar × --kt-tema-kapanis (0 → 1): logo en büyük haline
|
||||||
|
ulaşmaya yakın dolu çizim merkezden dışa doğru büyür, kareler arası
|
||||||
|
boşlukları yumuşak biçimde kapatır;
|
||||||
|
(3) tam ekran dolgu: --kt-tema-dolgu (0 → 1) ile işaret ekranı tam
|
||||||
|
kapsadıktan sonra dış çentiklerde kalan eski zeminin son anda dolması.
|
||||||
|
Yuvarlak büyüme yok — logo ekranı kaplayınca geçiş tamamlanır.
|
||||||
|
Konum, boy ve dolgular motion ile sürülür (lib/tema-gecisi.ts); buradaki
|
||||||
|
kt-tema-omur yalnızca geçişin pseudo elemanı motion bitene kadar yaşasın
|
||||||
|
diye durur (süre --kt-tema-sure, JS'den gelir). Hareket azaltılmışsa JS
|
||||||
|
geçişi hiç başlatmaz, tema düz değişir. */
|
||||||
@property --kt-tema-kenar {
|
@property --kt-tema-kenar {
|
||||||
syntax: "<length>";
|
syntax: "<length>";
|
||||||
inherits: true;
|
inherits: true;
|
||||||
initial-value: 0px;
|
initial-value: 0px;
|
||||||
}
|
}
|
||||||
@property --kt-tema-yaricap {
|
@property --kt-tema-kapanis {
|
||||||
syntax: "<length>";
|
syntax: "<number>";
|
||||||
inherits: true;
|
inherits: true;
|
||||||
initial-value: 0px;
|
initial-value: 0;
|
||||||
|
}
|
||||||
|
@property --kt-tema-dolgu {
|
||||||
|
syntax: "<number>";
|
||||||
|
inherits: true;
|
||||||
|
initial-value: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kt-tema-gecis {
|
.kt-tema-gecis {
|
||||||
@@ -508,40 +526,42 @@
|
|||||||
}
|
}
|
||||||
.kt-tema-gecis::view-transition-new(root) {
|
.kt-tema-gecis::view-transition-new(root) {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
/* İki SVG de data URI olarak gömülü, dosyadan url() ile DEĞİL: Chrome'da
|
||||||
|
view-transition pseudo elemanı dosyadan yüklenen ikinci bir maske
|
||||||
|
katmanını (boyu 0'dan büyük olduğu an) tümden şeffaf çiziyor — logo
|
||||||
|
hiç görünmüyordu (8 Eki 2026 tanısı). Gömülü hâlde iki katman da
|
||||||
|
doğru birleşiyor. Çizimler public/kolay-tercih-mark.svg ve
|
||||||
|
public/kolay-tercih-mark-dolu.svg ile aynı geometridir; oradaki dosya
|
||||||
|
değişirse burası da güncellenir. */
|
||||||
mask-image:
|
mask-image:
|
||||||
url("/kolay-tercih-mark.svg"),
|
url("data:image/svg+xml,<svg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20180%20180%22><rect%20x=%2227%22%20y=%2256%22%20width=%2277%22%20height=%2257%22%20rx=%2213%22/><rect%20x=%2291%22%20y=%2229%22%20width=%2256%22%20height=%22122%22%20rx=%2213%22/></svg>"),
|
||||||
radial-gradient(
|
url("data:image/svg+xml,<svg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20180%20180%22><rect%20x=%2227%22%20y=%2256%22%20width=%2257%22%20height=%2257%22%20rx=%2213%22/><rect%20x=%2291%22%20y=%2229%22%20width=%2256%22%20height=%2256%22%20rx=%2213%22/><rect%20x=%2291%22%20y=%2295%22%20width=%2256%22%20height=%2256%22%20rx=%2213%22/></svg>"),
|
||||||
circle at var(--kt-tema-x) var(--kt-tema-y),
|
linear-gradient(
|
||||||
#000 calc(var(--kt-tema-yaricap) - 1px),
|
rgb(0 0 0 / var(--kt-tema-dolgu)),
|
||||||
transparent var(--kt-tema-yaricap)
|
rgb(0 0 0 / var(--kt-tema-dolgu))
|
||||||
);
|
);
|
||||||
mask-repeat: no-repeat;
|
mask-repeat: no-repeat;
|
||||||
mask-size:
|
mask-size:
|
||||||
|
calc(var(--kt-tema-kenar) * var(--kt-tema-kapanis))
|
||||||
|
calc(var(--kt-tema-kenar) * var(--kt-tema-kapanis)),
|
||||||
var(--kt-tema-kenar) var(--kt-tema-kenar),
|
var(--kt-tema-kenar) var(--kt-tema-kenar),
|
||||||
100% 100%;
|
100% 100%;
|
||||||
mask-position:
|
mask-position:
|
||||||
|
calc(var(--kt-tema-x) - var(--kt-tema-kenar) * var(--kt-tema-kapanis) / 2)
|
||||||
|
calc(var(--kt-tema-y) - var(--kt-tema-kenar) * var(--kt-tema-kapanis) / 2),
|
||||||
calc(var(--kt-tema-x) - var(--kt-tema-kenar) / 2)
|
calc(var(--kt-tema-x) - var(--kt-tema-kenar) / 2)
|
||||||
calc(var(--kt-tema-y) - var(--kt-tema-kenar) / 2),
|
calc(var(--kt-tema-y) - var(--kt-tema-kenar) / 2),
|
||||||
0 0;
|
0 0;
|
||||||
animation:
|
/* Değeri değişmeyen ama gerçek bir animasyon: view transition, üzerindeki
|
||||||
kt-tema-isaret 0.9s cubic-bezier(0.65, 0, 0.35, 1) both,
|
tüm animasyonlar bitene kadar kalkmaz; maskeyi JS (motion) sürerken
|
||||||
kt-tema-daire 0.9s cubic-bezier(0.65, 0, 0.35, 1) both;
|
ömrü bu tutar. */
|
||||||
|
animation: kt-tema-omur var(--kt-tema-sure, 1.05s) linear both;
|
||||||
}
|
}
|
||||||
@keyframes kt-tema-isaret {
|
@keyframes kt-tema-omur {
|
||||||
from {
|
from {
|
||||||
--kt-tema-kenar: 0px;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
--kt-tema-kenar: var(--kt-tema-son);
|
opacity: 1;
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Daire işaretin ardından gelir: ilk %35'te sıfırda bekler. */
|
|
||||||
@keyframes kt-tema-daire {
|
|
||||||
0%,
|
|
||||||
35% {
|
|
||||||
--kt-tema-yaricap: 0px;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
--kt-tema-yaricap: var(--kt-tema-son);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,15 +166,12 @@ function donguyuBaslat(
|
|||||||
* yerinden başlar.
|
* yerinden başlar.
|
||||||
*/
|
*/
|
||||||
export function AnimasyonluMark({
|
export function AnimasyonluMark({
|
||||||
id,
|
|
||||||
className,
|
className,
|
||||||
sadeceHover = false,
|
sadeceHover = false,
|
||||||
oynat = true,
|
oynat = true,
|
||||||
varyant = "rota",
|
varyant = "rota",
|
||||||
renk = "marka",
|
renk = "marka",
|
||||||
}: {
|
}: {
|
||||||
/** Kök elemanın id'si (ör. tema geçişinin merkez noktası, lib/tema-gecisi.ts). */
|
|
||||||
id?: string;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
sadeceHover?: boolean;
|
sadeceHover?: boolean;
|
||||||
/** `sadeceHover` yokken döngü açık mı. `false` iken işaret durağandır. */
|
/** `sadeceHover` yokken döngü açık mı. `false` iken işaret durağandır. */
|
||||||
@@ -287,7 +284,6 @@ export function AnimasyonluMark({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
id={id}
|
|
||||||
ref={kokRef}
|
ref={kokRef}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Suspense } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { AnimasyonluMark } from "@/components/animasyonlu-mark";
|
import { AnimasyonluMark } from "@/components/animasyonlu-mark";
|
||||||
import { SurumRozeti } from "@/components/surum-rozeti";
|
import { SurumRozeti } from "@/components/surum-rozeti";
|
||||||
import { TEMA_ODAK_ID } from "@/lib/tema-gecisi";
|
|
||||||
import { KatalogArama } from "@/features/katalog/components/katalog-arama";
|
import { KatalogArama } from "@/features/katalog/components/katalog-arama";
|
||||||
import { UserNav, UserNavFallback } from "@/features/kullanici/components/user-nav";
|
import { UserNav, UserNavFallback } from "@/features/kullanici/components/user-nav";
|
||||||
import { getRehberAramaKayitlari } from "@/lib/rehber";
|
import { getRehberAramaKayitlari } from "@/lib/rehber";
|
||||||
@@ -24,13 +23,8 @@ export function SiteHeader() {
|
|||||||
className="group flex min-w-0 shrink items-center font-bricolage"
|
className="group flex min-w-0 shrink items-center font-bricolage"
|
||||||
>
|
>
|
||||||
{/* Inline animasyonlu mark: Link'teki `group` sayesinde hover'da
|
{/* Inline animasyonlu mark: Link'teki `group` sayesinde hover'da
|
||||||
kareler danışman panelindeki nabız animasyonuyla canlanır.
|
kareler danışman panelindeki nabız animasyonuyla canlanır. */}
|
||||||
id: tema geçişi maskesi bu noktadan yayılır (lib/tema-gecisi.ts). */}
|
<AnimasyonluMark sadeceHover className="size-8 sm:size-11" />
|
||||||
<AnimasyonluMark
|
|
||||||
id={TEMA_ODAK_ID}
|
|
||||||
sadeceHover
|
|
||||||
className="size-8 sm:size-11"
|
|
||||||
/>
|
|
||||||
<span className="truncate transition-[opacity,translate] duration-300 ease-out in-data-[nav-baslik]:pointer-events-none in-data-[nav-baslik]:-translate-y-2 in-data-[nav-baslik]:opacity-0 motion-reduce:transition-opacity">
|
<span className="truncate transition-[opacity,translate] duration-300 ease-out in-data-[nav-baslik]:pointer-events-none in-data-[nav-baslik]:-translate-y-2 in-data-[nav-baslik]:opacity-0 motion-reduce:transition-opacity">
|
||||||
<span className="text-lg font-light tracking-tighter sm:text-3xl">
|
<span className="text-lg font-light tracking-tighter sm:text-3xl">
|
||||||
Kolay
|
Kolay
|
||||||
|
|||||||
@@ -1,21 +1,48 @@
|
|||||||
// Tema geçişi (DESIGN.md §2.3): açık ↔ koyu değişimi ekranı bir anda
|
// 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
|
// çevirmez; yeni tema, KolayTercih işaretinin biçiminde önce ekranın altından
|
||||||
// başlayıp büyüyerek ekrana yayılır (View Transitions API + CSS maskesi,
|
// ortaya süzülür, sonra merkezden büyüyerek ekranı kaplar. View Transitions
|
||||||
// globals.css `.kt-tema-gecis`). Tarayıcı View Transitions bilmiyorsa ya da
|
// API + CSS maskesi (globals.css `.kt-tema-gecis`) eski/yeni görüntü çiftini
|
||||||
// kullanıcı hareketi azaltmışsa tema düz değişir.
|
// kurar; maskenin konumu, boyu, boşluk kapanışı 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.
|
||||||
|
|
||||||
/** Header'daki işaretin kök elemanı (site-header.tsx, AnimasyonluMark). */
|
import { animate, type AnimationPlaybackControls } from "motion";
|
||||||
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. */
|
/** Geçiş sırasında <html>'de duran sınıf (globals.css). */
|
||||||
const GECIS_SINIFI = "kt-tema-gecis";
|
const GECIS_SINIFI = "kt-tema-gecis";
|
||||||
|
|
||||||
|
// Saniye. Faz 1 (uçuş): işaret ekranın altından ortaya gelir — normal,
|
||||||
|
// boşluklu hâliyle. Faz 2 (kaplama): merkezden büyüyerek ekranı aşar;
|
||||||
|
// kaplamanın KAPANIS_BASI…KAPANIS_BITIS aralığında dolu çizim merkezden
|
||||||
|
// dışa büyür ve kareler arası boşlukları kapatır (en büyük hâle ulaşmadan).
|
||||||
|
// EASE fazlar arasında geçişin eski koreografisiyle aynı hissi verir.
|
||||||
|
const UCUS_SURE = 0.45;
|
||||||
|
const KAPLAMA_SURE = 0.6;
|
||||||
|
const KAPANIS_BASI = 0.55;
|
||||||
|
const KAPANIS_BITIS = 0.9;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// İşaretin dış kenarları (public/kolay-tercih-mark-dolu.svg, 180'lik viewBox;
|
||||||
|
// orijinal logonun boşlukları doldurulmuş çizimi, dış uzantılar aynı):
|
||||||
|
// x 27–147, y 29–151. Merkeze (90) göre oranlar — dolgu, bu sınır kutusu
|
||||||
|
// ekranı tam kapsadığı andan itibaren dolar; erken dolarsa ekrandaki eski
|
||||||
|
// zemin topluca solardı.
|
||||||
|
const KENAR_ORAN = {
|
||||||
|
sol: (90 - 27) / 180,
|
||||||
|
sag: (147 - 90) / 180,
|
||||||
|
ust: (90 - 29) / 180,
|
||||||
|
alt: (151 - 90) / 180,
|
||||||
|
} as const;
|
||||||
|
|
||||||
let suruyor = false;
|
let suruyor = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `uygula` temayı değiştiren çağrıdır (ör. `setTheme("dark")`). Geçiş
|
* `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;
|
* destekleniyorsa işaret ekranın altından ortaya süzülür ve oradan büyüyerek
|
||||||
* işaret ekranda değilse (krom gizli sayfalar) sol üst köşeden açılır.
|
* yeni temayı açar.
|
||||||
*/
|
*/
|
||||||
export function temayiGecisle(uygula: () => void) {
|
export function temayiGecisle(uygula: () => void) {
|
||||||
if (typeof document === "undefined") {
|
if (typeof document === "undefined") {
|
||||||
@@ -23,33 +50,103 @@ export function temayiGecisle(uygula: () => void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const azHareket = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
const azHareket = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
if (!document.startViewTransition || azHareket || suruyor) {
|
if (!document.startViewTransition || azHareket) {
|
||||||
uygula();
|
uygula();
|
||||||
return;
|
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 odak = document.getElementById(TEMA_ODAK_ID)?.getBoundingClientRect();
|
const en = window.innerWidth;
|
||||||
|
const boy = window.innerHeight;
|
||||||
const kok = document.documentElement;
|
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;
|
// Uçuş boyunca işaretin maskeden çıkan kenarı: ekranı kaplamayacak ama
|
||||||
// Maske merkezden ekranın en uzak köşesine kadar büyümeli.
|
// belirgin bir işaret olacak kadar (min ekran kenarının %22'si; işaretin
|
||||||
const uzak = Math.hypot(
|
// görünür karesi bunun ~%67'si).
|
||||||
Math.max(x, window.innerWidth - x),
|
const ucusKenar = Math.round(Math.min(en, boy) * 0.22);
|
||||||
Math.max(y, window.innerHeight - y),
|
// 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 en büyük
|
||||||
|
// hâlde köşe karesi bile ekranı aşsın (eski hesapla aynı çarpan).
|
||||||
|
const sonKenar = Math.ceil(Math.hypot(merkezX, merkezY) * 3.4);
|
||||||
|
// Dolgu, işaretin dış kutusu ekranı tam kapsadığı anda başlar (erken
|
||||||
|
// dolarsa marka henüz ekrana ulaşmadan eski zemin topluca solardı). Alt
|
||||||
|
// sınır 0.9: kapsama hesaba katılmayan dar bir marjla geç kalırsa bile
|
||||||
|
// dolgu kaplamanın son ~%10'unda bitsin; aksi hâlde ekranın köşelerinde
|
||||||
|
// eski zemin belirgin biçimde kalır.
|
||||||
|
const kapsaKenar = Math.max(
|
||||||
|
en / 2 / Math.max(KENAR_ORAN.sol, KENAR_ORAN.sag),
|
||||||
|
boy / 2 / Math.max(KENAR_ORAN.ust, KENAR_ORAN.alt),
|
||||||
|
);
|
||||||
|
const dolguBasi = Math.min(
|
||||||
|
1,
|
||||||
|
Math.max((kapsaKenar - ucusKenar) / (sonKenar - ucusKenar), 0.9),
|
||||||
);
|
);
|
||||||
|
|
||||||
kok.style.setProperty("--kt-tema-x", `${x}px`);
|
kok.style.setProperty("--kt-tema-x", `${merkezX}px`);
|
||||||
kok.style.setProperty("--kt-tema-y", `${y}px`);
|
kok.style.setProperty("--kt-tema-y", `${baslangicY}px`);
|
||||||
// İşaretin görünür karesi viewBox'ın ~%67'si; kenar bu oranla çarpılır ki
|
kok.style.setProperty("--kt-tema-kenar", `${ucusKenar}px`);
|
||||||
// en büyük hâlde köşe karesi bile ekranı aşsın.
|
kok.style.setProperty("--kt-tema-kapanis", "0");
|
||||||
kok.style.setProperty("--kt-tema-son", `${Math.ceil(uzak * 3.4)}px`);
|
kok.style.setProperty("--kt-tema-dolgu", "0");
|
||||||
|
kok.style.setProperty("--kt-tema-sure", `${GECIS_SURESI}s`);
|
||||||
kok.classList.add(GECIS_SINIFI);
|
kok.classList.add(GECIS_SINIFI);
|
||||||
suruyor = true;
|
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`),
|
||||||
|
}),
|
||||||
|
// Kapanış: dolu çizimin boyu kenar × kapanış — büyümenin ortasından
|
||||||
|
// sonuna doğru boşluklar merkezden dışa dolar, logo en büyük hâle
|
||||||
|
// ulaşmadan kapanır. Boyut sürüldüğü için ek bir katmanın alfa
|
||||||
|
// çakışması gerekmez; maske toplamı (add) değişmez.
|
||||||
|
animate(0, 1, {
|
||||||
|
duration: KAPLAMA_SURE * (KAPANIS_BITIS - KAPANIS_BASI),
|
||||||
|
delay: UCUS_SURE + KAPLAMA_SURE * KAPANIS_BASI,
|
||||||
|
ease: EASE,
|
||||||
|
onUpdate: (kapanis) => kok.style.setProperty("--kt-tema-kapanis", `${kapanis}`),
|
||||||
|
}),
|
||||||
|
// Dolgu: işaretin dış çentiklerinde kalan eski zemin son anda dolar —
|
||||||
|
// ekranı kapsayan boşluklar (kareler arası şeritler) maskenin kendisinde
|
||||||
|
// dolu çizimle kapanmıştır, burada değil.
|
||||||
|
animate(0, 1, {
|
||||||
|
duration: KAPLAMA_SURE * (1 - dolguBasi),
|
||||||
|
delay: UCUS_SURE + KAPLAMA_SURE * dolguBasi,
|
||||||
|
ease: EASE,
|
||||||
|
onUpdate: (dolgu) => kok.style.setProperty("--kt-tema-dolgu", `${dolgu}`),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
const gecis = document.startViewTransition(uygula);
|
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
|
gecis.finished
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
kontroller.forEach((k) => k.stop());
|
||||||
kok.classList.remove(GECIS_SINIFI);
|
kok.classList.remove(GECIS_SINIFI);
|
||||||
suruyor = false;
|
suruyor = false;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user