feat: Implement initial portfolio website structure with core components and a new post creator tool.
This commit is contained in:
1 parent
036363b521
commit
aa07d6faeb
15 files changed
+1337
-1855
No files matched your search
+62
-166
@@ -1,194 +1,90 @@
|
||||
"use client";
|
||||
import { Section } from "./Section";
|
||||
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { LucideIcon, Brain, Zap, Target, Rocket, Users, Lightbulb, Code, Shield, Terminal, Cpu } from "lucide-react";
|
||||
import Squares from "@/components/Squares";
|
||||
|
||||
// --- Types & Interfaces (Tipagem Forte para Previsibilidade) ---
|
||||
interface StoryStep {
|
||||
icon: LucideIcon;
|
||||
title: string;
|
||||
content: string;
|
||||
gradient: string;
|
||||
accent: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface CoreValue {
|
||||
icon: LucideIcon;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
// --- Data (Desacoplado para facilitar manutenção/CMS) ---
|
||||
const STORY_DATA: StoryStep[] = [
|
||||
const STORY_DATA = [
|
||||
{
|
||||
id: "KERNEL_INIT",
|
||||
icon: Brain,
|
||||
title: "Engenharia de Fundamentos",
|
||||
content: "Minha mentalidade é pautada pela redução de entropia. Não apenas escrevo código; projeto sistemas onde a escalabilidade é uma propriedade intrínseca da arquitetura, não um ajuste posterior.",
|
||||
gradient: "from-blue-600 to-cyan-500",
|
||||
accent: "text-blue-400",
|
||||
title: "Engenharia de fundamentos",
|
||||
content:
|
||||
"Projeto sistemas com foco em previsibilidade, manutenção e crescimento real. Escala entra na arquitetura desde o inÃcio.",
|
||||
},
|
||||
{
|
||||
id: "RUNTIME_EXEC",
|
||||
icon: Zap,
|
||||
title: "Entrega sob Restrições",
|
||||
content: "Em 3 anos de atuação profissional, especializei-me em cenários de alta criticidade. Atuei na ponte entre sistemas legados e microserviços, garantindo a resolução do problema.",
|
||||
gradient: "from-purple-600 to-pink-600",
|
||||
accent: "text-purple-400",
|
||||
title: "Entrega sob restrições",
|
||||
content:
|
||||
"Atuo bem em cenários com legado, prazos apertados e decisões de produto em movimento, sem sacrificar legibilidade técnica.",
|
||||
},
|
||||
];
|
||||
|
||||
const VALUES_DATA: CoreValue[] = [
|
||||
const VALUES_DATA = [
|
||||
{
|
||||
icon: Code,
|
||||
title: "Pragmatismo Arquitetural",
|
||||
description: "Priorizo a manutenibilidade e a resiliência. Código limpo é o meio, sistemas que geram ROI são o fim."
|
||||
title: "Pragmatismo arquitetural",
|
||||
description:
|
||||
"Decisões guiadas por ROI, operabilidade e clareza para o time que mantém o sistema depois.",
|
||||
},
|
||||
{
|
||||
icon: Brain,
|
||||
title: "Fundacionalismo Técnico",
|
||||
description: "Domínio profundo de estruturas de dados e protocolos. Tecnologias mudam, fundamentos são perenes."
|
||||
title: "Fundação técnica",
|
||||
description:
|
||||
"Fundamentos fortes em dados, protocolos e modelagem para evitar soluções frágeis e modismos vazios.",
|
||||
},
|
||||
{
|
||||
icon: Users,
|
||||
title: "Propriedade e Ownership",
|
||||
description: "Comunicação de baixa latência e responsabilidade radical sobre cada entrega e decisão técnica."
|
||||
title: "Ownership real",
|
||||
description:
|
||||
"Responsabilidade sobre entrega, comunicação e qualidade final, não só sobre o trecho de código escrito.",
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: "Security by Design",
|
||||
description: "Integridade e conformidade técnica (GDPR/LGPD) tratadas como requisitos funcionais, não opcionais."
|
||||
title: "Security by design",
|
||||
description:
|
||||
"Integridade, proteção de dados e conformidade tratadas como parte do produto, não como remendo.",
|
||||
},
|
||||
];
|
||||
|
||||
// --- Micro-componentes (Feynman Technique: Simplicidade e Reuso) ---
|
||||
|
||||
const SectionHeader = () => (
|
||||
<div className="text-center md:text-left mb-24 relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-blue-950/30 border border-blue-500/20 text-blue-400 font-mono text-xs tracking-wider mb-6"
|
||||
>
|
||||
<Terminal className="w-3 h-3" />
|
||||
<span>WHOAMI.sys</span>
|
||||
</motion.div>
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="text-4xl md:text-6xl font-black text-white tracking-tighter"
|
||||
>
|
||||
Engenharia <br />
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-500 to-cyan-400">Nuclear</span>
|
||||
</motion.h2>
|
||||
<p className="mt-6 text-lg text-slate-400 max-w-2xl leading-relaxed font-light border-l-2 border-slate-800 pl-6">
|
||||
"Transformando complexidade técnica em valor de negócio através da engenharia."
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const StoryCard = ({ step, index }: { step: StoryStep; index: number }) => {
|
||||
const isEven = index % 2 === 0;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: isEven ? -30 : 30 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
className={`flex flex-col ${isEven ? "md:flex-row" : "md:flex-row-reverse"} items-stretch gap-8 mb-20 relative`}
|
||||
>
|
||||
<div className="flex-1 w-full">
|
||||
<div className="group relative h-full p-8 rounded-3xl bg-zinc-900/40 border border-white/5 hover:border-blue-500/30 transition-all duration-500 shadow-xl backdrop-blur-xl overflow-hidden">
|
||||
{/* Background Glow */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
|
||||
<div className="relative z-10">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<div className="p-3 rounded-xl bg-blue-500/10 border border-blue-500/20 text-blue-400 group-hover:scale-110 transition-transform duration-300">
|
||||
<step.icon className="w-6 h-6" />
|
||||
</div>
|
||||
<span className="text-xs font-mono text-slate-500 uppercase tracking-widest">
|
||||
{step.id}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold text-white mb-4 group-hover:text-blue-400 transition-colors">{step.title}</h3>
|
||||
<p className="text-slate-400 leading-relaxed text-sm">{step.content}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Connection Line & Node */}
|
||||
<div className="hidden md:flex flex-col items-center justify-center w-12 relative">
|
||||
<div className="absolute top-0 bottom-0 w-[1px] bg-slate-800 group-hover:bg-blue-500/50 transition-colors" />
|
||||
<div className="w-4 h-4 rounded-full bg-slate-900 border-2 border-slate-700 z-10 group-hover:border-blue-500 transition-colors" />
|
||||
</div>
|
||||
|
||||
<div className="flex-1 hidden md:block" />
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function About() {
|
||||
return (
|
||||
<section id="about" className="relative py-32">
|
||||
{/* Background Gradients */}
|
||||
<div className="absolute top-0 left-0 w-full h-full pointer-events-none">
|
||||
<div className="absolute top-[-10%] right-[-10%] w-[600px] h-[600px] bg-blue-900/10 rounded-full blur-[120px]" />
|
||||
<div className="absolute bottom-[-10%] left-[-10%] w-[600px] h-[600px] bg-purple-900/10 rounded-full blur-[120px]" />
|
||||
</div>
|
||||
|
||||
<div className="container max-w-6xl mx-auto px-6 relative z-10">
|
||||
<SectionHeader />
|
||||
|
||||
<div className="relative mt-20">
|
||||
{/* Center Line for Mobile/Desktop */}
|
||||
<div className="absolute left-6 md:left-1/2 top-0 bottom-0 w-[1px] bg-slate-800 md:-translate-x-1/2 hidden md:block" />
|
||||
|
||||
{STORY_DATA.map((step, idx) => (
|
||||
<StoryCard key={idx} step={step} index={idx} />
|
||||
<Section
|
||||
id="about"
|
||||
eyebrow="WHOAMI.sys"
|
||||
title="Engenharia orientada por clareza, não por ruÃdo"
|
||||
description="Transformo complexidade técnica em sistemas estáveis, operáveis e alinhados ao negócio."
|
||||
aside={
|
||||
<div className="mt-sp-4 ds-metric">
|
||||
<span className="inline-block h-1.5 w-1.5 rounded-full bg-slash" />
|
||||
Garuva, SC · Remote worldwide
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="ds-grid-2">
|
||||
<div className="ds-grid-2">
|
||||
{STORY_DATA.map((step) => (
|
||||
<article key={step.id} className="ds-card">
|
||||
<div className="ds-kicker">{step.id}</div>
|
||||
<h3 className="ds-card-title">{step.title}</h3>
|
||||
<p className="ds-copy">{step.content}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Grid de Valores com Pareto 80/20 */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 mt-32">
|
||||
{VALUES_DATA.map((val, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="p-6 rounded-2xl bg-zinc-900/30 border border-white/5 hover:border-blue-500/20 hover:bg-zinc-900/50 transition-all duration-300 group"
|
||||
>
|
||||
<div className="mb-4 p-2 w-fit rounded-lg bg-slate-800/50 text-slate-400 group-hover:text-blue-400 group-hover:bg-blue-500/10 transition-colors">
|
||||
<val.icon className="w-5 h-5" />
|
||||
</div>
|
||||
<h4 className="text-white font-bold mb-2 text-sm uppercase tracking-wide group-hover:text-blue-200 transition-colors">{val.title}</h4>
|
||||
<p className="text-slate-500 text-xs leading-relaxed group-hover:text-slate-400 transition-colors">{val.description}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* SEO Semantic Content - Visible but subtle */}
|
||||
<div className="mt-24 pt-8 border-t border-slate-900">
|
||||
<div className="flex items-center justify-center gap-2 text-slate-700 text-xs font-mono uppercase tracking-widest mb-4">
|
||||
<Cpu className="w-3 h-3" />
|
||||
<span>System_Signature</span>
|
||||
</div>
|
||||
<p className="text-[10px] text-slate-700 text-center max-w-2xl mx-auto leading-relaxed font-mono">
|
||||
Evandro Fonseca Junior :: Engenheiro Full-Stack <br />
|
||||
Next.js / React / Angular / Node.js / Tauri / PostgreSQL / IoT <br />
|
||||
Garuva, Santa Catarina, Brasil :: Lat: -26.0264, Long: -48.8544
|
||||
<div className="ds-card">
|
||||
<div className="ds-kicker">System Signature</div>
|
||||
<h3 className="ds-card-title">Base técnica e postura de entrega</h3>
|
||||
<p className="ds-copy">
|
||||
Evandro Fonseca Junior. Engenheiro Full-Stack com foco em Next.js,
|
||||
React, Node.js, Tauri, integrações e arquitetura pragmática.
|
||||
</p>
|
||||
<div className="ds-grid-2 mt-sp-6">
|
||||
{VALUES_DATA.map((value) => (
|
||||
<div
|
||||
key={value.title}
|
||||
className="border-t border-[var(--border)] pt-sp-4"
|
||||
>
|
||||
<div className="text-[11px] font-medium uppercase tracking-[0.08em]">
|
||||
{value.title}
|
||||
</div>
|
||||
<p className="ds-copy !mt-sp-2">{value.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
}
|
||||
+98
-198
@@ -1,223 +1,123 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Send, User, Mail, MessageSquare, Sparkles } from "lucide-react";
|
||||
import { ShimmerButton as MagicShimmerButton } from "@/components/magicui/shimmer-button";
|
||||
import Squares from "@/components/Squares";
|
||||
import type React from "react";
|
||||
import { useState } from "react";
|
||||
import { Section } from "./Section";
|
||||
|
||||
// --- CONFIGURAÇÃO DE ENGENHARIA ---
|
||||
// Substitua pelo seu número real: CódigoPaís + DDD + Número (sem espaços ou símbolos)
|
||||
const WHATSAPP_NUMBER = "5547992742365";
|
||||
|
||||
interface FormData {
|
||||
name: string;
|
||||
email: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper Component: Resolve o erro de tipagem TS2322 (IntrinsicAttributes)
|
||||
* Estendemos a interface para aceitar propriedades de estilo customizadas.
|
||||
*/
|
||||
interface ExtendedShimmerProps extends React.ComponentProps<typeof MagicShimmerButton> {
|
||||
shimmerColor?: string;
|
||||
shimmerSize?: string;
|
||||
type?: "button" | "submit" | "reset";
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const CustomShimmerButton = ({
|
||||
children,
|
||||
className,
|
||||
shimmerColor = "#3b82f6",
|
||||
shimmerSize = "0.1em",
|
||||
...props
|
||||
}: ExtendedShimmerProps) => {
|
||||
return (
|
||||
<MagicShimmerButton
|
||||
{...props}
|
||||
className={className}
|
||||
// @ts-ignore - Ignora restrição de tipos da lib original se necessário
|
||||
shimmerColor={shimmerColor}
|
||||
shimmerSize={shimmerSize}
|
||||
>
|
||||
{children}
|
||||
</MagicShimmerButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Contact() {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
subject: "full-stack",
|
||||
message: "",
|
||||
});
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 800));
|
||||
|
||||
// Definimos os emojis via Unicode Escape para máxima compatibilidade
|
||||
const icons = {
|
||||
rocket: "\u{1F680}",
|
||||
person: "\u{1F464}",
|
||||
email: "\u{1F4E7}",
|
||||
tools: "\u{1F6E0}",
|
||||
chat: "\u{1F4AC}"
|
||||
};
|
||||
|
||||
const messageTemplate = `*NOVA SOLICITAÇÃO DE PROJETO*
|
||||
|
||||
*Origem:* Portfólio Profissional
|
||||
*Prioridade:* Alta (Lead Qualificado)
|
||||
|
||||
---
|
||||
*CLIENTE:* ${formData.name}
|
||||
*EMAIL:* ${formData.email}
|
||||
*ÁREA:* ${formData.subject.toUpperCase()}
|
||||
|
||||
*DESCRIÇÃO:*
|
||||
"${formData.message}"
|
||||
---
|
||||
_Mensagem gerada via Evandro.dev | Garuva, SC_`;
|
||||
const messageTemplate = `*NOVA SOLICITACAO DE PROJETO*\n\n*Origem:* Portfolio Profissional\n*Prioridade:* Alta\n\n---\n*CLIENTE:* ${formData.name}\n*EMAIL:* ${formData.email}\n*AREA:* ${formData.subject.toUpperCase()}\n\n*DESCRICAO:*\n"${formData.message}"\n---\n_Mensagem gerada via Evandro.dev | Garuva, SC_`;
|
||||
|
||||
const encodedMessage = encodeURIComponent(messageTemplate);
|
||||
const whatsappUrl = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodedMessage}`;
|
||||
|
||||
window.open(whatsappUrl, "_blank", "noopener,noreferrer");
|
||||
setIsSubmitting(false);
|
||||
};
|
||||
|
||||
const inputStyles =
|
||||
"w-full bg-black/40 border border-white/5 rounded-xl px-4 py-3 text-slate-200 placeholder:text-slate-600 focus:border-blue-500/50 focus:ring-2 focus:ring-blue-500/10 focus:bg-black/60 outline-none transition-all duration-300 font-mono text-sm backdrop-blur-sm group-hover:border-white/10";
|
||||
const labelStyles =
|
||||
"text-[10px] font-bold text-slate-500 uppercase tracking-widest mb-2 flex items-center gap-2 transition-colors group-hover:text-slate-400";
|
||||
|
||||
return (
|
||||
<section id="contact" className="w-full py-24 relative">
|
||||
|
||||
|
||||
<div className="w-full max-w-4xl mx-auto px-6 relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative bg-zinc-900/40 backdrop-blur-xl border border-white/10 rounded-3xl p-8 md:p-12 shadow-2xl overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-blue-500/0 via-blue-500/50 to-blue-500/0" />
|
||||
|
||||
<div className="mb-10 text-center space-y-2">
|
||||
<h2 className="text-3xl md:text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-b from-white to-white/60">
|
||||
Vamos Construir o Futuro
|
||||
</h2>
|
||||
<p className="text-slate-400 text-sm md:text-base max-w-lg mx-auto">
|
||||
Descreva seu desafio técnico. Retorno com uma arquitetura sólida em até 24h.
|
||||
</p>
|
||||
<Section
|
||||
id="contact"
|
||||
eyebrow="CONTACT_PROTOCOL.init"
|
||||
title="Vamos discutir o próximo sistema"
|
||||
description="Descreva o contexto, o gargalo ou o produto. O contato abre direto no WhatsApp com briefing estruturado."
|
||||
dark
|
||||
>
|
||||
<div className="ds-grid-2">
|
||||
<div className="ds-card">
|
||||
<div className="ds-kicker">Response SLA</div>
|
||||
<h3 className="ds-card-title">Retorno inicial em até 24h</h3>
|
||||
<p className="ds-copy">
|
||||
Ideal para discovery técnico, revisão de arquitetura, rescue de
|
||||
projeto, otimização de performance ou construção de produto do
|
||||
zero.
|
||||
</p>
|
||||
<div className="mt-sp-6 space-y-sp-4 text-[12px] leading-7 text-[rgba(255,255,255,.7)]">
|
||||
<div>WhatsApp: +55 47 99274-2365</div>
|
||||
<div>E-mail: evandrofonsecajunior@gmail.com</div>
|
||||
<div>Base: Garuva, Santa Catarina · atuação remota</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-8 relative">
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<User className="w-3 h-3 text-blue-500" /> NOME COMPLETO
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
placeholder="Ex: Alan Turing"
|
||||
className={inputStyles}
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<Mail className="w-3 h-3 text-blue-500" /> E-MAIL CORPORATIVO
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
type="email"
|
||||
placeholder="[email protected]"
|
||||
className={inputStyles}
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<Sparkles className="w-3 h-3 text-blue-500" /> TIPO DE PROJETO
|
||||
</label>
|
||||
<div className="relative">
|
||||
<select
|
||||
className={`${inputStyles} appearance-none cursor-pointer`}
|
||||
value={formData.subject}
|
||||
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
|
||||
>
|
||||
<option value="full-stack">Desenvolvimento Full-Stack</option>
|
||||
<option value="cloud">Cloud & Infrastructure</option>
|
||||
<option value="iot">Internet of Things (IoT)</option>
|
||||
<option value="consultancy">Consultoria Técnica Sênior</option>
|
||||
</select>
|
||||
<div className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none text-slate-500">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6" /></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<MessageSquare className="w-3 h-3 text-blue-500" /> DETALHES DO PROJETO
|
||||
</label>
|
||||
<textarea
|
||||
required
|
||||
rows={5}
|
||||
placeholder="Descreva os requisitos técnicos e objetivos do sistema..."
|
||||
className={`${inputStyles} resize-none`}
|
||||
value={formData.message}
|
||||
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<motion.div whileHover={{ scale: 1.01 }} whileTap={{ scale: 0.99 }} className="pt-6">
|
||||
<CustomShimmerButton
|
||||
type="submit"
|
||||
className="w-full h-14 rounded-xl shadow-lg shadow-blue-500/20"
|
||||
shimmerColor="#60a5fa"
|
||||
shimmerSize="0.1em"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
<div className="flex flex-row items-center justify-center gap-3 w-full h-full">
|
||||
{isSubmitting ? (
|
||||
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||
) : (
|
||||
<>
|
||||
<span className="text-white font-bold tracking-widest uppercase text-xs md:text-sm">
|
||||
Iniciar Protocolo de Contato
|
||||
</span>
|
||||
<Send className="w-4 h-4 text-white" />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CustomShimmerButton>
|
||||
</motion.div>
|
||||
|
||||
<footer className="pt-2">
|
||||
<p className="text-[10px] text-center text-slate-600 font-mono uppercase tracking-widest opacity-60">
|
||||
Secured by End-to-End Encryption
|
||||
</p>
|
||||
</footer>
|
||||
</form>
|
||||
</motion.div>
|
||||
<form onSubmit={handleSubmit} className="ds-card space-y-sp-5">
|
||||
<div>
|
||||
<label htmlFor="contact-name" className="ds-kicker block">
|
||||
Nome completo
|
||||
</label>
|
||||
<input
|
||||
id="contact-name"
|
||||
required
|
||||
type="text"
|
||||
value={formData.name}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, name: e.target.value })
|
||||
}
|
||||
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-email" className="ds-kicker block">
|
||||
E-mail corporativo
|
||||
</label>
|
||||
<input
|
||||
id="contact-email"
|
||||
required
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, email: e.target.value })
|
||||
}
|
||||
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-subject" className="ds-kicker block">
|
||||
Tipo de projeto
|
||||
</label>
|
||||
<select
|
||||
id="contact-subject"
|
||||
value={formData.subject}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, subject: e.target.value })
|
||||
}
|
||||
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
>
|
||||
<option value="full-stack">Desenvolvimento Full-Stack</option>
|
||||
<option value="cloud">Cloud & Infrastructure</option>
|
||||
<option value="iot">Internet of Things (IoT)</option>
|
||||
<option value="consultancy">Consultoria Técnica Sênior</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-message" className="ds-kicker block">
|
||||
Detalhes do projeto
|
||||
</label>
|
||||
<textarea
|
||||
id="contact-message"
|
||||
required
|
||||
rows={6}
|
||||
value={formData.message}
|
||||
onChange={(e) =>
|
||||
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,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" className="ds-link ds-link-accent border-0">
|
||||
Iniciar protocolo de contato
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
}
|
||||
+44
-170
@@ -1,194 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import React, { useMemo } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import {
|
||||
ChevronRight,
|
||||
Terminal,
|
||||
Cpu,
|
||||
Network,
|
||||
Code2
|
||||
} from "lucide-react";
|
||||
import { useMemo } from "react";
|
||||
import { usePortfolioData } from "@/lib/usePortfolioData";
|
||||
|
||||
// --- Tipagem e Configuração (Otimização Pareto 80/20) ---
|
||||
const CONFIG = {
|
||||
"innovo-tecnologia": { color: "text-blue-400", bg: "bg-blue-400/10", border: "border-blue-400/20", icon: Cpu },
|
||||
"apolo-energia": { color: "text-emerald-400", bg: "bg-emerald-400/10", border: "border-emerald-400/20", icon: Network },
|
||||
default: { color: "text-slate-400", bg: "bg-slate-400/10", border: "border-slate-400/20", icon: Code2 }
|
||||
};
|
||||
import { Section } from "./Section";
|
||||
|
||||
export default function Experience() {
|
||||
const { data, loading, error } = usePortfolioData();
|
||||
|
||||
// Memória: Evita re-processamento de regex em cada re-render (Princípio de Eficiência)
|
||||
const sortedExperiences = useMemo(() => {
|
||||
if (!data?.experiences) return [];
|
||||
return [...data.experiences]
|
||||
.filter((exp) => exp.featured)
|
||||
.sort((a, b) => {
|
||||
const yearA = parseInt(a.period.match(/\d{4}/)?.[0] || "0");
|
||||
const yearB = parseInt(b.period.match(/\d{4}/)?.[0] || "0");
|
||||
return yearB - yearA; // Da mais recente para a mais antiga (Padrão Senior)
|
||||
const yearA = parseInt(a.period.match(/\d{4}/)?.[0] || "0", 10);
|
||||
const yearB = parseInt(b.period.match(/\d{4}/)?.[0] || "0", 10);
|
||||
return yearB - yearA;
|
||||
});
|
||||
}, [data]);
|
||||
|
||||
if (loading) return <ExperienceSkeleton />;
|
||||
if (loading) return <div className="ds-loading">Loading system logs</div>;
|
||||
if (error || !data)
|
||||
return <div className="ds-error">Error loading system logs</div>;
|
||||
|
||||
return (
|
||||
<section id="experience" className="relative py-32">
|
||||
{/* Background Gradients */}
|
||||
<div className="absolute top-0 left-0 w-full h-full pointer-events-none">
|
||||
<div className="absolute top-[20%] left-[-10%] w-[500px] h-[500px] bg-blue-900/10 rounded-full blur-[100px]" />
|
||||
<div className="absolute bottom-[20%] right-[-10%] w-[500px] h-[500px] bg-indigo-900/10 rounded-full blur-[100px]" />
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto px-6 relative z-10">
|
||||
|
||||
{/* Header com Identidade Visual */}
|
||||
<div className="mb-24 text-center md:text-left">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-blue-950/30 border border-blue-500/20 text-blue-400 font-mono text-xs tracking-wider mb-6"
|
||||
>
|
||||
<Terminal className="w-3 h-3" />
|
||||
<span>SYSTEM_LOGS.history</span>
|
||||
</motion.div>
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="text-4xl md:text-6xl font-black text-white tracking-tighter"
|
||||
>
|
||||
Trajetória <span className="bg-gradient-to-r from-blue-500 to-indigo-500 bg-clip-text text-transparent">Profissional</span>
|
||||
</motion.h2>
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
{/* Timeline Desktop (Linha Central com Gradiente) */}
|
||||
<div className="absolute left-[50%] top-0 bottom-0 w-[2px] bg-gradient-to-b from-blue-500/50 via-indigo-500/20 to-transparent hidden lg:block translate-x-[-50%]" />
|
||||
|
||||
<div className="space-y-24">
|
||||
{sortedExperiences.map((exp, index) => (
|
||||
<ExperienceCard key={exp.id} exp={exp} index={index} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
// --- Sub-componente Card (Encapsulamento de Lógica de Transição) ---
|
||||
function ExperienceCard({ exp, index }: { exp: any, index: number }) {
|
||||
const isEven = index % 2 === 0;
|
||||
const config = (CONFIG as any)[exp.company.toLowerCase().replace(/\s+/g, "-")] || CONFIG.default;
|
||||
const Icon = config.icon;
|
||||
|
||||
return (
|
||||
<div className={`relative flex flex-col ${isEven ? 'lg:flex-row' : 'lg:flex-row-reverse'} items-center gap-8 lg:gap-16`}>
|
||||
|
||||
{/* Node Central (O "Ponto" da Timeline) */}
|
||||
<motion.div
|
||||
initial={{ scale: 0, opacity: 0 }}
|
||||
whileInView={{ scale: 1, opacity: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.2, duration: 0.5 }}
|
||||
className="hidden lg:flex absolute left-[50%] top-0 translate-x-[-50%] w-4 h-4 rounded-full bg-blue-500 shadow-[0_0_20px_rgba(59,130,246,0.5)] z-20 items-center justify-center"
|
||||
>
|
||||
<div className="w-2 h-2 rounded-full bg-white animate-pulse" />
|
||||
</motion.div>
|
||||
|
||||
{/* Indicador de Data na Timeline */}
|
||||
<div className="hidden lg:flex flex-1 justify-end items-start pt-2">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: isEven ? -20 : 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className={`${isEven ? 'text-right' : 'text-left'} flex-1`}
|
||||
>
|
||||
<span className="text-4xl font-black text-transparent bg-clip-text bg-gradient-to-b from-slate-700 to-slate-800 tracking-tighter opacity-50 select-none">
|
||||
{exp.period.split(' ')[0]}
|
||||
</span>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Card Principal */}
|
||||
<div className="flex-1 w-full relative group perspective-1000">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: isEven ? 50 : -50 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.6, delay: 0.1 * index }}
|
||||
whileHover={{ y: -5, transition: { duration: 0.2 } }}
|
||||
className={`p-8 rounded-3xl bg-zinc-900/40 border border-white/5 backdrop-blur-md relative overflow-hidden transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.1)] hover:border-blue-500/20`}
|
||||
>
|
||||
{/* Background Glow Effect on Hover */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
|
||||
{/* Badge de Empresa & Header */}
|
||||
<div className="relative z-10">
|
||||
<div className="flex flex-wrap justify-between items-start gap-4 mb-6">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`p-2 rounded-lg ${config.bg} ${config.color}`}>
|
||||
<Icon className="w-5 h-5" />
|
||||
</div>
|
||||
<span className={`text-xs font-bold uppercase tracking-widest ${config.color}`}>
|
||||
{exp.company}
|
||||
</span>
|
||||
<Section
|
||||
id="experience"
|
||||
eyebrow="SYSTEM_LOGS.history"
|
||||
title="Trajetória focada em produto, legado e crescimento sustentável"
|
||||
description="Experiências recentes onde combinei entrega rápida com responsabilidade arquitetural."
|
||||
>
|
||||
<div className="space-y-sp-6">
|
||||
{sortedExperiences.map((exp) => (
|
||||
<article key={exp.id} className="ds-card">
|
||||
<div className="ds-grid-2">
|
||||
<div>
|
||||
<div className="ds-kicker">{exp.period}</div>
|
||||
<h3 className="ds-card-title">{exp.title}</h3>
|
||||
<div className="mt-sp-3 text-[11px] uppercase tracking-[0.1em] text-meta">
|
||||
{exp.company} · {exp.type}
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-white group-hover:text-blue-400 transition-colors">
|
||||
{exp.title}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="px-3 py-1 rounded-full bg-white/5 border border-white/10 text-[10px] font-mono font-bold text-slate-400 uppercase tracking-wide">
|
||||
{exp.period}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-slate-400 leading-relaxed mb-8 text-sm">
|
||||
{exp.description}
|
||||
</p>
|
||||
|
||||
{/* Conquistas (Checklist Técnico) */}
|
||||
<div className="grid grid-cols-1 gap-3 mb-8">
|
||||
{exp.achievements?.map((ach: string, i: number) => (
|
||||
<div key={i} className="flex gap-3 text-sm text-slate-300 items-start">
|
||||
<div className="mt-1.5 w-1.5 h-1.5 rounded-full bg-blue-500 flex-shrink-0" />
|
||||
<span>{ach}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Tags de Tech */}
|
||||
<div className="flex flex-wrap gap-2 pt-6 border-t border-white/5">
|
||||
{exp.technologies?.map((tech: string) => (
|
||||
<span key={tech} className="px-3 py-1 bg-black/20 border border-white/5 text-slate-500 text-[10px] rounded-full font-mono hover:text-blue-400 hover:border-blue-400/30 transition-all cursor-default">
|
||||
{tech}
|
||||
<div className="flex flex-wrap items-start justify-start gap-sp-3 lg:justify-end">
|
||||
<span className="ds-tag">{exp.location}</span>
|
||||
<span className="ds-tag">
|
||||
{exp.technologies.length} tecnologias
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
<p className="ds-copy">{exp.description}</p>
|
||||
<ul className="ds-list">
|
||||
{exp.achievements?.map((achievement) => (
|
||||
<li key={achievement}>{achievement}</li>
|
||||
))}
|
||||
</ul>
|
||||
<ul className="ds-tags mt-sp-6">
|
||||
{exp.technologies?.map((tech) => (
|
||||
<li key={tech} className="ds-tag">
|
||||
{tech}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Spacer para Timeline Desktop */}
|
||||
<div className="hidden lg:block flex-1" />
|
||||
</div>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
function ExperienceSkeleton() {
|
||||
return (
|
||||
<div className="h-96 flex flex-col items-center justify-center gap-4 text-slate-600 font-mono animate-pulse">
|
||||
<Cpu className="w-8 h-8 animate-spin" />
|
||||
<span>BOOTING_SYSTEM_HISTORY...</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+106
-150
@@ -1,171 +1,127 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { MenuIcon, XIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useState } from "react";
|
||||
import { Logo } from "./Logo";
|
||||
|
||||
// Definição de Tipos para consistência de dados
|
||||
interface NavItem {
|
||||
href: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const navItems: NavItem[] = [
|
||||
const navItems = [
|
||||
{ href: "#home", label: "Home" },
|
||||
{ href: "#about", label: "Sobre" },
|
||||
{ href: "#skills", label: "Habilidades" },
|
||||
{ href: "#experience", label: "Experiência" },
|
||||
{ href: "#experience", label: "Experiencia" },
|
||||
{ href: "#projects", label: "Projetos" },
|
||||
{ href: "#modalities", label: "Contratacao" },
|
||||
{ href: "#contact", label: "Contato" },
|
||||
];
|
||||
|
||||
export function Header() {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
|
||||
// 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);
|
||||
}, []);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<motion.header
|
||||
initial={{ y: -100 }}
|
||||
animate={{ y: 0 }}
|
||||
className={cn(
|
||||
"fixed top-0 left-0 right-0 z-[100] transition-all duration-500 ease-in-out px-6 py-4",
|
||||
scrolled
|
||||
? "bg-black/40 backdrop-blur-xl border-b border-white/5 py-3"
|
||||
: "bg-transparent py-6"
|
||||
)}
|
||||
>
|
||||
<nav className="max-w-7xl mx-auto flex items-center justify-between">
|
||||
{/* Logo com Identidade Visual de Engenheiro */}
|
||||
<motion.a
|
||||
href="#home"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
const element = document.querySelector("#home");
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}
|
||||
}}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
<header
|
||||
className="fixed left-0 right-0 top-0 z-50 border-b backdrop-blur-xl"
|
||||
style={{
|
||||
borderColor: "rgba(255,255,255,.1)",
|
||||
background: "rgba(10,10,10,.96)",
|
||||
}}
|
||||
>
|
||||
<div className="mx-auto flex h-[52px] w-full max-w-[1240px] items-center justify-between px-6 lg:px-16">
|
||||
<a href="#home" className="flex items-center gap-3 no-underline">
|
||||
<Logo variant="mark" size="sm" theme="dark" />
|
||||
<span
|
||||
className="font-display text-sm font-extrabold tracking-tight"
|
||||
style={{ color: "#FFFFFF" }}
|
||||
>
|
||||
<div className="w-8 h-8 flex items-center justify-center">
|
||||
<Image
|
||||
src="/edev_logo.svg"
|
||||
alt="Evandro.dev Logo"
|
||||
width={32}
|
||||
height={32}
|
||||
className="w-8 h-8"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xl font-black tracking-tighter text-white">
|
||||
EVANDRO<span className="text-blue-500">.DEV</span>
|
||||
</span>
|
||||
</motion.a>
|
||||
evandro<span style={{ color: "#E8FF00" }}>.dev.br</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Desktop Navigation - Focada em Espaçamento Ótimo */}
|
||||
<div className="hidden md:flex items-center gap-1 bg-white/5 p-1 rounded-full border border-white/10 backdrop-blur-md">
|
||||
<nav className="hidden items-center lg:flex">
|
||||
<ul className="flex list-none items-center gap-2">
|
||||
{navItems.map((item) => (
|
||||
<a
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
const element = document.querySelector(item.href);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}
|
||||
}}
|
||||
className="px-5 py-2 text-xs font-bold uppercase tracking-widest text-slate-300 hover:text-white hover:bg-white/10 rounded-full transition-all duration-300 cursor-pointer"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
<li key={item.href}>
|
||||
<a
|
||||
href={item.href}
|
||||
className="rounded-sm px-3 py-2 text-[10px] uppercase tracking-[0.14em] no-underline transition-all duration-200 hover:bg-white/10"
|
||||
style={{ color: "rgba(255,255,255,.86)" }}
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Botão de Ação CTA (Call to Action) */}
|
||||
<div className="hidden md:block">
|
||||
<a
|
||||
href="/Profile.pdf"
|
||||
download="Evandro_Fonseca_Junior_CV.pdf"
|
||||
className="px-6 py-2 bg-white text-black text-xs font-bold uppercase tracking-widest rounded-full hover:bg-blue-500 hover:text-white transition-all duration-500 inline-block"
|
||||
>
|
||||
Download CV
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Mobile Toggle */}
|
||||
<button
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
className="md:hidden p-2 text-white bg-white/5 rounded-lg border border-white/10"
|
||||
>
|
||||
{isMenuOpen ? <XIcon size={20} /> : <MenuIcon size={20} />}
|
||||
</button>
|
||||
</ul>
|
||||
</nav>
|
||||
</motion.header>
|
||||
|
||||
{/* Mobile Menu Overlay com Framer Motion para fluidez */}
|
||||
<AnimatePresence>
|
||||
{isMenuOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: "100%" }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: "100%" }}
|
||||
transition={{ type: "spring", damping: 25, stiffness: 200 }}
|
||||
className="fixed inset-0 z-[110] bg-black/95 backdrop-blur-2xl md:hidden flex flex-col items-center justify-center gap-8"
|
||||
<div className="flex items-center gap-4">
|
||||
<span
|
||||
className="hidden rounded-full border px-[10px] py-1 text-[9px] uppercase tracking-[0.12em] lg:inline-block"
|
||||
style={{
|
||||
borderColor: "rgba(255,255,255,.15)",
|
||||
color: "rgba(255,255,255,.35)",
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
className="absolute top-8 right-8 p-4 text-white/50 hover:text-white"
|
||||
>
|
||||
<XIcon size={32} />
|
||||
</button>
|
||||
|
||||
{navItems.map((item, i) => (
|
||||
<motion.a
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
onClick={(e) => {
|
||||
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}
|
||||
</motion.a>
|
||||
v1.0 / 2026
|
||||
</span>
|
||||
<a
|
||||
href="/Profile.pdf"
|
||||
download="Evandro_Fonseca_Junior_CV.pdf"
|
||||
className="hidden rounded-sm px-4 py-2 text-[10px] font-semibold uppercase tracking-[0.1em] no-underline transition-all duration-200 hover:shadow-[0_0_0_1px_rgba(232,255,0,.8),0_8px_24px_rgba(232,255,0,.35)] lg:inline-flex"
|
||||
style={{ background: "#E8FF00", color: "#0A0A0A" }}
|
||||
>
|
||||
Download CV
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-8 w-8 flex-col items-center justify-center gap-1.5 border-none bg-transparent lg:hidden"
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
aria-label="Menu"
|
||||
>
|
||||
<span
|
||||
className={`h-0.5 w-5 bg-white transition-transform duration-200 ${mobileMenuOpen ? "translate-y-2 rotate-45" : ""}`}
|
||||
/>
|
||||
<span
|
||||
className={`h-0.5 w-5 bg-white transition-opacity duration-200 ${mobileMenuOpen ? "opacity-0" : ""}`}
|
||||
/>
|
||||
<span
|
||||
className={`h-0.5 w-5 bg-white transition-transform duration-200 ${mobileMenuOpen ? "-translate-y-2 -rotate-45" : ""}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`absolute left-0 right-0 top-[52px] overflow-hidden border-b backdrop-blur-xl transition-all duration-300 lg:hidden ${mobileMenuOpen ? "max-h-[420px] opacity-100" : "max-h-0 opacity-0"}`}
|
||||
style={{
|
||||
borderColor: "rgba(255,255,255,.1)",
|
||||
background: "rgba(10,10,10,.98)",
|
||||
}}
|
||||
>
|
||||
<nav className="px-6 py-4">
|
||||
<ul className="flex list-none flex-col gap-2">
|
||||
{navItems.map((item) => (
|
||||
<li key={item.href}>
|
||||
<a
|
||||
href={item.href}
|
||||
className="block rounded-sm px-3 py-3 text-[11px] uppercase tracking-[0.14em] no-underline transition-all duration-200 hover:bg-white/10"
|
||||
style={{ color: "rgba(255,255,255,.9)" }}
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
<motion.a
|
||||
href="/Profile.pdf"
|
||||
download="Evandro_Fonseca_Junior_CV.pdf"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: navItems.length * 0.1 }}
|
||||
className="mt-8 px-8 py-4 bg-white text-black text-xl font-black uppercase tracking-tighter rounded-full hover:bg-blue-500 hover:text-white transition-all duration-300"
|
||||
>
|
||||
Download CV
|
||||
</motion.a>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
<li>
|
||||
<a
|
||||
href="/Profile.pdf"
|
||||
download="Evandro_Fonseca_Junior_CV.pdf"
|
||||
className="mt-2 inline-flex rounded-sm px-4 py-3 text-[10px] font-semibold uppercase tracking-[0.1em] no-underline"
|
||||
style={{ background: "#E8FF00", color: "#0A0A0A" }}
|
||||
>
|
||||
Download CV
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
||||
+199
-124
@@ -1,145 +1,220 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import { motion } from "motion/react";
|
||||
import Image from "next/image";
|
||||
import { AuroraText } from "@/components/magicui/aurora-text";
|
||||
import { AnimatedGradientText } from "@/components/magicui/animated-gradient-text";
|
||||
import { Github, Linkedin, MessageCircle, Mail, MapPin, Terminal } from "lucide-react";
|
||||
import TextType from "@/components/TextType";
|
||||
import { Logo } from "./Logo";
|
||||
|
||||
const SOCIAL_LINKS = [
|
||||
{
|
||||
href: "https://github.com/evandrodevbr",
|
||||
label: "GitHub",
|
||||
icon: (
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
|
||||
),
|
||||
},
|
||||
{
|
||||
href: "https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/",
|
||||
label: "LinkedIn",
|
||||
icon: (
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
|
||||
),
|
||||
},
|
||||
{
|
||||
href: "mailto:[email protected]",
|
||||
label: "Email",
|
||||
icon: (
|
||||
<>
|
||||
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" />
|
||||
<polyline points="22,6 12,13 2,6" />
|
||||
</>
|
||||
),
|
||||
stroke: true,
|
||||
},
|
||||
];
|
||||
|
||||
const STATS = [
|
||||
{ value: "4", accent: "px", label: "Base unit" },
|
||||
{ value: "9", accent: "x", label: "Type scale" },
|
||||
{ value: "4", accent: "+", label: "Core tokens" },
|
||||
];
|
||||
|
||||
export default function Hero() {
|
||||
const getGreetingMessage = () => {
|
||||
const hour = new Date().getHours();
|
||||
if (hour >= 8 && hour < 12) return "Olá! Vi seu portfólio. Podemos conversar?";
|
||||
if (hour >= 13 && hour < 18) return "Boa tarde! Vi seu portfólio. Podemos conversar?";
|
||||
return "Olá! Vi seu portfólio. Podemos conversar quando estiver disponível?";
|
||||
};
|
||||
|
||||
const generateWhatsAppUrl = () => {
|
||||
const message = encodeURIComponent(getGreetingMessage());
|
||||
return `https://wa.me/5547992742365?text=${message}`;
|
||||
};
|
||||
const hour = new Date().getHours();
|
||||
const greeting =
|
||||
hour >= 8 && hour < 12
|
||||
? "Ola! Vi seu portfolio. Podemos conversar?"
|
||||
: hour >= 13 && hour < 18
|
||||
? "Boa tarde! Vi seu portfolio. Podemos conversar?"
|
||||
: "Ola! Vi seu portfolio. Podemos conversar quando estiver disponivel?";
|
||||
|
||||
return (
|
||||
<section id="home" className="relative min-h-screen flex items-center justify-center overflow-hidden pt-28 md:pt-20">
|
||||
{/* 1. Background Engineering: Grid Pattern & Radial Shading */}
|
||||
<div className="absolute inset-0 z-0 pointer-events-none">
|
||||
<div className="absolute inset-0 bg-radial-at-t from-blue-500/10 via-transparent to-transparent" />
|
||||
</div>
|
||||
<section
|
||||
id="home"
|
||||
className="relative overflow-hidden px-6 py-24 lg:px-16"
|
||||
style={{ background: "#0A0A0A", color: "#FFFFFF" }}
|
||||
>
|
||||
<div className="pointer-events-none absolute inset-0 bg-grid-light opacity-70" />
|
||||
<div className="pointer-events-none absolute inset-x-0 top-0 h-40 bg-[radial-gradient(circle_at_top,rgba(232,255,0,0.18),transparent_60%)]" />
|
||||
|
||||
<div className="relative z-10 w-full max-w-6xl mx-auto px-6 grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
|
||||
<div className="relative z-10 mx-auto grid min-h-[calc(100vh-52px)] w-full max-w-[1240px] grid-cols-1 items-center gap-16 lg:grid-cols-2">
|
||||
<div>
|
||||
<div className="mb-8 inline-flex items-center gap-2">
|
||||
<span
|
||||
className="h-1.5 w-1.5 animate-pulse rounded-full"
|
||||
style={{ background: "#E8FF00" }}
|
||||
/>
|
||||
<span
|
||||
className="text-[9px] uppercase tracking-[0.2em]"
|
||||
style={{ color: "rgba(255,255,255,.38)" }}
|
||||
>
|
||||
Systems engineer available
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Lado Esquerdo: Conteúdo Textual (80/20 do Impacto) */}
|
||||
<div className="lg:col-span-7 text-left">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
<h1
|
||||
className="mb-6 font-display text-5xl font-extrabold leading-[0.92] tracking-[-0.04em] md:text-6xl lg:text-7xl xl:text-[5.4rem]"
|
||||
style={{ color: "#FFFFFF" }}
|
||||
>
|
||||
<AnimatedGradientText className="mb-6 inline-flex items-center gap-2 px-4 py-2 rounded-full border border-blue-500/20 bg-blue-500/5 backdrop-blur-md">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-500"></span>
|
||||
</span>
|
||||
<span className="text-sm font-medium text-cyan-300 tracking-wide uppercase">
|
||||
Systems Engineer available
|
||||
</span>
|
||||
</AnimatedGradientText>
|
||||
Evandro
|
||||
<br />
|
||||
<span style={{ color: "#E8FF00" }}>.dev</span>
|
||||
<br />
|
||||
.br
|
||||
</h1>
|
||||
|
||||
<h1 className="text-5xl md:text-7xl font-black text-white mb-4 tracking-tight leading-none">
|
||||
Evandro <br />
|
||||
<AuroraText className="italic">Fonseca Junior</AuroraText>
|
||||
</h1>
|
||||
<p
|
||||
className="mb-10 max-w-[460px] text-[13px] leading-7"
|
||||
style={{ color: "rgba(255,255,255,.72)" }}
|
||||
>
|
||||
Engenheiro de Software especializado em aplicacoes de alta
|
||||
performance, interfaces de produto e sistemas criticos com Next.js,
|
||||
React, Tauri e arquitetura escalavel.
|
||||
</p>
|
||||
|
||||
<div className="h-10 flex items-center gap-2 mb-6">
|
||||
<Terminal className="w-5 h-5 text-blue-400" />
|
||||
<TextType
|
||||
text={["Engenheiro de Software", "Next.js & Tauri Specialist", "High Performance Systems Architect"]}
|
||||
className="text-2xl font-mono text-slate-400"
|
||||
typingSpeed={60}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-8 flex flex-wrap items-center gap-4">
|
||||
<a
|
||||
href={`https://wa.me/5547992742365?text=${encodeURIComponent(greeting)}`}
|
||||
className="inline-flex h-11 items-center rounded-sm px-6 text-[11px] font-semibold uppercase tracking-[0.08em] no-underline transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_0_0_1px_rgba(232,255,0,.8),0_8px_24px_rgba(232,255,0,.35)]"
|
||||
style={{ background: "#E8FF00", color: "#0A0A0A" }}
|
||||
>
|
||||
Iniciar projeto
|
||||
</a>
|
||||
|
||||
<p className="text-lg text-slate-400 max-w-xl mb-10 leading-relaxed">
|
||||
Engenheiro de Software especializado em aplicações de alta performance e sistemas críticos. Desenvolvimento com <span className="text-white font-medium">Next.js 15, React 19, Tauri</span> e arquitetura escalável. Transformo requisitos complexos em software robusto.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
<motion.a
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
href={generateWhatsAppUrl()}
|
||||
className="px-8 py-4 bg-blue-600 hover:bg-blue-500 text-white rounded-xl font-bold transition-all shadow-lg shadow-blue-600/20 flex items-center gap-2"
|
||||
>
|
||||
<MessageCircle className="w-5 h-5" />
|
||||
Iniciar Projeto
|
||||
</motion.a>
|
||||
|
||||
<div className="flex gap-4 px-4">
|
||||
{[
|
||||
{ icon: Github, link: "https://github.com/evandrodevbr", rel: "me" },
|
||||
{ icon: Linkedin, link: "https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/", rel: "me" },
|
||||
{ icon: Mail, link: "mailto:[email protected]" }
|
||||
].map((social, i) => (
|
||||
<a
|
||||
key={i}
|
||||
href={social.link}
|
||||
rel={social.rel ? `${social.rel} noopener noreferrer` : "noopener noreferrer"}
|
||||
target={social.link.startsWith("mailto:") ? undefined : "_blank"}
|
||||
className="p-3 rounded-lg border border-slate-800 text-slate-400 hover:text-white hover:border-slate-600 transition-all"
|
||||
<div className="flex items-center gap-2">
|
||||
{SOCIAL_LINKS.map((link) => (
|
||||
<a
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
target={link.href.startsWith("http") ? "_blank" : undefined}
|
||||
rel={
|
||||
link.href.startsWith("http")
|
||||
? "noopener noreferrer"
|
||||
: undefined
|
||||
}
|
||||
className="inline-flex h-11 w-11 items-center justify-center rounded-sm border transition-all duration-200 hover:bg-white/10"
|
||||
style={{
|
||||
borderColor: "rgba(255,255,255,.18)",
|
||||
color: "rgba(255,255,255,.84)",
|
||||
}}
|
||||
aria-label={link.label}
|
||||
>
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill={link.stroke ? "none" : "currentColor"}
|
||||
stroke={link.stroke ? "currentColor" : "none"}
|
||||
strokeWidth={link.stroke ? "2" : undefined}
|
||||
role="img"
|
||||
aria-label={link.label}
|
||||
>
|
||||
<social.icon className="w-5 h-5" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
{link.icon}
|
||||
</svg>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 flex items-center gap-2 text-slate-500 text-sm">
|
||||
<MapPin className="w-4 h-4" />
|
||||
<span>Garuva, SC | Remote Worldwide</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Lado Direito: Visual (A "Âncora" do Design) */}
|
||||
<div className="lg:col-span-5 relative flex justify-center">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
className="relative w-72 h-72 md:w-96 md:h-96"
|
||||
<div
|
||||
className="text-[10px] uppercase tracking-[0.14em]"
|
||||
style={{ color: "rgba(255,255,255,.38)" }}
|
||||
>
|
||||
{/* Elementos Orbitais (Vibe Engenharia) */}
|
||||
<div className="absolute inset-0 rounded-full border border-dashed border-blue-500/30 animate-[spin_20s_linear_infinite]" />
|
||||
<div className="absolute inset-10 rounded-full border border-blue-500/10 animate-[spin_15s_linear_infinite_reverse]" />
|
||||
Garuva, SC | Remote worldwide
|
||||
</div>
|
||||
|
||||
{/* Foto de Perfil com Masking de Engenharia */}
|
||||
<div className="relative z-10 w-full h-full rounded-[2.5rem] overflow-hidden border-2 border-slate-800 shadow-2xl">
|
||||
<div className="absolute inset-0 bg-blue-500/10 z-10 hover:opacity-0 transition-opacity duration-500" />
|
||||
<Image
|
||||
src="/edev.jpeg"
|
||||
alt="Evandro Fonseca Junior"
|
||||
fill
|
||||
className="object-cover grayscale hover:grayscale-0 transition-all duration-700 scale-105 hover:scale-100"
|
||||
priority
|
||||
fetchPriority="high"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Floating Stats Badge */}
|
||||
<div className="absolute -bottom-6 -right-6 bg-slate-900 border border-slate-800 p-4 rounded-2xl shadow-2xl z-20 backdrop-blur-xl">
|
||||
<p className="text-xs text-slate-500 uppercase font-bold tracking-tighter">Exp. Level</p>
|
||||
<p className="text-xl font-mono text-blue-400">Mid-Level Engineer</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
<div
|
||||
className="mt-10 grid max-w-[440px] grid-cols-3 gap-px border max-sm:grid-cols-1"
|
||||
style={{
|
||||
borderColor: "rgba(255,255,255,.12)",
|
||||
background: "rgba(255,255,255,.08)",
|
||||
}}
|
||||
>
|
||||
{STATS.map((item) => (
|
||||
<div
|
||||
key={item.label}
|
||||
className="p-5"
|
||||
style={{ background: "rgba(255,255,255,.03)" }}
|
||||
>
|
||||
<div
|
||||
className="font-display text-2xl font-extrabold tracking-[-0.03em]"
|
||||
style={{ color: "#FFFFFF" }}
|
||||
>
|
||||
{item.value}
|
||||
<span style={{ color: "#E8FF00" }}>{item.accent}</span>
|
||||
</div>
|
||||
<div
|
||||
className="mt-1 text-[9px] uppercase tracking-[0.12em]"
|
||||
style={{ color: "rgba(255,255,255,.35)" }}
|
||||
>
|
||||
{item.label}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scroll Indicator (Refinado) */}
|
||||
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2">
|
||||
<span className="text-[10px] text-slate-600 uppercase tracking-[0.2em]">Scroll</span>
|
||||
<div className="w-[1px] h-12 bg-gradient-to-b from-blue-500 to-transparent" />
|
||||
<div className="flex flex-col items-end gap-6 max-lg:items-start">
|
||||
<div
|
||||
className="relative flex aspect-square w-full max-w-[440px] items-center justify-center border max-lg:max-w-[320px]"
|
||||
style={{
|
||||
borderColor: "rgba(255,255,255,.12)",
|
||||
background: "rgba(255,255,255,.03)",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className="absolute left-6 top-5 text-[9px] tracking-[0.14em]"
|
||||
style={{ color: "rgba(255,255,255,.32)" }}
|
||||
>
|
||||
D / SLASH MARK
|
||||
</span>
|
||||
<Logo variant="mark" size="xl" theme="dark" />
|
||||
<span
|
||||
className="absolute bottom-5 right-6 text-[9px] tracking-[0.14em]"
|
||||
style={{ color: "#E8FF00", opacity: 0.78 }}
|
||||
>
|
||||
CONCEITO ESCOLHIDO
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex items-center gap-3 text-[9px] tracking-[0.12em]"
|
||||
style={{ color: "rgba(255,255,255,.32)" }}
|
||||
>
|
||||
<span
|
||||
className="h-px w-6"
|
||||
style={{ background: "rgba(255,255,255,.18)" }}
|
||||
/>
|
||||
D / Slash mark · conceito final
|
||||
</div>
|
||||
<div
|
||||
className="flex items-center gap-3 text-[9px] tracking-[0.12em]"
|
||||
style={{ color: "rgba(255,255,255,.32)" }}
|
||||
>
|
||||
<span
|
||||
className="h-px w-6"
|
||||
style={{ background: "rgba(255,255,255,.18)" }}
|
||||
/>
|
||||
Escala: 280x200 · viewbox
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
+73
-194
@@ -1,207 +1,86 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import React, { useMemo } from "react";
|
||||
import { motion } from "motion/react";
|
||||
import { BentoGrid, BentoGridItem } from "@/components/magicui/bento-grid";
|
||||
import {
|
||||
ExternalLink,
|
||||
Github,
|
||||
Star,
|
||||
Zap,
|
||||
Globe,
|
||||
Cpu,
|
||||
Code2,
|
||||
Terminal,
|
||||
} from "lucide-react";
|
||||
import { useMemo } from "react";
|
||||
import { usePortfolioData } from "@/lib/usePortfolioData";
|
||||
|
||||
// --- Configuração de Cores (Harmonizado com a seção anterior) ---
|
||||
const CATEGORY_THEMES: Record<string, any> = {
|
||||
"full-stack": { color: "text-blue-400", bg: "bg-blue-500/10", border: "border-blue-500/20", icon: Globe },
|
||||
iot: { color: "text-purple-400", bg: "bg-purple-500/10", border: "border-purple-500/20", icon: Cpu },
|
||||
api: { color: "text-orange-400", bg: "bg-orange-500/10", border: "border-orange-500/20", icon: Code2 },
|
||||
web: { color: "text-green-400", bg: "bg-green-500/10", border: "border-green-500/20", icon: Globe },
|
||||
desktop: { color: "text-emerald-400", bg: "bg-emerald-500/10", border: "border-emerald-500/20", icon: Terminal },
|
||||
};
|
||||
|
||||
// Funções auxiliares para Schema
|
||||
function getApplicationCategory(category: string): string {
|
||||
const map: Record<string, string> = {
|
||||
"full-stack": "WebApplication",
|
||||
"iot": "DesktopApplication",
|
||||
"api": "WebApplication",
|
||||
"web": "WebApplication",
|
||||
"desktop": "DesktopApplication"
|
||||
};
|
||||
return map[category.toLowerCase()] || "WebApplication";
|
||||
}
|
||||
|
||||
function getOperatingSystem(category: string): string {
|
||||
if (category.toLowerCase() === "desktop") return "Windows, Linux";
|
||||
return "Web Browser";
|
||||
}
|
||||
import { Section } from "./Section";
|
||||
|
||||
export default function Projects() {
|
||||
const { data, loading, error } = usePortfolioData();
|
||||
|
||||
const projects = useMemo(() =>
|
||||
data?.projects.filter((p) => p.featured) || [],
|
||||
[data]);
|
||||
|
||||
const projectsJsonLd = useMemo(() => {
|
||||
if (!projects || projects.length === 0) return null;
|
||||
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ItemList",
|
||||
"itemListElement": projects.map((project, index) => ({
|
||||
"@type": "ListItem",
|
||||
"position": index + 1,
|
||||
"item": {
|
||||
"@type": "SoftwareApplication",
|
||||
"name": project.title,
|
||||
"description": project.description,
|
||||
"applicationCategory": getApplicationCategory(project.category),
|
||||
"operatingSystem": getOperatingSystem(project.category),
|
||||
"url": project.demoUrl || project.githubUrl || `https://evandro.dev.br/#projects`,
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "0",
|
||||
"priceCurrency": "BRL"
|
||||
},
|
||||
"softwareVersion": "1.0.0",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Evandro Fonseca Junior",
|
||||
"url": "https://evandro.dev.br"
|
||||
}
|
||||
}
|
||||
}))
|
||||
};
|
||||
}, [projects]);
|
||||
|
||||
if (loading) return <div className="py-20 text-center animate-pulse text-slate-500 font-mono">Loading_Assets...</div>;
|
||||
if (error) return <div className="py-20 text-center text-red-500">System_Error: Failed to sync projects.</div>;
|
||||
|
||||
return (
|
||||
<section id="projects" className="py-32 px-6 relative">
|
||||
{/* Background Decor */}
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,_var(--tw-gradient-stops))] from-blue-500/5 via-transparent to-transparent pointer-events-none" />
|
||||
|
||||
<div className="max-w-7xl mx-auto relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="text-left mb-20"
|
||||
>
|
||||
<span className="text-blue-500 font-mono text-sm tracking-[0.3em] uppercase block mb-4">Produção_Intelectual</span>
|
||||
<h2 className="text-5xl md:text-7xl font-black text-white tracking-tighter">
|
||||
Projetos <span className="text-slate-700 italic">Principais</span>
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
<BentoGrid className="grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{projects.map((project, index) => {
|
||||
const theme = CATEGORY_THEMES[project.category.toLowerCase()] || CATEGORY_THEMES.web;
|
||||
|
||||
// Lógica de Grid Inteligente:
|
||||
// Index 0: NutriScan (Destaque - 2 colunas)
|
||||
// Index 1: Twins Lab (Complemento - 1 coluna)
|
||||
// Demais: 1 coluna cada (Preenche a linha 2 perfeitamente)
|
||||
const colSpan = index === 0 ? "md:col-span-2" : "md:col-span-1";
|
||||
|
||||
return (
|
||||
<BentoGridItem
|
||||
key={project.id}
|
||||
className={`${colSpan} group relative flex flex-col justify-between overflow-hidden rounded-3xl border border-slate-800 bg-slate-900/40 backdrop-blur-xl p-8 transition-all duration-500 hover:border-blue-500/30 min-h-[22rem]`}
|
||||
>
|
||||
{/* Header: Icon & Links */}
|
||||
<div className="relative z-10">
|
||||
<div className="flex items-start justify-between mb-8">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`p-4 rounded-2xl ${theme.bg} border ${theme.border} group-hover:scale-110 transition-transform duration-500`}>
|
||||
<theme.icon className={`w-6 h-6 ${theme.color}`} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-white tracking-tight">{project.title}</h3>
|
||||
<p className="text-sm text-slate-500 font-medium">{project.subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
{project.githubUrl && <ProjectLink href={project.githubUrl} icon={Github} />}
|
||||
{project.demoUrl && <ProjectLink href={project.demoUrl} icon={ExternalLink} highlight />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Badges de Tecnologias */}
|
||||
<div className="flex flex-wrap gap-2 mb-6">
|
||||
{project.technologies.slice(0, 5).map((tech: string) => (
|
||||
<span key={tech} className="px-2 py-1 text-[10px] font-mono font-bold bg-slate-950 text-slate-400 border border-slate-800 rounded-md">
|
||||
{tech}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="text-slate-400 text-sm leading-relaxed mb-6 line-clamp-3 group-hover:line-clamp-none transition-all duration-500">
|
||||
{project.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Footer: Metrics & Status */}
|
||||
<div className="relative z-10 pt-6 border-t border-slate-800/50 mt-auto flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-[10px] uppercase tracking-widest text-slate-600 font-bold">Complexity</span>
|
||||
<ComplexityStars rating={project.metrics?.complexity || 3} />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`w-2 h-2 rounded-full animate-pulse ${project.status === 'Em Produção' ? 'bg-emerald-500' : 'bg-blue-500'}`} />
|
||||
<span className="text-[10px] font-bold text-slate-400 uppercase">{project.status}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Background Hover Glow */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/5 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700" />
|
||||
</BentoGridItem>
|
||||
);
|
||||
})}
|
||||
</BentoGrid>
|
||||
|
||||
{/* JSON-LD Schema for Projects */}
|
||||
{projectsJsonLd && (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(projectsJsonLd) }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
const projects = useMemo(
|
||||
() => data?.projects.filter((p) => p.featured) || [],
|
||||
[data],
|
||||
);
|
||||
}
|
||||
|
||||
// --- Subcomponentes Auxiliares ---
|
||||
if (loading)
|
||||
return <div className="ds-loading">Loading featured projects</div>;
|
||||
if (error)
|
||||
return <div className="ds-error">Error loading featured projects</div>;
|
||||
|
||||
function ProjectLink({ href, icon: Icon, highlight }: { href: string; icon: any; highlight?: boolean }) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`p-2 rounded-xl transition-all duration-300 hover:scale-110 ${highlight ? 'bg-blue-600 text-white shadow-lg shadow-blue-600/20' : 'bg-slate-900 border border-slate-800 text-slate-500 hover:text-white'
|
||||
}`}
|
||||
<Section
|
||||
id="projects"
|
||||
eyebrow="PRODUCAO_INTELECTUAL"
|
||||
title="Projetos com recorte técnico claro e impacto observável"
|
||||
description="Seleção de produtos e ferramentas onde performance, confiabilidade e clareza de arquitetura foram requisitos reais."
|
||||
dark
|
||||
>
|
||||
<Icon className="w-4 h-4" />
|
||||
</a>
|
||||
<div className="ds-grid-2">
|
||||
{projects.map((project) => (
|
||||
<article key={project.id} className="ds-card">
|
||||
<div className="flex items-start justify-between gap-sp-6">
|
||||
<div>
|
||||
<div className="ds-kicker">{project.category}</div>
|
||||
<h3 className="ds-card-title">{project.title}</h3>
|
||||
<p className="mt-sp-2 text-[11px] uppercase tracking-[0.1em] text-[rgba(255,255,255,.36)]">
|
||||
{project.subtitle}
|
||||
</p>
|
||||
</div>
|
||||
<span className="ds-tag">{project.status}</span>
|
||||
</div>
|
||||
<p className="ds-copy">{project.description}</p>
|
||||
<div className="mt-sp-6 flex flex-wrap gap-sp-3">
|
||||
{project.githubUrl && (
|
||||
<a
|
||||
href={project.githubUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="ds-link ds-link-muted"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
)}
|
||||
{project.demoUrl && (
|
||||
<a
|
||||
href={project.demoUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="ds-link ds-link-accent"
|
||||
>
|
||||
Live demo
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<ul className="ds-tags mt-sp-6">
|
||||
{project.technologies.slice(0, 6).map((tech: string) => (
|
||||
<li key={tech} className="ds-tag">
|
||||
{tech}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-sp-6 flex flex-wrap gap-sp-4">
|
||||
<span className="ds-metric">
|
||||
Complexity {project.metrics?.complexity || 3}/5
|
||||
</span>
|
||||
{project.metrics?.teamSize && (
|
||||
<span className="ds-metric">
|
||||
Team {project.metrics.teamSize}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
function ComplexityStars({ rating }: { rating: number }) {
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<div key={i} className={`w-1.5 h-1.5 rounded-full ${i < rating ? 'bg-yellow-500' : 'bg-slate-800'}`} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+29
-121
@@ -1,134 +1,42 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import {
|
||||
Code, Database, Cloud, Cpu, Smartphone,
|
||||
Zap, GitBranch, TestTube, Terminal, Layers
|
||||
} from "lucide-react";
|
||||
import { usePortfolioData } from "@/lib/usePortfolioData";
|
||||
|
||||
const ICON_MAP: Record<string, React.ElementType> = {
|
||||
Code, Database, Cloud, Cpu, Smartphone, Zap, GitBranch, TestTube, Terminal, Layers
|
||||
};
|
||||
|
||||
const getCategoryStyles = (color: string) => {
|
||||
const base = color.replace("text-", "");
|
||||
return {
|
||||
icon: color,
|
||||
bg: `bg-${base}/10`,
|
||||
border: `border-slate-800/50`,
|
||||
};
|
||||
};
|
||||
import { Section } from "./Section";
|
||||
|
||||
export default function Skills() {
|
||||
const { data, loading, error } = usePortfolioData();
|
||||
|
||||
if (loading) return <LoadingState />;
|
||||
if (error || !data) return <ErrorState />;
|
||||
if (loading) return <div className="ds-loading">Loading skill registry</div>;
|
||||
if (error || !data) {
|
||||
return <div className="ds-error">Error loading skill registry</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<section id="skills" className="relative py-32 px-6">
|
||||
{/* Background Decoration */}
|
||||
<div className="absolute top-0 left-0 w-full h-full pointer-events-none">
|
||||
<div className="absolute top-[40%] left-[50%] -translate-x-1/2 w-[800px] h-[800px] bg-blue-900/5 rounded-full blur-[100px]" />
|
||||
</div>
|
||||
|
||||
<div className="max-w-7xl mx-auto relative z-10">
|
||||
|
||||
{/* Header Seção */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
className="flex flex-col md:flex-row justify-between items-end mb-20 gap-8"
|
||||
>
|
||||
<div className="text-left">
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-blue-950/30 border border-blue-500/20 text-blue-400 font-mono text-xs tracking-wider mb-4">
|
||||
<Layers className="w-3 h-3" />
|
||||
<span>MODULE_REGISTRY.lib</span>
|
||||
<Section
|
||||
id="skills"
|
||||
eyebrow="MODULE_REGISTRY.lib"
|
||||
title="Stack modular para produto, operação e escala"
|
||||
description="Ferramentas escolhidas por previsibilidade operacional, velocidade de entrega e facilidade de manutenção."
|
||||
dark
|
||||
>
|
||||
<div className="ds-grid-2">
|
||||
{data.skills.technical.map((category, index) => (
|
||||
<article key={category.category} className="ds-card">
|
||||
<div className="flex items-center justify-between gap-sp-4">
|
||||
<div className="ds-kicker">ID_0{index + 1}X</div>
|
||||
<div className="ds-metric">{category.skills.length} items</div>
|
||||
</div>
|
||||
<h3 className="text-4xl md:text-6xl font-black text-white tracking-tighter">
|
||||
Arsenal <span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-500 to-indigo-500">Tecnológico</span>
|
||||
</h3>
|
||||
</div>
|
||||
<p className="text-slate-400 max-w-md text-sm md:text-base font-light leading-relaxed border-l-2 border-slate-800 pl-6">
|
||||
Sistemas resilientes construídos com precisão matemática e rigor arquitetural.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Grid de Habilidades */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{data.skills.technical.map((category, index) => {
|
||||
const Icon = ICON_MAP[category.icon] || Code;
|
||||
const styles = getCategoryStyles(category.color);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={category.category}
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, amount: 0.2 }}
|
||||
transition={{
|
||||
duration: 0.5,
|
||||
delay: index * 0.05,
|
||||
ease: "easeOut"
|
||||
}}
|
||||
className="h-full"
|
||||
>
|
||||
<div
|
||||
className="group relative h-full p-8 flex flex-col bg-zinc-900/40 border border-white/5 rounded-2xl backdrop-blur-sm hover:border-blue-500/20 hover:bg-zinc-900/60 transition-all duration-300 overflow-hidden"
|
||||
>
|
||||
{/* Scanning Line Effect */}
|
||||
<div className="absolute top-0 left-0 w-full h-[2px] bg-gradient-to-r from-transparent via-blue-500/50 to-transparent -translate-x-full group-hover:animate-scan" />
|
||||
|
||||
<div className="flex items-start justify-between mb-8">
|
||||
<div className={`p-4 rounded-xl bg-slate-800/50 border border-white/5 group-hover:bg-blue-500/10 group-hover:border-blue-500/20 transition-all duration-300`}>
|
||||
<Icon className={`w-8 h-8 text-slate-400 group-hover:text-blue-400 transition-colors`} />
|
||||
</div>
|
||||
<span className="text-[10px] font-mono text-slate-600 uppercase tracking-widest font-bold group-hover:text-blue-500/50 transition-colors">
|
||||
ID_0{index}X
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-xl font-bold text-white mb-6 group-hover:text-blue-200 transition-colors">
|
||||
{category.category}
|
||||
</h3>
|
||||
|
||||
<div className="flex flex-wrap gap-2 mt-auto">
|
||||
{category.skills.map((skill, sIdx) => (
|
||||
<span
|
||||
key={sIdx}
|
||||
className="px-2.5 py-1 text-[10px] font-mono bg-black/40 text-slate-400 rounded border border-white/5 group-hover:border-blue-500/20 group-hover:text-blue-300 transition-all duration-300 cursor-default"
|
||||
>
|
||||
{skill}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<h3 className="ds-card-title">{category.category}</h3>
|
||||
<ul className="ds-tags mt-sp-6">
|
||||
{category.skills.map((skill) => (
|
||||
<li key={skill} className="ds-tag">
|
||||
{skill}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
// --- Componentes de Suporte (Manter no mesmo arquivo para contexto ou mover para /components) ---
|
||||
function LoadingState() {
|
||||
return (
|
||||
<div className="py-32 flex flex-col items-center justify-center space-y-4 bg-[#030712]">
|
||||
<div className="w-12 h-12 border-4 border-blue-500/20 border-t-blue-500 rounded-full animate-spin" />
|
||||
<span className="text-slate-500 font-mono text-sm animate-pulse uppercase tracking-tighter">Initializing Systems...</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ErrorState() {
|
||||
return (
|
||||
<div className="py-32 text-center text-red-400 font-mono bg-[#030712]">
|
||||
[FATAL_ERROR]: Failed to synchronize portfolio data.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,272 +1,110 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import {
|
||||
Briefcase,
|
||||
Clock,
|
||||
HardHat,
|
||||
Lightbulb,
|
||||
Building2,
|
||||
Users,
|
||||
User,
|
||||
Star,
|
||||
CheckCircle2,
|
||||
Terminal,
|
||||
ShieldCheck,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
import { Section } from "./Section";
|
||||
|
||||
// --- 1. DATA ---
|
||||
const WorkModalitiesData = [
|
||||
{
|
||||
title: "Intervenção Ad-hoc",
|
||||
value: "R$ 35 - 70/hora",
|
||||
badge: "AGILIDADE",
|
||||
badge: "Agilidade",
|
||||
idealFor:
|
||||
"Resolução de gargalos técnicos específicos e consultoria de arquitetura imediata.",
|
||||
description:
|
||||
"Engenharia sob demanda com foco em troubleshooting e otimização de performance. Rastreabilidade total via timesheet detalhado.",
|
||||
"Engenharia sob demanda com foco em troubleshooting, performance e decisões rápidas com rastreabilidade.",
|
||||
benefits: [
|
||||
"Diagnóstico Sênior Imediato",
|
||||
"Sem Compromisso de Longo Prazo",
|
||||
"Documentação de Alterações",
|
||||
"Diagnóstico sênior imediato",
|
||||
"Sem compromisso de longo prazo",
|
||||
"Documentação de alterações",
|
||||
],
|
||||
icon: Zap,
|
||||
color: "blue",
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
title: "Alocação de Sprint",
|
||||
value: "Eficiência Financeira",
|
||||
badge: "MAIS ESCOLHIDO",
|
||||
title: "Alocação de sprint",
|
||||
value: "Eficiência financeira",
|
||||
badge: "Mais escolhido",
|
||||
idealFor:
|
||||
"Desenvolvimento contínuo de features com previsibilidade de budget e prioridade técnica.",
|
||||
"Times que precisam de entrega contínua com previsibilidade de orçamento e prioridade técnica.",
|
||||
description:
|
||||
"Pacotes de horas pré-pagas que garantem disponibilidade na agenda e redução do custo unitário por hora. Ideal para scaling.",
|
||||
"Pacotes de horas pré-pagas com redução de custo unitário e espaço reservado na agenda para evolução constante.",
|
||||
benefits: [
|
||||
"Taxa horária reduzida (Lock-in)",
|
||||
"Garantia de Disponibilidade",
|
||||
"Prioridade em Critical Bugs",
|
||||
"Taxa horária reduzida",
|
||||
"Garantia de disponibilidade",
|
||||
"Prioridade em bugs críticos",
|
||||
],
|
||||
icon: Briefcase,
|
||||
color: "green",
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
title: "Engenheiro Dedicado",
|
||||
title: "Engenheiro dedicado",
|
||||
value: "A partir de R$ 2.800/mês",
|
||||
badge: "VIP & ESTRATÉGICO",
|
||||
badge: "Estratégico",
|
||||
idealFor:
|
||||
"Empresas que necessitam de um 'Fractional CTO' ou Lead Engineer para governança técnica.",
|
||||
"Empresas que precisam de liderança técnica contínua, coordenação de backlog e direção arquitetural.",
|
||||
description:
|
||||
"Parceria estratégica com foco em sustentabilidade do sistema, manutenção preventiva e evolução arquitetural contínua.",
|
||||
"Parceria recorrente para sustentação, evolução de sistema, revisão de dívida técnica e tomada de decisão.",
|
||||
benefits: [
|
||||
"SLA de Resposta Prioritária",
|
||||
"Gestão de Débito Técnico",
|
||||
"Consultoria Estratégica",
|
||||
"SLA prioritário",
|
||||
"Gestão de débito técnico",
|
||||
"Consultoria estratégica",
|
||||
],
|
||||
icon: ShieldCheck,
|
||||
color: "purple",
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
title: "Squad por Projeto",
|
||||
value: "Escopo Fechado",
|
||||
badge: "CONTROLE TOTAL",
|
||||
title: "Squad por projeto",
|
||||
value: "Escopo fechado",
|
||||
badge: "Controle total",
|
||||
idealFor:
|
||||
"Produtos novos ou migrações de sistemas onde o orçamento é rigorosamente definido pelo escopo.",
|
||||
"Produtos novos, replatforming ou migrações com orçamento definido por entregáveis e marcos claros.",
|
||||
description:
|
||||
"Desenvolvimento orientado a entregáveis (milestones). Mitigação de riscos através de definições claras de 'Done'.",
|
||||
"Execução orientada a milestones com redução de risco através de definição objetiva de escopo e critérios de done.",
|
||||
benefits: [
|
||||
"Estimativa de Riscos Inclusa",
|
||||
"Cronograma de Entregas",
|
||||
"Garantia Pós-Entrega",
|
||||
"Estimativa de riscos inclusa",
|
||||
"Cronograma de entregas",
|
||||
"Garantia pós-entrega",
|
||||
],
|
||||
icon: HardHat,
|
||||
color: "orange",
|
||||
featured: false,
|
||||
},
|
||||
];
|
||||
|
||||
// --- 2. COMPONENTS ---
|
||||
|
||||
export function WorkModalities() {
|
||||
return (
|
||||
<section
|
||||
<Section
|
||||
id="modalities"
|
||||
className="py-32 px-6 relative"
|
||||
eyebrow="CONTRACT_PROTOCOLS.sys"
|
||||
title="Formatos de contratação para contextos técnicos distintos"
|
||||
description="Modelos pensados para reduzir overhead, preservar velocidade de decisão e manter previsibilidade."
|
||||
>
|
||||
{/* Background Decor handled globally now, avoiding overflow-hidden here allows bleed */}
|
||||
|
||||
<div className="max-w-7xl mx-auto relative z-10">
|
||||
|
||||
{/* Header Profissional */}
|
||||
<div className="mb-24 text-center md:text-left">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-blue-950/30 border border-blue-500/20 text-blue-400 font-mono text-xs tracking-wider mb-6"
|
||||
>
|
||||
<Terminal className="w-3 h-3" />
|
||||
<span>CONTRACT_PROTOCOLS.sys</span>
|
||||
</motion.div>
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="text-4xl md:text-6xl font-black text-white tracking-tighter"
|
||||
>
|
||||
Flexibilidade <br />
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-500 to-cyan-400">Contratual</span>
|
||||
</motion.h2>
|
||||
<p className="mt-6 text-lg text-slate-400 max-w-2xl leading-relaxed font-light border-l-2 border-slate-800 pl-6">
|
||||
Modelos de engajamento adaptáveis para diferentes estágios de maturidade tecnológica e orçamentária.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Comparação de Mercado (Anchoring Effect) */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-24">
|
||||
<MarketCard
|
||||
title="Agências Tradicionais"
|
||||
price="Alto Overhead"
|
||||
icon={Building2}
|
||||
color="text-red-500"
|
||||
delay={0}
|
||||
best={false}
|
||||
/>
|
||||
<MarketCard
|
||||
title="Consultorias Big Tech"
|
||||
price="Custo Inflacionado"
|
||||
icon={Users}
|
||||
color="text-orange-500"
|
||||
delay={0.1}
|
||||
best={false}
|
||||
/>
|
||||
<MarketCard
|
||||
title="Freelancers Generalistas"
|
||||
price="Risco Técnico"
|
||||
icon={User}
|
||||
color="text-yellow-500"
|
||||
delay={0.2}
|
||||
best={false}
|
||||
/>
|
||||
<MarketCard
|
||||
title="Engenheiro Especialista"
|
||||
price="High ROI"
|
||||
icon={Star}
|
||||
color="text-emerald-400"
|
||||
best={true}
|
||||
delay={0.3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Grid de Modalidades */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
{WorkModalitiesData.map((modality, index) => (
|
||||
<ModalityCard key={modality.title} modality={modality} index={index} />
|
||||
))}
|
||||
</div>
|
||||
<div className="ds-grid-4 mb-sp-6">
|
||||
{[
|
||||
["Agências tradicionais", "Alto overhead"],
|
||||
["Consultorias big tech", "Custo inflacionado"],
|
||||
["Freelancers generalistas", "Risco técnico"],
|
||||
["Engenheiro especialista", "High ROI"],
|
||||
].map(([label, value]) => (
|
||||
<div key={label} className="ds-panel">
|
||||
<div className="ds-kicker">{label}</div>
|
||||
<div className="mt-sp-3 font-display text-2xl font-extrabold tracking-[-0.02em]">
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function MarketCard({ title, price, icon: Icon, color, best, delay }: any) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay }}
|
||||
className={`p-6 rounded-2xl border backdrop-blur-sm transition-all duration-300 ${best
|
||||
? "bg-emerald-500/5 border-emerald-500/20 shadow-[0_0_20px_rgba(16,185,129,0.1)]"
|
||||
: "bg-zinc-900/40 border-white/5 opacity-70 hover:opacity-100"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<Icon className={`w-4 h-4 ${color}`} />
|
||||
<h4 className="text-[10px] font-bold text-slate-400 uppercase tracking-widest">
|
||||
{title}
|
||||
</h4>
|
||||
<div className="ds-grid-2">
|
||||
{WorkModalitiesData.map((modality) => (
|
||||
<article key={modality.title} className="ds-card">
|
||||
<div className="flex items-center justify-between gap-sp-4">
|
||||
<span className="ds-kicker">{modality.badge}</span>
|
||||
<span className="ds-tag">{modality.value}</span>
|
||||
</div>
|
||||
<h3 className="ds-card-title">{modality.title}</h3>
|
||||
<p className="ds-copy">{modality.description}</p>
|
||||
<div className="mt-sp-5 rounded-[var(--r-md)] bg-[rgba(10,10,10,.03)] p-sp-4 text-[11px] leading-7 text-ink-80">
|
||||
Ideal para: {modality.idealFor}
|
||||
</div>
|
||||
<ul className="ds-list">
|
||||
{modality.benefits.map((benefit) => (
|
||||
<li key={benefit}>{benefit}</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
<p className={`text-sm font-bold ${best ? "text-emerald-400" : "text-slate-500"}`}>
|
||||
{price}
|
||||
</p>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
function ModalityCard({ modality, index }: { modality: any; index: number }) {
|
||||
const Icon = modality.icon;
|
||||
const isFeatured = modality.featured;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-50px" }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
className={`group relative flex flex-col p-8 rounded-3xl border transition-all duration-500 overflow-hidden ${isFeatured
|
||||
? "bg-zinc-900/60 border-blue-500/30 shadow-2xl shadow-blue-900/10"
|
||||
: "bg-zinc-900/40 border-white/5 hover:border-white/10"
|
||||
}`}
|
||||
>
|
||||
{/* Hover Gradient */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
|
||||
{/* Badge */}
|
||||
{modality.badge && (
|
||||
<div className="absolute top-6 right-6">
|
||||
<span className={`px-3 py-1 rounded-full text-[10px] font-bold tracking-widest uppercase border ${isFeatured
|
||||
? "bg-blue-500/10 border-blue-500/20 text-blue-300"
|
||||
: "bg-slate-800/50 border-slate-700 text-slate-400"
|
||||
}`}>
|
||||
{modality.badge}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Header */}
|
||||
<div className="relative z-10 mb-8">
|
||||
<div className={`w-12 h-12 rounded-xl flex items-center justify-center mb-6 transition-transform group-hover:scale-110 ${isFeatured ? "bg-blue-500/10 text-blue-400" : "bg-slate-800/50 text-slate-400"
|
||||
}`}>
|
||||
<Icon className="w-6 h-6" />
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold text-white mb-2 group-hover:text-blue-200 transition-colors">
|
||||
{modality.title}
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-slate-500">
|
||||
{modality.value}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10 flex-1">
|
||||
<p className="text-slate-400 text-sm leading-relaxed mb-8">
|
||||
{modality.description}
|
||||
</p>
|
||||
|
||||
<ul className="space-y-3 mb-8">
|
||||
{modality.benefits.map((benefit: string, i: number) => (
|
||||
<li key={i} className="flex items-start gap-3 text-xs text-slate-300">
|
||||
<CheckCircle2 className={`w-4 h-4 flex-shrink-0 mt-0.5 ${isFeatured ? "text-blue-400" : "text-slate-500"}`} />
|
||||
<span>{benefit}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="relative z-10 pt-6 border-t border-white/5 mt-auto">
|
||||
<p className="text-[10px] uppercase tracking-wider text-slate-500">
|
||||
<span className="text-slate-600 font-bold mb-1 block">Ideal Para:</span>
|
||||
{modality.idealFor}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
+309
-159
@@ -1,168 +1,318 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@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");
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--animate-aurora: aurora 8s ease-in-out infinite alternate;
|
||||
@keyframes aurora {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
transform: rotate(-5deg) scale(0.9);
|
||||
}
|
||||
25% {
|
||||
background-position: 50% 100%;
|
||||
transform: rotate(5deg) scale(1.1);
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
transform: rotate(-3deg) scale(0.95);
|
||||
}
|
||||
75% {
|
||||
background-position: 50% 0%;
|
||||
transform: rotate(3deg) scale(1.05);
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
transform: rotate(-5deg) scale(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--blue-primary: #4facfe; /* Nova cor azul primária */
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--ink: #0a0a0a;
|
||||
--ink-80: rgba(10, 10, 10, 0.8);
|
||||
--ink-40: rgba(10, 10, 10, 0.4);
|
||||
--ink-12: rgba(10, 10, 10, 0.12);
|
||||
--ink-06: rgba(10, 10, 10, 0.06);
|
||||
--paper: #f4f2ed;
|
||||
--paper-dark: #eceae4;
|
||||
--white: #ffffff;
|
||||
--slash: #e8ff00;
|
||||
--slash-dim: rgba(232, 255, 0, 0.15);
|
||||
--meta: #777;
|
||||
--border: rgba(10, 10, 10, 0.1);
|
||||
--border-light: rgba(10, 10, 10, 0.06);
|
||||
--sp-1: 4px;
|
||||
--sp-2: 8px;
|
||||
--sp-3: 12px;
|
||||
--sp-4: 16px;
|
||||
--sp-5: 20px;
|
||||
--sp-6: 24px;
|
||||
--sp-8: 32px;
|
||||
--sp-10: 40px;
|
||||
--sp-12: 48px;
|
||||
--sp-16: 64px;
|
||||
--sp-20: 80px;
|
||||
--sp-24: 96px;
|
||||
--r-sm: 4px;
|
||||
--r-md: 8px;
|
||||
--r-lg: 16px;
|
||||
--r-full: 999px;
|
||||
--font-display: "Syne", 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);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.205 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.205 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.922 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.556 0 0);
|
||||
--blue-primary: #4facfe; /* Nova cor azul primária */
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.205 0 0);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
@apply bg-[#030712] text-foreground overflow-x-hidden max-w-[100vw];
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.animate-shimmer {
|
||||
animation: shimmer 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth; /* Adicionar rolagem suave */
|
||||
scroll-padding-top: 64px; /* Altura do cabeçalho fixo */
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--paper);
|
||||
color: var(--ink);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--slash);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.bg-grid {
|
||||
background-image:
|
||||
linear-gradient(rgba(10, 10, 10, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(10, 10, 10, 0.03) 1px, transparent 1px);
|
||||
background-size: 48px 48px;
|
||||
}
|
||||
|
||||
.bg-grid-light {
|
||||
background-image:
|
||||
linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
|
||||
background-size: 48px 48px;
|
||||
}
|
||||
|
||||
.ds-main {
|
||||
padding-top: 52px;
|
||||
}
|
||||
|
||||
.ds-section {
|
||||
padding: var(--sp-20) var(--sp-16);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.ds-section:nth-of-type(even) {
|
||||
background: var(--paper-dark);
|
||||
}
|
||||
|
||||
.ds-section-dark {
|
||||
background: var(--ink);
|
||||
border-bottom-color: rgba(255, 255, 255, 0.06);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.ds-section-shell,
|
||||
.ds-loading,
|
||||
.ds-error {
|
||||
width: min(1240px, 100%);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.ds-section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: var(--sp-8);
|
||||
margin-bottom: var(--sp-12);
|
||||
}
|
||||
|
||||
.ds-section-meta {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.ds-eyebrow,
|
||||
.ds-kicker {
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
color: var(--meta);
|
||||
}
|
||||
|
||||
.ds-eyebrow {
|
||||
margin-bottom: var(--sp-2);
|
||||
}
|
||||
|
||||
.ds-section-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(24px, 4vw, 40px);
|
||||
line-height: 1.05;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.ds-section-description {
|
||||
color: var(--meta);
|
||||
font-size: 11px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.ds-grid-2,
|
||||
.ds-grid-4 {
|
||||
display: grid;
|
||||
gap: var(--sp-6);
|
||||
}
|
||||
|
||||
.ds-grid-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.ds-grid-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.ds-card,
|
||||
.ds-panel {
|
||||
border: 1px solid var(--border);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.ds-card {
|
||||
background: rgba(255, 255, 255, 0.55);
|
||||
padding: var(--sp-6);
|
||||
}
|
||||
|
||||
.ds-panel {
|
||||
background: rgba(10, 10, 10, 0.02);
|
||||
padding: var(--sp-5);
|
||||
}
|
||||
|
||||
.ds-card-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(18px, 2.4vw, 28px);
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
margin-top: var(--sp-3);
|
||||
}
|
||||
|
||||
.ds-copy {
|
||||
margin-top: var(--sp-4);
|
||||
color: var(--ink-80);
|
||||
font-size: 12px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.ds-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--sp-2);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.ds-tag {
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--r-full);
|
||||
background: rgba(10, 10, 10, 0.03);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.ds-metric {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-2);
|
||||
color: var(--meta);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.ds-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-2);
|
||||
text-decoration: none;
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
transition:
|
||||
transform 0.2s ease,
|
||||
background 0.2s ease,
|
||||
border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.ds-link:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.ds-link-accent {
|
||||
color: var(--ink);
|
||||
background: var(--slash);
|
||||
padding: 12px 18px;
|
||||
}
|
||||
|
||||
.ds-link-muted {
|
||||
padding: 12px 18px;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.ds-list {
|
||||
margin-top: var(--sp-6);
|
||||
padding-left: var(--sp-5);
|
||||
font-size: 12px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.ds-list li::marker {
|
||||
color: var(--slash);
|
||||
}
|
||||
|
||||
.ds-loading,
|
||||
.ds-error {
|
||||
padding: var(--sp-10) var(--sp-16);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.ds-section-dark .ds-eyebrow,
|
||||
.ds-section-dark .ds-kicker,
|
||||
.ds-section-dark .ds-metric {
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.ds-section-dark .ds-section-description {
|
||||
color: rgba(255, 255, 255, 0.38);
|
||||
}
|
||||
|
||||
.ds-section-dark .ds-card,
|
||||
.ds-section-dark .ds-panel {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.ds-section-dark .ds-copy,
|
||||
.ds-section-dark .ds-list {
|
||||
color: rgba(255, 255, 255, 0.68);
|
||||
}
|
||||
|
||||
.ds-section-dark .ds-tag {
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.ds-section-dark .ds-link-muted {
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.ds-section {
|
||||
padding: var(--sp-16) var(--sp-6);
|
||||
}
|
||||
|
||||
.ds-section-header,
|
||||
.ds-grid-2,
|
||||
.ds-grid-4 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
+2
-55
@@ -1,25 +1,8 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import Script from "next/script";
|
||||
// Importação necessária para corrigir o erro de namespace e tipagem do children
|
||||
import { ReactNode } from "react";
|
||||
import GoogleAnalytics from "./components/GoogleAnalytics";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
adjustFontFallback: true,
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
adjustFontFallback: true,
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Evandro Fonseca Junior | Engenheiro de Software (Next.js, Tauri & Rust)",
|
||||
description:
|
||||
@@ -97,13 +80,12 @@ export const metadata: Metadata = {
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#000000",
|
||||
themeColor: "#ffffff",
|
||||
width: "device-width",
|
||||
initialScale: 1,
|
||||
maximumScale: 5,
|
||||
};
|
||||
|
||||
// Interface tipada corretamente
|
||||
interface RootLayoutProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
@@ -149,49 +131,14 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
return (
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
{/* Preconnect to external origins for better performance */}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link
|
||||
rel="preconnect"
|
||||
href="https://fonts.gstatic.com"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
<link rel="preconnect" href="https://wa.me" />
|
||||
<link rel="preconnect" href="https://www.linkedin.com" />
|
||||
<link rel="preconnect" href="https://github.com" />
|
||||
|
||||
{/* DNS prefetch for additional performance */}
|
||||
<link rel="dns-prefetch" href="//fonts.googleapis.com" />
|
||||
<link rel="dns-prefetch" href="//fonts.gstatic.com" />
|
||||
<link rel="dns-prefetch" href="//wa.me" />
|
||||
<link rel="dns-prefetch" href="//www.linkedin.com" />
|
||||
<link rel="dns-prefetch" href="//github.com" />
|
||||
|
||||
{/* SEO and Crawling */}
|
||||
<link rel="canonical" href="https://evandro.dev.br" />
|
||||
|
||||
{/* Theme color for mobile browsers */}
|
||||
<meta name="msapplication-TileColor" content="#000000" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-title" content="Evandro.dev" />
|
||||
</head>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<body>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
{children}
|
||||
<Script
|
||||
src="/analytics/api/script.js"
|
||||
data-site-id="1"
|
||||
data-debounce="100"
|
||||
strategy="afterInteractive"
|
||||
/>
|
||||
<GoogleAnalytics />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+10
-65
@@ -1,78 +1,23 @@
|
||||
import dynamic from "next/dynamic";
|
||||
import About from "./components/About";
|
||||
import Contact from "./components/Contact";
|
||||
import Experience from "./components/Experience";
|
||||
import { Header } from "./components/Header";
|
||||
import Squares from "@/components/Squares";
|
||||
import { WorkModalities } from "./components/WorkModalities"; // Importar WorkModalities
|
||||
import DotGrid from "@/components/DotGrid";
|
||||
|
||||
// Lazy load components for better performance
|
||||
const Hero = dynamic(() => import("./components/Hero"), {
|
||||
loading: () => (
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="animate-pulse text-white">Carregando...</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
const About = dynamic(() => import("./components/About"), {
|
||||
loading: () => (
|
||||
<div className="py-20 px-4 text-center">
|
||||
<div className="animate-pulse text-white">Carregando seção...</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
const Skills = dynamic(() => import("./components/Skills"), {
|
||||
loading: () => (
|
||||
<div className="py-20 px-4 text-center">
|
||||
<div className="animate-pulse text-white">Carregando habilidades...</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
const Experience = dynamic(() => import("./components/Experience"), {
|
||||
loading: () => (
|
||||
<div className="py-20 px-4 text-center">
|
||||
<div className="animate-pulse text-white">Carregando experiência...</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
const Projects = dynamic(() => import("./components/Projects"), {
|
||||
loading: () => (
|
||||
<div className="py-20 px-4 text-center">
|
||||
<div className="animate-pulse text-white">Carregando projetos...</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
const Contact = dynamic(() => import("./components/Contact"), {
|
||||
loading: () => (
|
||||
<div className="py-20 px-4 text-center">
|
||||
<div className="animate-pulse text-white">Carregando contato...</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
import Hero from "./components/Hero";
|
||||
import Projects from "./components/Projects";
|
||||
import Skills from "./components/Skills";
|
||||
import { WorkModalities } from "./components/WorkModalities";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="min-h-screen text-white relative">
|
||||
<div className="fixed inset-0 z-0 opacity-50">
|
||||
<Squares
|
||||
speed={0.5}
|
||||
squareSize={40}
|
||||
direction="diagonal" // up, down, left, right, diagonal
|
||||
borderColor="#271E37"
|
||||
hoverFillColor="#222222"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Header />
|
||||
<main className="relative z-10">
|
||||
<main className="ds-main">
|
||||
<Hero />
|
||||
<About />
|
||||
<Skills />
|
||||
<Experience />
|
||||
<Projects />
|
||||
<WorkModalities /> {/* Adicionar WorkModalities aqui */}
|
||||
<WorkModalities />
|
||||
<Contact />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Generated
+245
-217
@@ -4,6 +4,15 @@ settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
next@>=10.0.0 <15.5.10: '>=15.5.10'
|
||||
next@>=15.5.1-canary.0 <15.5.10: '>=15.5.10'
|
||||
tar@<7.5.7: '>=7.5.7'
|
||||
tar@<7.5.8: '>=7.5.8'
|
||||
tar@<=7.5.2: '>=7.5.3'
|
||||
tar@<=7.5.3: '>=7.5.4'
|
||||
tar@<=7.5.9: '>=7.5.10'
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -30,8 +39,8 @@ importers:
|
||||
specifier: ^12.23.12
|
||||
version: 12.23.12([email protected]([email protected]))([email protected])
|
||||
next:
|
||||
specifier: 15.5.9
|
||||
version: 15.5.9([email protected]([email protected]))([email protected])
|
||||
specifier: '>=15.5.10'
|
||||
version: 16.1.6([email protected]([email protected]))([email protected])
|
||||
ogl:
|
||||
specifier: ^1.0.11
|
||||
version: 1.0.11
|
||||
@@ -101,24 +110,28 @@ packages:
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@biomejs/[email protected]':
|
||||
resolution: {integrity: sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@biomejs/[email protected]':
|
||||
resolution: {integrity: sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@biomejs/[email protected]':
|
||||
resolution: {integrity: sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@biomejs/[email protected]':
|
||||
resolution: {integrity: sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==}
|
||||
@@ -132,127 +145,158 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@emnapi/runtime@1.5.0':
|
||||
resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==}
|
||||
'@emnapi/runtime@1.8.1':
|
||||
resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==}
|
||||
|
||||
'@img/[email protected]':
|
||||
resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==}
|
||||
'@img/[email protected]':
|
||||
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@img/[email protected]':
|
||||
resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.2.0':
|
||||
resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==}
|
||||
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected]':
|
||||
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/[email protected].0':
|
||||
resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==}
|
||||
'@img/[email protected].4':
|
||||
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.34.3':
|
||||
resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==}
|
||||
'@img/sharp-linux-riscv64@0.34.5':
|
||||
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected]':
|
||||
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@img/[email protected].3':
|
||||
resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==}
|
||||
'@img/[email protected].5':
|
||||
resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -277,53 +321,57 @@ packages:
|
||||
'@jridgewell/[email protected]':
|
||||
resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
|
||||
|
||||
'@next/env@15.5.9':
|
||||
resolution: {integrity: sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==}
|
||||
'@next/env@16.1.6':
|
||||
resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==}
|
||||
|
||||
'@next/swc-darwin-arm64@15.5.7':
|
||||
resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==}
|
||||
'@next/swc-darwin-arm64@16.1.6':
|
||||
resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-darwin-x64@15.5.7':
|
||||
resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==}
|
||||
'@next/swc-darwin-x64@16.1.6':
|
||||
resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-linux-arm64-gnu@15.5.7':
|
||||
resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==}
|
||||
'@next/swc-linux-arm64-gnu@16.1.6':
|
||||
resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-arm64-musl@15.5.7':
|
||||
resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==}
|
||||
'@next/swc-linux-arm64-musl@16.1.6':
|
||||
resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-linux-x64-gnu@15.5.7':
|
||||
resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==}
|
||||
'@next/swc-linux-x64-gnu@16.1.6':
|
||||
resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-x64-musl@15.5.7':
|
||||
resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==}
|
||||
'@next/swc-linux-x64-musl@16.1.6':
|
||||
resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-win32-arm64-msvc@15.5.7':
|
||||
resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==}
|
||||
'@next/swc-win32-arm64-msvc@16.1.6':
|
||||
resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@next/swc-win32-x64-msvc@15.5.7':
|
||||
resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==}
|
||||
'@next/swc-win32-x64-msvc@16.1.6':
|
||||
resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -369,24 +417,28 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/[email protected]':
|
||||
resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/[email protected]':
|
||||
resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/[email protected]':
|
||||
resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/[email protected]':
|
||||
resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==}
|
||||
@@ -430,6 +482,11 @@ packages:
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==}
|
||||
|
||||
@@ -450,20 +507,6 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-huuGFnDoXLy/tsCZYYa/H35BBRs9cxsS0XKJ3BXjRp699cQKuoEVrvKlAQMx0DKXG7+VUv4jsHVrS7yPbkLSkQ==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
|
||||
engines: {node: '>=12.5.0'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
@@ -471,6 +514,10 @@ packages:
|
||||
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@@ -495,9 +542,6 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
|
||||
hasBin: true
|
||||
@@ -531,24 +575,28 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
|
||||
@@ -578,15 +626,10 @@ packages:
|
||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minizlib@3.0.2:
|
||||
resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==}
|
||||
minizlib@3.1.0:
|
||||
resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==}
|
||||
|
||||
@@ -612,9 +655,9 @@ packages:
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
next@15.5.9:
|
||||
resolution: {integrity: sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==}
|
||||
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
|
||||
next@16.1.6:
|
||||
resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@opentelemetry/api': ^1.1.0
|
||||
@@ -662,18 +705,15 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
|
||||
|
||||
[email protected].2:
|
||||
resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
|
||||
[email protected].4:
|
||||
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
[email protected].3:
|
||||
resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==}
|
||||
[email protected].5:
|
||||
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -706,8 +746,8 @@ packages:
|
||||
resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tar@7.4.3:
|
||||
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
|
||||
tar@7.5.10:
|
||||
resolution: {integrity: sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
[email protected]:
|
||||
@@ -767,95 +807,106 @@ snapshots:
|
||||
'@biomejs/[email protected]':
|
||||
optional: true
|
||||
|
||||
'@emnapi/runtime@1.5.0':
|
||||
'@emnapi/runtime@1.8.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@img/[email protected]':
|
||||
'@img/[email protected]':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected]':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-arm64': 1.2.0
|
||||
'@img/sharp-libvips-darwin-arm64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].3':
|
||||
'@img/[email protected].5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-x64': 1.2.0
|
||||
'@img/sharp-libvips-darwin-x64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].0':
|
||||
'@img/[email protected].4':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].0':
|
||||
'@img/[email protected].4':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].0':
|
||||
'@img/[email protected].4':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].0':
|
||||
'@img/[email protected].4':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].0':
|
||||
'@img/[email protected].4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.2.0':
|
||||
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.2.0':
|
||||
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm[email protected].0':
|
||||
'@img/sharp-libvips-linux-x[email protected].4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x[email protected].0':
|
||||
'@img/sharp-libvips-linuxmusl-arm[email protected].4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-li[email protected]':
|
||||
'@img/sharp-li[email protected]':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected]':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm64': 1.2.0
|
||||
'@img/sharp-libvips-linux-arm64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].3':
|
||||
'@img/[email protected].5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm': 1.2.0
|
||||
'@img/sharp-libvips-linux-arm': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].3':
|
||||
'@img/[email protected].5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-ppc64': 1.2.0
|
||||
'@img/sharp-libvips-linux-ppc64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-s390x@0.34.3':
|
||||
'@img/sharp-linux-riscv64@0.34.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-s390x': 1.2.0
|
||||
'@img/sharp-libvips-linux-riscv64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-x64@0.34.3':
|
||||
'@img/sharp-linux-s390x@0.34.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-x64': 1.2.0
|
||||
'@img/sharp-libvips-linux-s390x': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-arm[email protected].3':
|
||||
'@img/sharp-linux-x[email protected].5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.2.0
|
||||
'@img/sharp-libvips-linux-x64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-x[email protected].3':
|
||||
'@img/sharp-linuxmusl-arm[email protected].5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.2.0
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-wasm32@0.34.3':
|
||||
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
|
||||
optional: true
|
||||
|
||||
'@img/[email protected]':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.5.0
|
||||
'@emnapi/runtime': 1.8.1
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].3':
|
||||
'@img/[email protected].5':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].3':
|
||||
'@img/[email protected].5':
|
||||
optional: true
|
||||
|
||||
'@img/[email protected].3':
|
||||
'@img/[email protected].5':
|
||||
optional: true
|
||||
|
||||
'@isaacs/[email protected]':
|
||||
@@ -881,30 +932,30 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@next/env@15.5.9': {}
|
||||
'@next/env@16.1.6': {}
|
||||
|
||||
'@next/swc-darwin-arm64@15.5.7':
|
||||
'@next/swc-darwin-arm64@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@next/swc-darwin-x64@15.5.7':
|
||||
'@next/swc-darwin-x64@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-gnu@15.5.7':
|
||||
'@next/swc-linux-arm64-gnu@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-musl@15.5.7':
|
||||
'@next/swc-linux-arm64-musl@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-gnu@15.5.7':
|
||||
'@next/swc-linux-x64-gnu@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-musl@15.5.7':
|
||||
'@next/swc-linux-x64-musl@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-arm64-msvc@15.5.7':
|
||||
'@next/swc-win32-arm64-msvc@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-x64-msvc@15.5.7':
|
||||
'@next/swc-win32-x64-msvc@16.1.6':
|
||||
optional: true
|
||||
|
||||
'@swc/[email protected]':
|
||||
@@ -960,7 +1011,7 @@ snapshots:
|
||||
'@tailwindcss/[email protected]':
|
||||
dependencies:
|
||||
detect-libc: 2.0.4
|
||||
tar: 7.4.3
|
||||
tar: 7.5.10
|
||||
optionalDependencies:
|
||||
'@tailwindcss/oxide-android-arm64': 4.1.12
|
||||
'@tailwindcss/oxide-darwin-arm64': 4.1.12
|
||||
@@ -995,6 +1046,8 @@ snapshots:
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
@@ -1011,30 +1064,13 @@ snapshots:
|
||||
dependencies:
|
||||
phenomenon: 1.6.0
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
optional: true
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@@ -1053,9 +1089,6 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
optional: true
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
@@ -1113,12 +1146,10 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
minizlib@3.0.2:
|
||||
minizlib@3.1.0:
|
||||
dependencies:
|
||||
minipass: 7.1.2
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
motion-utils: 12.23.6
|
||||
@@ -1135,25 +1166,26 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
next@15.5.9([email protected]([email protected]))([email protected]):
|
||||
next@16.1.6([email protected]([email protected]))([email protected]):
|
||||
dependencies:
|
||||
'@next/env': 15.5.9
|
||||
'@next/env': 16.1.6
|
||||
'@swc/helpers': 0.5.15
|
||||
baseline-browser-mapping: 2.10.0
|
||||
caniuse-lite: 1.0.30001739
|
||||
postcss: 8.4.31
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0([email protected])
|
||||
styled-jsx: 5.1.6([email protected])
|
||||
optionalDependencies:
|
||||
'@next/swc-darwin-arm64': 15.5.7
|
||||
'@next/swc-darwin-x64': 15.5.7
|
||||
'@next/swc-linux-arm64-gnu': 15.5.7
|
||||
'@next/swc-linux-arm64-musl': 15.5.7
|
||||
'@next/swc-linux-x64-gnu': 15.5.7
|
||||
'@next/swc-linux-x64-musl': 15.5.7
|
||||
'@next/swc-win32-arm64-msvc': 15.5.7
|
||||
'@next/swc-win32-x64-msvc': 15.5.7
|
||||
sharp: 0.34.3
|
||||
'@next/swc-darwin-arm64': 16.1.6
|
||||
'@next/swc-darwin-x64': 16.1.6
|
||||
'@next/swc-linux-arm64-gnu': 16.1.6
|
||||
'@next/swc-linux-arm64-musl': 16.1.6
|
||||
'@next/swc-linux-x64-gnu': 16.1.6
|
||||
'@next/swc-linux-x64-musl': 16.1.6
|
||||
'@next/swc-win32-arm64-msvc': 16.1.6
|
||||
'@next/swc-win32-x64-msvc': 16.1.6
|
||||
sharp: 0.34.5
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
@@ -1185,42 +1217,39 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected].2:
|
||||
[email protected].4:
|
||||
optional: true
|
||||
|
||||
[email protected].3:
|
||||
[email protected].5:
|
||||
dependencies:
|
||||
color: 4.2.3
|
||||
detect-libc: 2.0.4
|
||||
semver: 7.7.2
|
||||
'@img/colour': 1.1.0
|
||||
detect-libc: 2.1.2
|
||||
semver: 7.7.4
|
||||
optionalDependencies:
|
||||
'@img/sharp-darwin-arm64': 0.34.3
|
||||
'@img/sharp-darwin-x64': 0.34.3
|
||||
'@img/sharp-libvips-darwin-arm64': 1.2.0
|
||||
'@img/sharp-libvips-darwin-x64': 1.2.0
|
||||
'@img/sharp-libvips-linux-arm': 1.2.0
|
||||
'@img/sharp-libvips-linux-arm64': 1.2.0
|
||||
'@img/sharp-libvips-linux-ppc64': 1.2.0
|
||||
'@img/sharp-libvips-linux-s390x': 1.2.0
|
||||
'@img/sharp-libvips-linux-x64': 1.2.0
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.2.0
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.2.0
|
||||
'@img/sharp-linux-arm': 0.34.3
|
||||
'@img/sharp-linux-arm64': 0.34.3
|
||||
'@img/sharp-linux-ppc64': 0.34.3
|
||||
'@img/sharp-linux-s390x': 0.34.3
|
||||
'@img/sharp-linux-x64': 0.34.3
|
||||
'@img/sharp-linuxmusl-arm64': 0.34.3
|
||||
'@img/sharp-linuxmusl-x64': 0.34.3
|
||||
'@img/sharp-wasm32': 0.34.3
|
||||
'@img/sharp-win32-arm64': 0.34.3
|
||||
'@img/sharp-win32-ia32': 0.34.3
|
||||
'@img/sharp-win32-x64': 0.34.3
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
'@img/sharp-darwin-arm64': 0.34.5
|
||||
'@img/sharp-darwin-x64': 0.34.5
|
||||
'@img/sharp-libvips-darwin-arm64': 1.2.4
|
||||
'@img/sharp-libvips-darwin-x64': 1.2.4
|
||||
'@img/sharp-libvips-linux-arm': 1.2.4
|
||||
'@img/sharp-libvips-linux-arm64': 1.2.4
|
||||
'@img/sharp-libvips-linux-ppc64': 1.2.4
|
||||
'@img/sharp-libvips-linux-riscv64': 1.2.4
|
||||
'@img/sharp-libvips-linux-s390x': 1.2.4
|
||||
'@img/sharp-libvips-linux-x64': 1.2.4
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
|
||||
'@img/sharp-linux-arm': 0.34.5
|
||||
'@img/sharp-linux-arm64': 0.34.5
|
||||
'@img/sharp-linux-ppc64': 0.34.5
|
||||
'@img/sharp-linux-riscv64': 0.34.5
|
||||
'@img/sharp-linux-s390x': 0.34.5
|
||||
'@img/sharp-linux-x64': 0.34.5
|
||||
'@img/sharp-linuxmusl-arm64': 0.34.5
|
||||
'@img/sharp-linuxmusl-x64': 0.34.5
|
||||
'@img/sharp-wasm32': 0.34.5
|
||||
'@img/sharp-win32-arm64': 0.34.5
|
||||
'@img/sharp-win32-ia32': 0.34.5
|
||||
'@img/sharp-win32-x64': 0.34.5
|
||||
optional: true
|
||||
|
||||
[email protected]: {}
|
||||
@@ -1240,13 +1269,12 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
tar@7.4.3:
|
||||
tar@7.5.10:
|
||||
dependencies:
|
||||
'@isaacs/fs-minipass': 4.0.1
|
||||
chownr: 3.0.0
|
||||
minipass: 7.1.2
|
||||
minizlib: 3.0.2
|
||||
mkdirp: 3.0.1
|
||||
minizlib: 3.1.0
|
||||
yallist: 5.0.0
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
+10
-1
@@ -1,6 +1,15 @@
|
||||
packages:
|
||||
- '.'
|
||||
- .
|
||||
|
||||
onlyBuiltDependencies:
|
||||
- '@tailwindcss/oxide'
|
||||
- sharp
|
||||
|
||||
overrides:
|
||||
next@>=10.0.0 <15.5.10: '>=15.5.10'
|
||||
next@>=15.5.1-canary.0 <15.5.10: '>=15.5.10'
|
||||
tar@<7.5.7: '>=7.5.7'
|
||||
tar@<7.5.8: '>=7.5.8'
|
||||
tar@<=7.5.2: '>=7.5.3'
|
||||
tar@<=7.5.3: '>=7.5.4'
|
||||
tar@<=7.5.9: '>=7.5.10'
|
||||
+64
-1
@@ -18,7 +18,65 @@ module.exports = {
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
"blue-primary": "#4facfe", // Cor azul personalizada
|
||||
// Primary colors
|
||||
ink: {
|
||||
DEFAULT: "#0A0A0A",
|
||||
80: "rgba(10,10,10,.8)",
|
||||
40: "rgba(10,10,10,.4)",
|
||||
12: "rgba(10,10,10,.12)",
|
||||
6: "rgba(10,10,10,.06)",
|
||||
},
|
||||
paper: {
|
||||
DEFAULT: "#F4F2ED",
|
||||
dark: "#ECEAE4",
|
||||
},
|
||||
white: "#FFFFFF",
|
||||
|
||||
// Accent
|
||||
slash: {
|
||||
DEFAULT: "#E8FF00",
|
||||
dim: "rgba(232,255,0,.15)",
|
||||
},
|
||||
|
||||
// Neutrals
|
||||
meta: "#777",
|
||||
border: "rgba(10,10,10,.1)",
|
||||
"border-light": "rgba(10,10,10,.06)",
|
||||
},
|
||||
fontFamily: {
|
||||
display: ["Syne", "sans-serif"],
|
||||
mono: ["Geist Mono", "monospace"],
|
||||
},
|
||||
fontSize: {
|
||||
"ds-xs": ["9px", { lineHeight: "1.4", letterSpacing: "0.14em" }],
|
||||
"ds-sm": ["10px", { lineHeight: "1.5", letterSpacing: "0.12em" }],
|
||||
"ds-base": ["11px", { lineHeight: "1.6" }],
|
||||
"ds-md": ["12px", { lineHeight: "1.7" }],
|
||||
"ds-lg": ["13px", { lineHeight: "1.6" }],
|
||||
},
|
||||
spacing: {
|
||||
"sp-1": "4px",
|
||||
"sp-2": "8px",
|
||||
"sp-3": "12px",
|
||||
"sp-4": "16px",
|
||||
"sp-5": "20px",
|
||||
"sp-6": "24px",
|
||||
"sp-8": "32px",
|
||||
"sp-10": "40px",
|
||||
"sp-12": "48px",
|
||||
"sp-16": "64px",
|
||||
"sp-20": "80px",
|
||||
"sp-24": "96px",
|
||||
},
|
||||
borderRadius: {
|
||||
"r-sm": "4px",
|
||||
"r-md": "8px",
|
||||
"r-lg": "16px",
|
||||
"r-full": "999px",
|
||||
},
|
||||
transitionTimingFunction: {
|
||||
"ease-out": "cubic-bezier(.16,1,.3,1)",
|
||||
"ease-in": "cubic-bezier(.4,0,1,1)",
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
@@ -29,10 +87,15 @@ module.exports = {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: "0" },
|
||||
},
|
||||
pulse: {
|
||||
"0%, 100%": { opacity: "1", transform: "scale(1)" },
|
||||
"50%": { opacity: "0.5", transform: "scale(0.75)" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
pulse: "pulse 2s ease-in-out infinite",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
+19
-5
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
@@ -11,7 +15,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
@@ -19,9 +23,19 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user