diff --git a/app/components/Contact.tsx b/app/components/Contact.tsx
index c0d27e8..2f2983c 100644
--- a/app/components/Contact.tsx
+++ b/app/components/Contact.tsx
@@ -39,8 +39,7 @@ export default function Contact() {
Retorno inicial em até 24h
Ideal para discovery técnico, revisão de arquitetura, rescue de
- projeto, otimização de performance ou construção de produto do
- zero.
+ projeto, otimização de performance ou construção de produto do zero.
WhatsApp: +55 47 99274-2365
@@ -63,7 +62,10 @@ export default function Contact() {
setFormData({ ...formData, name: e.target.value })
}
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.06)] px-sp-4 py-[14px] text-[12px] outline-none transition-colors focus:border-slash"
- style={{ color: "#fff", backgroundColor: "rgba(255,255,255,0.06)" }}
+ style={{
+ color: "#fff",
+ backgroundColor: "rgba(255,255,255,0.06)",
+ }}
/>
@@ -79,7 +81,10 @@ export default function Contact() {
setFormData({ ...formData, email: e.target.value })
}
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.06)] px-sp-4 py-[14px] text-[12px] outline-none transition-colors focus:border-slash"
- style={{ color: "#fff", backgroundColor: "rgba(255,255,255,0.06)" }}
+ style={{
+ color: "#fff",
+ backgroundColor: "rgba(255,255,255,0.06)",
+ }}
/>
@@ -114,7 +119,10 @@ export default function Contact() {
setFormData({ ...formData, message: e.target.value })
}
className="mt-sp-2 w-full resize-none border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.06)] px-sp-4 py-[14px] text-[12px] outline-none transition-colors focus:border-slash"
- style={{ color: "#fff", backgroundColor: "rgba(255,255,255,0.06)" }}
+ style={{
+ color: "#fff",
+ backgroundColor: "rgba(255,255,255,0.06)",
+ }}
/>
diff --git a/app/components/Header.tsx b/app/components/Header.tsx
index 639f956..0cf1362 100644
--- a/app/components/Header.tsx
+++ b/app/components/Header.tsx
@@ -17,9 +17,7 @@ export function Header() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
return (
-
+
diff --git a/app/components/Hero.tsx b/app/components/Hero.tsx
index 158d11a..e9af4ee 100644
--- a/app/components/Hero.tsx
+++ b/app/components/Hero.tsx
@@ -1,5 +1,7 @@
"use client";
+import { useState, useEffect } from "react";
+import { motion, AnimatePresence } from "framer-motion";
import { Logo } from "./Logo";
const SOCIAL_LINKS = [
@@ -30,13 +32,103 @@ const SOCIAL_LINKS = [
},
];
-const STATS = [
- { value: "4", accent: "px", label: "Base unit" },
- { value: "9", accent: "x", label: "Type scale" },
- { value: "4", accent: "+", label: "Core tokens" },
-];
+const textToType = "evandro.dev.br";
export default function Hero() {
+ const [phase, setPhase] = useState<"typing" | "idle" | "glitch" | "logo">(
+ "typing",
+ );
+ const [typedCount, setTypedCount] = useState(0);
+
+ useEffect(() => {
+ let timeout: NodeJS.Timeout;
+
+ if (phase === "typing") {
+ if (typedCount < textToType.length) {
+ timeout = setTimeout(() => {
+ setTypedCount((c) => c + 1);
+ }, 120); // typing speed
+ } else {
+ timeout = setTimeout(() => {
+ setPhase("idle");
+ }, 1200); // Wait after typing finishes
+ }
+ } else if (phase === "idle") {
+ timeout = setTimeout(() => {
+ setPhase("glitch");
+ }, 100); // trigger glitch
+ } else if (phase === "glitch") {
+ timeout = setTimeout(() => {
+ setPhase("logo");
+ }, 600); // Glitch out duration
+ } else if (phase === "logo") {
+ timeout = setTimeout(() => {
+ setTypedCount(0);
+ setPhase("typing");
+ }, 3500); // Logo display and blink duration
+ }
+
+ return () => clearTimeout(timeout);
+ }, [phase, typedCount]);
+
+ const renderTypedText = () => {
+ const chars = [];
+ for (let i = 0; i < typedCount; i++) {
+ const char = textToType[i];
+ if (i < 7) {
+ chars.push(
+
+ {char}
+ ,
+ );
+ } else if (i === 7) {
+ chars.push( );
+ chars.push(
+
+ {char}
+ ,
+ );
+ } else if (i < 11) {
+ chars.push(
+
+ {char}
+ ,
+ );
+ } else if (i === 11) {
+ chars.push( );
+ chars.push(
+
+ {char}
+ ,
+ );
+ } else {
+ chars.push(
+
+ {char}
+ ,
+ );
+ }
+ }
+ // blinking cursor
+ if (phase === "typing" || phase === "idle") {
+ chars.push(
+
+ _
+ ,
+ );
+ }
+ return chars;
+ };
+
const hour = new Date().getHours();
const greeting =
hour >= 8 && hour < 12
@@ -53,8 +145,13 @@ export default function Hero() {
-
-
+
+
-
- evandro
-
- .dev
-
- .br
-
+
+
+ {(phase === "typing" || phase === "idle") && (
+
+ {renderTypedText()}
+
+ )}
+
+ {phase === "logo" && (
+
+
+
+ )}
+
+
-
+
Iniciar projeto
+
+ Download CV
+
+
-
-
-
-
- EV / LOGO MARK
-
-
-
-
-
-
-
-
-
-
-
-
- CONCEITO ESCOLHIDO
-
-
-
-
- EV / Full mark · identidade visual
-
-
-
- Escala: 280x280 · svg viewbox
-
-
+
);
diff --git a/app/components/WorkModalities.tsx b/app/components/WorkModalities.tsx
index 5d0926e..d058ce9 100644
--- a/app/components/WorkModalities.tsx
+++ b/app/components/WorkModalities.tsx
@@ -92,7 +92,9 @@ function TierCard({ tier }: { tier: Tier }) {
onBlur={() => setHovered(false)}
tabIndex={0}
style={{
- border: tier.featured ? "2px solid #0A0A0A" : "1px solid rgba(10,10,10,0.1)",
+ border: tier.featured
+ ? "2px solid #0A0A0A"
+ : "1px solid rgba(10,10,10,0.1)",
background: tier.featured ? "#0A0A0A" : "#fff",
padding: "var(--sp-6)",
display: "flex",
@@ -108,7 +110,13 @@ function TierCard({ tier }: { tier: Tier }) {
}}
>
{/* Top row */}
-
+
@@ -159,7 +171,15 @@ function TierCard({ tier }: { tier: Tier }) {
{/* Description */}
-
+
{tier.description}
@@ -183,7 +203,9 @@ function TierCard({ tier }: { tier: Tier }) {
{/* Pricing */}
@@ -198,7 +220,16 @@ function TierCard({ tier }: { tier: Tier }) {
>
{tier.pricing}
-
diff --git a/app/components/ui/NumberIcons.tsx b/app/components/ui/NumberIcons.tsx
index 5715d84..c08ed65 100644
--- a/app/components/ui/NumberIcons.tsx
+++ b/app/components/ui/NumberIcons.tsx
@@ -1,5 +1,5 @@
// src/components/ui/NumberIcons.tsx
-import React from 'react';
+import React from "react";
interface NumberIconProps extends React.SVGProps
{
/** Tamanho em pixels. Escala mantendo o viewBox 80x80 */
@@ -9,9 +9,9 @@ interface NumberIconProps extends React.SVGProps {
}
const baseProps = {
- fill: 'none',
- xmlns: 'http://www.w3.org/2000/svg',
- viewBox: '0 0 80 80',
+ fill: "none",
+ xmlns: "http://www.w3.org/2000/svg",
+ viewBox: "0 0 80 80",
};
/**
@@ -22,44 +22,53 @@ const GraphicShell = () => (
<>
{/* Base Background */}
-
+
{/* Borda reativa ao hover */}
-
-
+
{/* Grid de background sutil (Cyberpunk/Tech feel) */}
{/* Brand Slash (Acento) com Motion */}
-
>
);
-export const NumberOne = ({ size = 80, className = '', ...props }: NumberIconProps) => (
- (
+
-
1
@@ -67,23 +76,28 @@ export const NumberOne = ({ size = 80, className = '', ...props }: NumberIconPro
);
-export const NumberTwo = ({ size = 80, className = '', ...props }: NumberIconProps) => (
- (
+
-
2
@@ -91,23 +105,28 @@ export const NumberTwo = ({ size = 80, className = '', ...props }: NumberIconPro
);
-export const NumberThree = ({ size = 80, className = '', ...props }: NumberIconProps) => (
- (
+
-
3
@@ -115,23 +134,28 @@ export const NumberThree = ({ size = 80, className = '', ...props }: NumberIconP
);
-export const NumberFour = ({ size = 80, className = '', ...props }: NumberIconProps) => (
- (
+
-
4
diff --git a/app/globals.css b/app/globals.css
index bbf74fd..e934e92 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,16 +1,16 @@
@import url("https://fonts.googleapis.com/css2?family=Syne:wght@400;500;600;700;800&family=Geist+Mono:wght@300;400;500;600&display=swap");
@font-face {
- font-family: 'Monument Extended';
- src: url('/fonts/MonumentExtended-Regular.otf') format('opentype');
+ font-family: "Monument Extended";
+ src: url("/fonts/MonumentExtended-Regular.otf") format("opentype");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
- font-family: 'Monument Extended';
- src: url('/fonts/MonumentExtended-Ultrabold.otf') format('opentype');
+ font-family: "Monument Extended";
+ src: url("/fonts/MonumentExtended-Ultrabold.otf") format("opentype");
font-weight: 800;
font-style: normal;
font-display: swap;
@@ -66,7 +66,7 @@
--r-lg: 16px;
--r-full: 999px;
--font-display: "Syne", sans-serif;
- --font-hero: 'Monument Extended', sans-serif;
+ --font-hero: "Monument Extended", sans-serif;
--font-mono: "Geist Mono", monospace;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
@@ -124,7 +124,7 @@ textarea {
}
.ds-main {
- padding-top: 52px;
+ /* padding-top: 52px; removed since there is no header now */
}
.ds-section {
diff --git a/app/page.tsx b/app/page.tsx
index 16416a7..dad2d05 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,7 +1,6 @@
import About from "./components/About";
import Contact from "./components/Contact";
import Experience from "./components/Experience";
-import { Header } from "./components/Header";
import Hero from "./components/Hero";
import Projects from "./components/Projects";
import Skills from "./components/Skills";
@@ -10,7 +9,6 @@ import { WorkModalities } from "./components/WorkModalities";
export default function Home() {
return (