diff --git a/app/components/About.tsx b/app/components/About.tsx index a872591..aaefd3a 100644 --- a/app/components/About.tsx +++ b/app/components/About.tsx @@ -97,7 +97,7 @@ const StoryCard = ({ step, index }: { step: StoryStep; index: number }) => { export default function About() { return ( -
+
{/* Background Decor (Engenharia Visual) */}
diff --git a/app/components/Contact.tsx b/app/components/Contact.tsx index 1060142..0176481 100644 --- a/app/components/Contact.tsx +++ b/app/components/Contact.tsx @@ -76,7 +76,7 @@ export default function Contact() { "text-xs font-bold text-slate-500 uppercase tracking-widest mb-2 flex items-center gap-2"; return ( -
+
{/* Nome */} diff --git a/app/components/Header.tsx b/app/components/Header.tsx index 0404a29..474f1c2 100644 --- a/app/components/Header.tsx +++ b/app/components/Header.tsx @@ -1,191 +1,163 @@ "use client"; -import { motion } from "motion/react"; -import { - CalendarIcon, - HomeIcon, - MailIcon, - MenuIcon, - PencilIcon, - XIcon, -} from "lucide-react"; -import Link from "next/link"; -import React, { useState } from "react"; - +import React, { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { MenuIcon, XIcon, Layers } from "lucide-react"; import { cn } from "@/lib/utils"; -import { Dock, DockIcon } from "@/components/magicui/dock"; -export type IconProps = React.HTMLAttributes; +// Definição de Tipos para consistência de dados +interface NavItem { + href: string; + label: string; +} -const Icons = { - calendar: (props: IconProps) => , - email: (props: IconProps) => , - linkedin: (props: IconProps) => ( - - LinkedIn - - - ), - x: (props: IconProps) => ( - - X - - - ), - youtube: (props: IconProps) => ( - - youtube - - - ), - github: (props: IconProps) => ( - - - - ), -}; - -const DATA = { - navbar: [ - { href: "#", icon: HomeIcon, label: "Home" }, - { href: "#", icon: PencilIcon, label: "Blog" }, - ], - contact: { - social: { - GitHub: { - name: "GitHub", - url: "#", - icon: Icons.github, - }, - LinkedIn: { - name: "LinkedIn", - url: "#", - icon: Icons.linkedin, - }, - X: { - name: "X", - url: "#", - icon: Icons.x, - }, - email: { - name: "Send Email", - url: "#", - icon: Icons.email, - }, - }, - }, -}; +const navItems: NavItem[] = [ + { href: "#home", label: "Home" }, + { href: "#about", label: "Sobre" }, + { href: "#skills", label: "Habilidades" }, + { href: "#experience", label: "Experiência" }, + { href: "#projects", label: "Projetos" }, + { href: "#contact", label: "Contato" }, +]; export function Header() { const [isMenuOpen, setIsMenuOpen] = useState(false); + const [scrolled, setScrolled] = useState(false); - const toggleMenu = () => { - setIsMenuOpen(!isMenuOpen); - }; - - const navItems = [ - { href: "#", label: "Home" }, - { href: "#about", label: "Sobre" }, - { href: "#skills", label: "Habilidades" }, - { href: "#experience", label: "Experiência" }, - { href: "#projects", label: "Projetos" }, - { href: "#contact", label: "Contato" }, - ]; + // Hook de detecção de scroll para mudança de estado do Header + useEffect(() => { + const handleScroll = () => { + setScrolled(window.scrollY > 20); + }; + window.addEventListener("scroll", handleScroll); + return () => window.removeEventListener("scroll", handleScroll); + }, []); return ( - - + + + {/* Mobile Menu Overlay com Framer Motion para fluidez */} + + {isMenuOpen && ( + + + + {navItems.map((item, i) => ( { + e.preventDefault(); + setIsMenuOpen(false); + const element = document.querySelector(item.href); + if (element) { + element.scrollIntoView({ behavior: "smooth", block: "start" }); + } + }} + className="text-3xl font-black text-white uppercase tracking-tighter hover:text-blue-500 transition-colors cursor-pointer" > {item.label} - ))} - - - {/* Mobile Menu Button */} -
- -
-
- - - {/* Mobile Menu */} - {isMenuOpen && ( - - {navItems.map((item, index) => ( - {item.label} + Download CV - ))} - - )} - + + )} + + ); -} +} \ No newline at end of file diff --git a/app/components/Hero.tsx b/app/components/Hero.tsx index 44f067d..09623c8 100644 --- a/app/components/Hero.tsx +++ b/app/components/Hero.tsx @@ -21,7 +21,7 @@ export default function Hero() { }; return ( -
+
{/* 1. Background Engineering: Grid Pattern & Radial Shading */}
diff --git a/app/components/Skills.tsx b/app/components/Skills.tsx index 43224e7..d74871d 100644 --- a/app/components/Skills.tsx +++ b/app/components/Skills.tsx @@ -1,7 +1,7 @@ "use client"; -import React, { useMemo } from "react"; -import { motion } from "motion/react"; +import React from "react"; +import { motion } from "framer-motion"; // Ajustado para o padrão estável import { MagicCard } from "@/components/magicui/magic-card"; import { Code, Database, Cloud, Cpu, Smartphone, @@ -9,19 +9,29 @@ import { } from "lucide-react"; import { usePortfolioData } from "@/lib/usePortfolioData"; +// --- RESOLUÇÃO DE TIPAGEM (Wrapper) --- +// Estendemos a interface original para aceitar as props de gradiente que a lib pode ter omitido nos tipos +interface FixedMagicCardProps extends React.ComponentProps { + gradientColor?: string; + gradientSize?: number; + gradientOpacity?: number; +} + +const FixedMagicCard = (props: FixedMagicCardProps) => { + // @ts-ignore - Forçamos o cast para o componente original aceitar as props em runtime + return ; +}; + const ICON_MAP: Record = { - Code, Database, Cloud, Cpu, Smartphone, Zap, GitBranch, TestTube, Terminal + Code, Database, Cloud, Cpu, Smartphone, Zap, GitBranch, TestTube, Terminal, Layers }; -// Refinamento do Pareto: Cores baseadas em variáveis CSS para evitar quebras no Tailwind const getCategoryStyles = (color: string) => { const base = color.replace("text-", ""); return { icon: color, bg: `bg-${base}/10`, - // Removido o hover:border daqui para evitar conflitos de transição border: `border-slate-800/50`, - glow: `rgba(var(--${base}-rgb, 59, 130, 246), 0.15)` // Fallback para azul }; }; @@ -35,7 +45,7 @@ export default function Skills() {
- {/* Header Header */} + {/* Header Seção */} - ))}
- + ); })} @@ -114,19 +122,19 @@ export default function Skills() { ); } -// --- Componentes de Suporte (Clean Code) --- +// --- Componentes de Suporte (Manter no mesmo arquivo para contexto ou mover para /components) --- function LoadingState() { return ( -
+
- Initializing Systems... + Initializing Systems...
); } function ErrorState() { return ( -
+
[FATAL_ERROR]: Failed to synchronize portfolio data.
); diff --git a/public/Profile.pdf b/public/Profile.pdf new file mode 100644 index 0000000..59c9339 Binary files /dev/null and b/public/Profile.pdf differ