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,49 @@
|
||||
import { renderHook } from "@testing-library/react";
|
||||
import { useReducedMotion } from "./useReducedMotion";
|
||||
|
||||
// Mock do Framer Motion
|
||||
jest.mock("framer-motion", () => ({
|
||||
useReducedMotion: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("useReducedMotion", () => {
|
||||
it("deve retornar false quando prefers-reduced-motion não está ativo", () => {
|
||||
const { useReducedMotion: mockUseReducedMotion } =
|
||||
jest.requireMock("framer-motion");
|
||||
mockUseReducedMotion.mockReturnValue(false);
|
||||
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it("deve retornar true quando prefers-reduced-motion está ativo", () => {
|
||||
const { useReducedMotion: mockUseReducedMotion } =
|
||||
jest.requireMock("framer-motion");
|
||||
mockUseReducedMotion.mockReturnValue(true);
|
||||
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it("deve retornar false quando o hook do Framer Motion retorna null", () => {
|
||||
const { useReducedMotion: mockUseReducedMotion } =
|
||||
jest.requireMock("framer-motion");
|
||||
mockUseReducedMotion.mockReturnValue(null);
|
||||
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it("deve retornar false quando o hook do Framer Motion retorna undefined", () => {
|
||||
const { useReducedMotion: mockUseReducedMotion } =
|
||||
jest.requireMock("framer-motion");
|
||||
mockUseReducedMotion.mockReturnValue(undefined);
|
||||
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
"use client";
|
||||
|
||||
import { useReducedMotion as useFramerReducedMotion } from "framer-motion";
|
||||
|
||||
/**
|
||||
* Hook que detecta a preferência prefers-reduced-motion do sistema operacional.
|
||||
* Wrapper sobre o hook useReducedMotion do Framer Motion.
|
||||
*
|
||||
* @returns {boolean} true se prefers-reduced-motion está ativo, false caso contrário
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const reducedMotion = useReducedMotion();
|
||||
*
|
||||
* return (
|
||||
* <motion.div
|
||||
* animate={{ opacity: 1, y: reducedMotion ? 0 : 20 }}
|
||||
* />
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export function useReducedMotion(): boolean {
|
||||
return useFramerReducedMotion() ?? false;
|
||||
}
|
||||
@@ -14,10 +14,10 @@ export function useScrollReveal(options?: {
|
||||
scrub?: boolean | number;
|
||||
}) {
|
||||
const ref = useRef<HTMLElement>(null);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) return;
|
||||
|
||||
|
||||
// Lazy registration to avoid Next.js hydration mismatch issues
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
@@ -37,12 +37,20 @@ export function useScrollReveal(options?: {
|
||||
end: options?.end ?? "top 50%",
|
||||
scrub: options?.scrub ?? false,
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}, ref);
|
||||
|
||||
return () => ctx.revert();
|
||||
}, [options?.y, options?.duration, options?.delay, options?.ease, options?.start, options?.end, options?.scrub]);
|
||||
}, [
|
||||
options?.y,
|
||||
options?.duration,
|
||||
options?.delay,
|
||||
options?.ease,
|
||||
options?.start,
|
||||
options?.end,
|
||||
options?.scrub,
|
||||
]);
|
||||
|
||||
return ref;
|
||||
}
|
||||
Reference in new issue
Block a user