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,101 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import Hero from "./Hero";
|
||||
|
||||
let mockReducedMotion = false;
|
||||
|
||||
jest.mock("framer-motion", () => {
|
||||
const React = require("react");
|
||||
|
||||
const motion = new Proxy(
|
||||
{},
|
||||
{
|
||||
get: (_, tag: string) => {
|
||||
const Component = ({
|
||||
children,
|
||||
initial,
|
||||
animate,
|
||||
whileHover,
|
||||
whileTap,
|
||||
...props
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
initial?: unknown;
|
||||
animate?: unknown;
|
||||
whileHover?: unknown;
|
||||
whileTap?: unknown;
|
||||
} & Record<string, unknown>) => {
|
||||
const dataProps = {
|
||||
...(initial !== undefined
|
||||
? { "data-initial": JSON.stringify(initial) }
|
||||
: {}),
|
||||
...(animate !== undefined
|
||||
? { "data-animate": JSON.stringify(animate) }
|
||||
: {}),
|
||||
...(whileHover !== undefined
|
||||
? { "data-while-hover": JSON.stringify(whileHover) }
|
||||
: {}),
|
||||
...(whileTap !== undefined
|
||||
? { "data-while-tap": JSON.stringify(whileTap) }
|
||||
: {}),
|
||||
};
|
||||
|
||||
return React.createElement(tag, { ...props, ...dataProps }, children);
|
||||
};
|
||||
Component.displayName = `motion.${tag}`;
|
||||
return Component;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
AnimatePresence: ({ children }: { children: React.ReactNode }) => children,
|
||||
motion,
|
||||
useInView: () => true,
|
||||
useReducedMotion: () => mockReducedMotion,
|
||||
};
|
||||
});
|
||||
|
||||
describe("Hero reduced motion", () => {
|
||||
afterEach(() => {
|
||||
mockReducedMotion = false;
|
||||
});
|
||||
|
||||
it("removes hover/tap scale animations when reduced motion is enabled", () => {
|
||||
mockReducedMotion = true;
|
||||
|
||||
const { container } = render(<Hero />);
|
||||
|
||||
const primaryAction = screen.getByText(/Iniciar projeto/i).closest("a");
|
||||
const secondaryAction = screen.getByText(/Ver projetos/i).closest("a");
|
||||
|
||||
expect(primaryAction).not.toHaveAttribute("data-while-hover");
|
||||
expect(primaryAction).not.toHaveAttribute("data-while-tap");
|
||||
expect(secondaryAction).not.toHaveAttribute("data-while-hover");
|
||||
expect(secondaryAction).not.toHaveAttribute("data-while-tap");
|
||||
|
||||
const rootMotionBlock = container.querySelector(
|
||||
"div[data-initial][data-animate]",
|
||||
);
|
||||
expect(rootMotionBlock).toBeInTheDocument();
|
||||
expect(rootMotionBlock?.getAttribute("data-initial")).toContain(
|
||||
'"opacity":0',
|
||||
);
|
||||
expect(rootMotionBlock?.getAttribute("data-animate")).toContain(
|
||||
'"opacity":1',
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps essential hero content visible with reduced motion enabled", () => {
|
||||
mockReducedMotion = true;
|
||||
|
||||
render(<Hero />);
|
||||
|
||||
expect(screen.getByLabelText("evandro.dev.br")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(/Available for selected builds/i),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText(/Execution Brief/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user