63 lines
1.7 KiB
TypeScript
63 lines
1.7 KiB
TypeScript
"use client";
|
||
|
||
import { useRef, type ReactNode } from "react";
|
||
import {
|
||
motion,
|
||
useReducedMotion,
|
||
useScroll,
|
||
useTransform,
|
||
} from "motion/react";
|
||
|
||
/**
|
||
* Site geneli hafif scroll parallax'ı. Element görünümden geçerken
|
||
* scroll'a bağlı küçük bir dikey sürüklenme uygular (yalnızca transform,
|
||
* scroll ile 1:1 — gecikme/easing yok).
|
||
*
|
||
* strength > 0: içerik scroll'dan biraz hızlı akar (ön katman).
|
||
* strength < 0: içerik scroll'un gerisinde kalır (arka katman, derinlik).
|
||
*
|
||
* `fromStart`, sayfanın tepesinde yüklenen (hero gibi) elemanlar içindir:
|
||
* sayfa en üstteyken kayma tam 0'dır, aşağı indikçe birikir — böylece
|
||
* ilk boyamada içerik kaymış görünmez.
|
||
*
|
||
* Hareket azaltılmışsa (prefers-reduced-motion) hiç kayma uygulanmaz.
|
||
*/
|
||
export function Parallax({
|
||
children,
|
||
strength = 20,
|
||
fromStart = false,
|
||
className,
|
||
}: {
|
||
children: ReactNode;
|
||
/** Piksel cinsinden sürüklenme genliği; işaret katman yönünü belirler. */
|
||
strength?: number;
|
||
fromStart?: boolean;
|
||
className?: string;
|
||
}) {
|
||
const ref = useRef<HTMLDivElement>(null);
|
||
const reduceMotion = useReducedMotion();
|
||
const { scrollYProgress } = useScroll({
|
||
target: ref,
|
||
offset: fromStart
|
||
? ["start start", "end start"]
|
||
: ["start end", "end start"],
|
||
});
|
||
const y = useTransform(
|
||
scrollYProgress,
|
||
[0, 1],
|
||
fromStart ? [0, -2 * strength] : [strength, -strength],
|
||
);
|
||
|
||
return (
|
||
<motion.div
|
||
ref={ref}
|
||
className={className}
|
||
// willChange: kayma 0'dan geçerken katmanın compositor'dan düşüp
|
||
// tekrar oluşturulmasını (raster churn) engeller
|
||
style={reduceMotion ? { y: 0 } : { y, willChange: "transform" }}
|
||
>
|
||
{children}
|
||
</motion.div>
|
||
);
|
||
}
|