feat(experience): skills e experiencia visiveis (aberta em telas largas) e link Experiencia no menu

- ExperienceDisclosure abre a gaveta em >=1024px e quando o link aponta para #experience/#skills; no celular segue recolhida
- novo item Experiencia em NAVIGATION_ITEMS (desktop e menu mobile); testes do Header atualizados

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
Evandro Fonseca JuniorandClaude Sonnet 5.5 committed 2026-10-04 23:42:27 -03:00
1 parent d5f04162a8
commit 2b5b4a2267
4 files changed
+82 -7

No files matched your search

+15 -2
View File
@@ -32,7 +32,13 @@ describe("Header", () => {
within(navigation)
.getAllByRole("link")
.map((link) => link.getAttribute("href")),
).toEqual(["/#modalities", "/cases", "/#process", "/#about"]);
).toEqual([
"/#modalities",
"/cases",
"/#process",
"/#about",
"/#experience",
]);
const contactLink = screen
.getAllByRole("link")
.find((link) => link.getAttribute("href") === "/#contact");
@@ -68,7 +74,14 @@ describe("Header", () => {
within(mobileNavigation)
.getAllByRole("link")
.map((link) => link.getAttribute("href")),
).toEqual(["/#modalities", "/cases", "/#process", "/#about", "/#contact"]);
).toEqual([
"/#modalities",
"/cases",
"/#process",
"/#about",
"/#experience",
"/#contact",
]);
expect(
within(mobileNavigation).queryByRole("link", {
name: /currículo|download cv/i,
+3 -5
View File
@@ -16,6 +16,7 @@ import Projects from "../Projects";
import Skills from "../Skills";
import NotebookStory from "../story/NotebookStory";
import { WorkModalities } from "../WorkModalities";
import ExperienceDisclosure from "./ExperienceDisclosure";
import ScrollVelocityText from "./ScrollVelocityText";
import SectionDivider from "./SectionDivider";
import { useHomeFragmentNavigation } from "./useHomeFragmentNavigation";
@@ -56,13 +57,10 @@ export default function CinematicHome({
<About />
<details className="ds-section !pt-0">
<summary className="ds-section-shell cursor-pointer py-sp-5 text-lg font-semibold">
Experiência e tecnologias por trás das entregas
</summary>
<ExperienceDisclosure>
<Skills categories={skillCategories} />
<Experience experiences={experiences} />
</details>
</ExperienceDisclosure>
<div className="overflow-hidden bg-[var(--ink)] py-6 text-[rgba(244,242,237,0.05)]">
<ScrollVelocityText text="VAMOS CONSTRUIR" direction="left" />
@@ -0,0 +1,63 @@
"use client";
import { type ReactNode, useEffect, useState } from "react";
const TARGETS = new Set(["#experience", "#skills"]);
/**
* Skills e Experiência ficavam numa gaveta sempre fechada e sem link no menu.
* Agora abre sozinha em telas largas (onde há espaço) e quando um link aponta para #experience ou #skills;
* no celular continua recolhida para a página não crescer.
*/
export default function ExperienceDisclosure({
children,
}: {
children: ReactNode;
}) {
const [open, setOpen] = useState(false);
useEffect(() => {
const reveal = (hash: string) => {
if (!TARGETS.has(hash)) return;
setOpen(true);
// espera o React abrir a gaveta para o alvo existir no layout
requestAnimationFrame(() =>
document
.getElementById(hash.slice(1))
?.scrollIntoView({ behavior: "instant", block: "start" }),
);
};
if (window.matchMedia("(min-width: 1024px)").matches) setOpen(true);
else if (TARGETS.has(window.location.hash)) setOpen(true);
const onClick = (event: MouseEvent) => {
const link =
event.target instanceof Element
? event.target.closest("a[href*='#']")
: null;
if (!(link instanceof HTMLAnchorElement)) return;
const url = new URL(link.href);
if (url.pathname === window.location.pathname) reveal(url.hash);
};
const onHashChange = () => reveal(window.location.hash);
document.addEventListener("click", onClick);
window.addEventListener("hashchange", onHashChange);
return () => {
document.removeEventListener("click", onClick);
window.removeEventListener("hashchange", onHashChange);
};
}, []);
return (
<details
open={open}
onToggle={(event) => setOpen(event.currentTarget.open)}
className="ds-section !pt-0"
>
<summary className="ds-section-shell cursor-pointer py-sp-5 text-lg font-semibold">
Experiência e tecnologias por trás das entregas
</summary>
{children}
</details>
);
}