update light effects

This commit is contained in:
Nikita 2026-09-16 23:15:46 +05:00
parent 401f80f484
commit da7c67734f
2 changed files with 48 additions and 7 deletions

View file

@ -1,6 +1,6 @@
"use client";
import { useRef, type CSSProperties, type MouseEvent } from "react";
import { useEffect, useRef, type CSSProperties, type MouseEvent } from "react";
import styles from "@/static/hero/flashlight.module.css";
@ -13,6 +13,9 @@ type FlashlightTextProps = {
const FlashlightText = ({ text }: FlashlightTextProps) => {
const ref = useRef<HTMLSpanElement>(null);
const mouseX = useRef(-1);
const mouseY = useRef(-1);
const setPosition = (x: number, y: number) => {
const element = ref.current;
if (!element) return;
@ -21,10 +24,40 @@ const FlashlightText = ({ text }: FlashlightTextProps) => {
element.style.setProperty("--fy", `${y}px`);
};
const syncWithPointer = () => {
const element = ref.current;
if (!element) return;
const point = document.elementFromPoint(mouseX.current, mouseY.current
);
if (point && element.contains(point)) {
const rect = element.getBoundingClientRect();
setPosition(mouseX.current - rect.left, mouseY.current - rect.top);
element.classList.remove(styles.idle);
} else {
setPosition(OFFSCREEN, OFFSCREEN);
element.classList.add(styles.idle);
}
};
useEffect(() => {
const onScroll = () => syncWithPointer();
window.addEventListener("scroll", onScroll, { capture: true, passive: true });
return () =>
window.removeEventListener("scroll", onScroll, { capture: true });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleMove = (e: MouseEvent<HTMLSpanElement>) => {
const element = ref.current;
if (!element) return;
mouseX.current = e.clientX;
mouseY.current = e.clientY;
const rect = element.getBoundingClientRect();
setPosition(e.clientX - rect.left, e.clientY - rect.top);

View file

@ -36,14 +36,20 @@ const Cursor = () => {
setVisible(true);
};
const onPointerOver = (e: PointerEvent) => {
const target = e.target as HTMLElement | null;
const interactive = target?.closest(
"a, button, [role='button'], input, select, textarea, [data-cursor-hover]"
const isInteractive = (target: Element | null) =>
Boolean(
target?.closest(
"a, button, [role='button'], input, select, textarea, [data-cursor-hover]"
)
);
setHovering(Boolean(interactive));
const onPointerOver = (e: PointerEvent) => {
setHovering(isInteractive(e.target as Element | null));
};
const onScroll = () => {
const target = document.elementFromPoint(mouseX, mouseY);
setHovering(isInteractive(target));
};
const onPointerDown = () => setPressed(true);
@ -62,6 +68,7 @@ const Cursor = () => {
window.addEventListener("pointermove", onPointerMove, { passive: true });
window.addEventListener("pointerover", onPointerOver, { passive: true });
window.addEventListener("scroll", onScroll, { capture: true, passive: true });
window.addEventListener("pointerdown", onPointerDown);
window.addEventListener("pointerup", onPointerUp);
@ -71,6 +78,7 @@ const Cursor = () => {
cancelAnimationFrame(raf);
window.removeEventListener("pointermove", onPointerMove);
window.removeEventListener("pointerover", onPointerOver);
window.removeEventListener("scroll", onScroll, { capture: true });
window.removeEventListener("pointerdown", onPointerDown);
window.removeEventListener("pointerup", onPointerUp);
document.documentElement.classList.remove("has-cursor");