CI / verify (push) Failing after 5m9s
Align the notebook browser with the physical LCD, refresh real project captures and navigation, simplify service content, and stabilize hero hydration.
77 lines
2.2 KiB
TypeScript
77 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useId, useState } from "react";
|
|
|
|
interface ScrollVelocityTextProps {
|
|
text: string;
|
|
direction: "left" | "right";
|
|
className?: string;
|
|
}
|
|
|
|
const GROUPS = [0, 1] as const;
|
|
|
|
export default function ScrollVelocityText({
|
|
text,
|
|
direction,
|
|
className = "",
|
|
}: ScrollVelocityTextProps) {
|
|
const trackId = useId();
|
|
const [isPaused, setIsPaused] = useState(false);
|
|
const [shouldReduceMotion, setShouldReduceMotion] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
setShouldReduceMotion(media.matches);
|
|
const updatePreference = (event: MediaQueryListEvent) => {
|
|
setShouldReduceMotion(event.matches);
|
|
};
|
|
media.addEventListener("change", updatePreference);
|
|
return () => media.removeEventListener("change", updatePreference);
|
|
}, []);
|
|
|
|
const animationPaused = shouldReduceMotion || isPaused;
|
|
|
|
return (
|
|
<div className={`scroll-velocity-text ${className}`.trim()}>
|
|
<div className="scroll-velocity-viewport">
|
|
<div
|
|
id={trackId}
|
|
className={`scroll-velocity-track ${
|
|
direction === "left" ? "animate-marquee" : "animate-marquee-reverse"
|
|
}`}
|
|
style={{
|
|
animationPlayState: animationPaused ? "paused" : undefined,
|
|
}}
|
|
>
|
|
{GROUPS.map((group) => (
|
|
<span
|
|
key={group}
|
|
className="scroll-velocity-group"
|
|
aria-hidden={group === 0 ? undefined : "true"}
|
|
>
|
|
<span className="scroll-velocity-item">
|
|
<span aria-hidden={group === 0 ? "false" : "true"}>{text}</span>
|
|
<span aria-hidden="true" className="scroll-velocity-dot">
|
|
•
|
|
</span>
|
|
</span>
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{!shouldReduceMotion ? (
|
|
<button
|
|
type="button"
|
|
className="scroll-velocity-control"
|
|
aria-controls={trackId}
|
|
aria-pressed={isPaused}
|
|
onClick={() => setIsPaused((paused) => !paused)}
|
|
>
|
|
{isPaused ? "Retomar animação" : "Pausar animação"}
|
|
</button>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|