feat: add animated components for enhanced UI/UX
- Introduced DrawLine component for drawing animations. - Added LazyRevealImage component for lazy loading images with reveal animations. - Implemented TextDiffuseReveal for animated text reveals with staggered effects. - Created TopProgressBar for a dynamic loading indicator. - Added PointCloud mock for testing animations. - Developed useReducedMotion hook to handle user preferences for reduced motion. - Centralized animation configurations in config.ts for easier management. - Defined animation variants in variants.ts for consistent animation effects. - Established AnimationProvider to supply global animation settings. - Created tests for AnimationProvider and useReducedMotion hook. - Added SVG assets for branding and UI elements. - Documented frontend review plan and hero circuit board animation plan.
This commit is contained in:
1 parent
0ab6930f92
commit
08dd046887
76 files changed
+21682
-1197
No files matched your search
@@ -0,0 +1,63 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useInView, useReducedMotion } from "framer-motion";
|
||||
|
||||
interface CounterValueProps {
|
||||
value: number;
|
||||
className?: string;
|
||||
duration?: number;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
once?: boolean;
|
||||
amount?: number;
|
||||
}
|
||||
|
||||
export function CounterValue({
|
||||
value,
|
||||
className = "",
|
||||
duration = 1200,
|
||||
prefix = "",
|
||||
suffix = "",
|
||||
once = true,
|
||||
amount = 0.45,
|
||||
}: Readonly<CounterValueProps>) {
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
const ref = useRef<HTMLSpanElement | null>(null);
|
||||
const isInView = useInView(ref, { once, amount });
|
||||
const [displayValue, setDisplayValue] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isInView) return;
|
||||
|
||||
if (shouldReduceMotion) {
|
||||
setDisplayValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
const start = performance.now();
|
||||
let rafId = 0;
|
||||
|
||||
const frame = (now: number) => {
|
||||
const elapsed = now - start;
|
||||
const progress = Math.min(elapsed / duration, 1);
|
||||
const eased = 1 - Math.pow(1 - progress, 3);
|
||||
setDisplayValue(Math.round(value * eased));
|
||||
|
||||
if (progress < 1) {
|
||||
rafId = requestAnimationFrame(frame);
|
||||
}
|
||||
};
|
||||
|
||||
rafId = requestAnimationFrame(frame);
|
||||
return () => cancelAnimationFrame(rafId);
|
||||
}, [isInView, value, duration, shouldReduceMotion]);
|
||||
|
||||
return (
|
||||
<span ref={ref} className={className}>
|
||||
{prefix}
|
||||
{displayValue}
|
||||
{suffix}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user