feat: rebuild landing experience, content and analytics

This commit is contained in:
Evandro Fonseca Junior committed 2026-09-13 04:30:58 -03:00
1 parent d24ee12299
commit 9aff4d1035
51 files changed
+3023 -2595

No files matched your search

+66 -22
View File
@@ -1,4 +1,11 @@
import { act, render, screen, waitFor } from "@testing-library/react";
import {
act,
fireEvent,
render,
screen,
waitFor,
within,
} from "@testing-library/react";
import { getFeaturedProjects } from "@/lib/portfolio-data";
import NotebookStory, { canUseNotebook3D } from "./NotebookStory";
@@ -29,6 +36,7 @@ jest.mock("gsap/ScrollTrigger", () => ({
const projects = getFeaturedProjects(null);
let intersectionCallback: IntersectionObserverCallback | undefined;
let reducedMotionListener: (() => void) | undefined;
const mockObserve = jest.fn();
const mockDisconnect = jest.fn();
@@ -63,7 +71,11 @@ function mockMatchMedia({
(query === "(hover: hover)" && hover),
media: query,
onchange: null,
addEventListener: jest.fn(),
addEventListener: jest.fn((event: string, callback: () => void) => {
if (query === "(prefers-reduced-motion: reduce)" && event === "change") {
reducedMotionListener = callback;
}
}),
removeEventListener: jest.fn(),
addListener: jest.fn(),
removeListener: jest.fn(),
@@ -80,6 +92,7 @@ describe("NotebookStory", () => {
});
setDocumentHidden(false);
intersectionCallback = undefined;
reducedMotionListener = undefined;
mockObserve.mockReset();
mockDisconnect.mockReset();
class MockIntersectionObserver {
@@ -115,17 +128,53 @@ describe("NotebookStory", () => {
);
});
it("does not initialize the 3D stage on coarse pointers", async () => {
mockMatchMedia({ coarse: true });
it("initializes the 3D stage on a narrow touch viewport without hover", async () => {
mockMatchMedia({ coarse: true, hover: false });
Object.defineProperty(window, "innerWidth", {
configurable: true,
value: 390,
});
render(<NotebookStory projects={projects} />);
expect(screen.getByTestId("notebook-fallback")).toBeInTheDocument();
await waitFor(() =>
expect(screen.queryByTestId("notebook-stage")).not.toBeInTheDocument(),
expect(await screen.findByTestId("notebook-stage")).toBeInTheDocument();
expect(screen.queryByTestId("notebook-fallback")).not.toBeInTheDocument();
});
it("lets touch users select and open a project outside the scaled screen", async () => {
mockMatchMedia({ coarse: true, hover: false });
render(<NotebookStory projects={projects} />);
await screen.findByTestId("notebook-stage");
const controls = screen.getByRole("navigation", {
name: "Navegar projetos do notebook",
});
const button = within(controls).getByRole("button", {
name: /Mostrar SC/i,
});
fireEvent.click(button);
expect(button).toHaveAttribute("aria-pressed", "true");
expect(
within(controls).getByRole("link", { name: /Abrir projeto/i }),
).toHaveAttribute(
"href",
projects.find((project) => project.id === "sc-plus")?.demoUrl,
);
});
it("initializes the 3D stage only on a desktop hover-capable viewport", async () => {
it("returns to static content if reduced motion is enabled during the story", async () => {
mockMatchMedia({ coarse: true, hover: false });
render(<NotebookStory projects={projects} />);
await screen.findByTestId("notebook-stage");
mockMatchMedia({ reduced: true, coarse: true, hover: false });
act(() => reducedMotionListener?.());
expect(screen.getByTestId("notebook-fallback")).toBeInTheDocument();
expect(screen.queryByTestId("notebook-stage")).not.toBeInTheDocument();
});
it("initializes the 3D stage on a desktop viewport", async () => {
render(<NotebookStory projects={projects} />);
await waitFor(() =>
@@ -155,22 +204,19 @@ describe("NotebookStory", () => {
act(() => document.dispatchEvent(new Event("visibilitychange")));
expect(stage).toHaveAttribute("data-is-visible", "false");
});
it("returns to the static fallback when the viewport loses desktop eligibility", async () => {
it("keeps the mounted 3D stage when resizing from desktop to touch mobile", async () => {
render(<NotebookStory projects={projects} />);
await waitFor(() =>
expect(screen.getByTestId("notebook-stage")).toBeInTheDocument(),
);
const stage = await screen.findByTestId("notebook-stage");
Object.defineProperty(window, "innerWidth", {
configurable: true,
value: 800,
value: 360,
});
window.dispatchEvent(new Event("resize"));
mockMatchMedia({ coarse: true, hover: false });
act(() => window.dispatchEvent(new Event("resize")));
await waitFor(() =>
expect(screen.queryByTestId("notebook-stage")).not.toBeInTheDocument(),
);
expect(screen.getByTestId("notebook-fallback")).toBeInTheDocument();
expect(screen.getByTestId("notebook-stage")).toBe(stage);
expect(screen.queryByTestId("notebook-fallback")).not.toBeInTheDocument();
});
it("keeps the static fallback when no mapped projects are available", async () => {
@@ -187,17 +233,15 @@ describe("NotebookStory", () => {
);
});
it("requires desktop hover input without reduced motion", () => {
it("respects reduced motion independently of width and pointer capabilities", () => {
const matchMedia = (query: string) =>
({
matches: query === "(hover: hover)",
}) as MediaQueryList;
expect(canUseNotebook3D({ innerWidth: 1280, matchMedia })).toBe(true);
expect(canUseNotebook3D({ innerWidth: 1024, matchMedia })).toBe(false);
expect(canUseNotebook3D({ matchMedia })).toBe(true);
expect(
canUseNotebook3D({
innerWidth: 1280,
matchMedia: (query) =>
({
matches: