feat(about): add story sections and core values to About component
Enhance the About page with new story sections detailing personal journey and core values, including icons and structured content for better user engagement and self-presentation.
This commit is contained in:
1 parent
367ca8f495
commit
6ec67c8f5a
11 files changed
+1540
-464
No files matched your search
+270
-68
@@ -1,8 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "motion/react";
|
||||
import { BentoGrid, BentoGridItem } from "@/components/magicui/bento-grid";
|
||||
import { Calendar, MapPin, Briefcase } from "lucide-react";
|
||||
import {
|
||||
Calendar,
|
||||
MapPin,
|
||||
Briefcase,
|
||||
Zap,
|
||||
TrendingUp,
|
||||
Users,
|
||||
Award,
|
||||
ExternalLink,
|
||||
} from "lucide-react";
|
||||
import { usePortfolioData } from "@/lib/usePortfolioData";
|
||||
|
||||
export default function Experience() {
|
||||
@@ -11,7 +19,7 @@ export default function Experience() {
|
||||
if (loading) {
|
||||
return (
|
||||
<section id="experience" className="py-20 px-4">
|
||||
<div className="max-w-6xl mx-auto text-center">
|
||||
<div className="max-w-7xl mx-auto text-center">
|
||||
<div className="animate-pulse">
|
||||
<div className="h-8 bg-gray-700 rounded w-1/3 mx-auto mb-4"></div>
|
||||
<div className="h-4 bg-gray-700 rounded w-1/2 mx-auto"></div>
|
||||
@@ -24,99 +32,293 @@ export default function Experience() {
|
||||
if (error || !data) {
|
||||
return (
|
||||
<section id="experience" className="py-20 px-4">
|
||||
<div className="max-w-6xl mx-auto text-center">
|
||||
<div className="max-w-7xl mx-auto text-center">
|
||||
<p className="text-red-400">Erro ao carregar dados de experiência.</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
const experiences = data.experiences.filter((exp) => exp.featured);
|
||||
const experiences = data.experiences
|
||||
.filter((exp) => exp.featured)
|
||||
.sort((a, b) => {
|
||||
// Extrair ano de início de cada experiência
|
||||
const getStartYear = (period: string) => {
|
||||
const yearMatch = period.match(/(\d{4})/);
|
||||
return yearMatch ? parseInt(yearMatch[1]) : 0;
|
||||
};
|
||||
|
||||
const yearA = getStartYear(a.period);
|
||||
const yearB = getStartYear(b.period);
|
||||
|
||||
// Ordenar da mais antiga para a mais nova
|
||||
return yearA - yearB;
|
||||
});
|
||||
|
||||
// Configuração de cores por empresa/tipo
|
||||
const experienceConfig = {
|
||||
"innovo-tecnologia": {
|
||||
color: "from-blue-500 to-cyan-600",
|
||||
bgColor: "bg-blue-500/10",
|
||||
borderColor: "border-blue-500/20",
|
||||
iconColor: "text-blue-400",
|
||||
accent: "blue",
|
||||
},
|
||||
"apolo-energia": {
|
||||
color: "from-green-500 to-emerald-600",
|
||||
bgColor: "bg-green-500/10",
|
||||
borderColor: "border-green-500/20",
|
||||
iconColor: "text-green-400",
|
||||
accent: "green",
|
||||
},
|
||||
};
|
||||
|
||||
const getExperienceConfig = (company: string) => {
|
||||
const key = company
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/[^a-z0-9-]/g, "");
|
||||
return (
|
||||
experienceConfig[key as keyof typeof experienceConfig] ||
|
||||
experienceConfig["innovo-tecnologia"]
|
||||
);
|
||||
};
|
||||
|
||||
const formatDuration = (period: string) => {
|
||||
// Extrair meses da string de período (ex: "3 meses")
|
||||
const monthsMatch = period.match(/(\d+)\s*meses?/i);
|
||||
if (monthsMatch) {
|
||||
const months = parseInt(monthsMatch[1]);
|
||||
if (months < 12) {
|
||||
return `${months} ${months === 1 ? "mês" : "meses"}`;
|
||||
} else {
|
||||
const years = Math.floor(months / 12);
|
||||
const remainingMonths = months % 12;
|
||||
if (remainingMonths === 0) {
|
||||
return `${years} ${years === 1 ? "ano" : "anos"}`;
|
||||
} else {
|
||||
return `${years} ${
|
||||
years === 1 ? "ano" : "anos"
|
||||
} e ${remainingMonths} ${remainingMonths === 1 ? "mês" : "meses"}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extrair anos da string de período (ex: "3 anos 5 meses")
|
||||
const yearsMatch = period.match(/(\d+)\s*anos?/i);
|
||||
if (yearsMatch) {
|
||||
const years = parseInt(yearsMatch[1]);
|
||||
return `${years}+ ${years === 1 ? "ano" : "anos"}`;
|
||||
}
|
||||
|
||||
return "Experiência relevante";
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
id="experience"
|
||||
className="py-20 px-4 bg-gradient-to-b from-transparent to-black/20 mx-auto"
|
||||
>
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<section id="experience" className="py-20 px-4 relative">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
viewport={{ once: true }}
|
||||
className="text-center mb-16"
|
||||
className="text-center mb-20"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-6">
|
||||
<div className="inline-flex items-center gap-2 bg-gradient-to-r from-cyan-400/10 to-blue-500/10 px-6 py-3 rounded-full mb-6 border border-cyan-400/20">
|
||||
<div className="w-2 h-2 bg-cyan-400 rounded-full animate-pulse"></div>
|
||||
<span className="text-sm font-medium text-cyan-300">
|
||||
Jornada Profissional
|
||||
</span>
|
||||
</div>
|
||||
<h2 className="text-4xl md:text-5xl lg:text-6xl font-bold mb-6 bg-gradient-to-r from-cyan-400 to-blue-500 bg-clip-text text-transparent">
|
||||
Experiência Profissional
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||
Minha jornada profissional em desenvolvimento de software e soluções
|
||||
tecnológicas
|
||||
<p className="text-xl text-gray-300 max-w-3xl mx-auto leading-relaxed">
|
||||
Uma trajetória de crescimento técnico e impacto real, onde cada
|
||||
projeto representou um novo nível de desafio e aprendizado
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<BentoGrid className="gap-6">
|
||||
{experiences.map((exp, index) => (
|
||||
<BentoGridItem
|
||||
key={exp.id}
|
||||
colSpan={index === 0 ? 2 : 1}
|
||||
className="group hover:scale-[1.02] transition-all duration-300 hover:shadow-2xl hover:shadow-blue-500/10"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-semibold text-white mb-1">
|
||||
{exp.title}
|
||||
</h3>
|
||||
<p className="text-blue-400 font-medium">{exp.company}</p>
|
||||
<div className="flex flex-wrap items-center gap-2 text-sm text-gray-400 mt-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<Calendar className="w-4 h-4" />
|
||||
{exp.period}
|
||||
{/* Experience Cards Grid */}
|
||||
<div className="grid lg:grid-cols-2 gap-8">
|
||||
{experiences.map((exp, index) => {
|
||||
const config = getExperienceConfig(exp.company);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={exp.id}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: index * 0.2 }}
|
||||
viewport={{ once: true }}
|
||||
className="relative"
|
||||
>
|
||||
{/* Content Card */}
|
||||
<div className="h-full">
|
||||
<div className="relative group">
|
||||
{/* Background Glow */}
|
||||
<div
|
||||
className={`absolute inset-0 bg-gradient-to-r ${config.color} opacity-10 rounded-2xl blur-xl group-hover:opacity-20 transition-opacity duration-500`}
|
||||
></div>
|
||||
|
||||
{/* Main Card */}
|
||||
<div className="relative bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-8 hover:border-cyan-500/30 transition-all duration-300 hover:scale-105">
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between mb-6">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className={`p-3 rounded-xl ${config.bgColor}`}>
|
||||
<Briefcase
|
||||
className={`w-6 h-6 ${config.iconColor}`}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-white mb-1">
|
||||
{exp.title}
|
||||
</h3>
|
||||
<p
|
||||
className={`text-lg font-semibold ${config.iconColor}`}
|
||||
>
|
||||
{exp.company}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Meta Info */}
|
||||
<div className="flex flex-wrap gap-4 text-sm text-gray-400 mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Calendar className="w-4 h-4" />
|
||||
<span>{exp.period}</span>
|
||||
</div>
|
||||
{exp.location && (
|
||||
<div className="flex items-center gap-2">
|
||||
<MapPin className="w-4 h-4" />
|
||||
<span>{exp.location}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<Users className="w-4 h-4" />
|
||||
<span>{exp.type}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Duration Badge */}
|
||||
<div
|
||||
className={`px-4 py-2 rounded-full ${config.bgColor} border ${config.borderColor}`}
|
||||
>
|
||||
<span
|
||||
className={`text-sm font-bold ${config.iconColor}`}
|
||||
>
|
||||
{formatDuration(exp.period)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{exp.location && (
|
||||
<div className="flex items-center gap-1">
|
||||
<MapPin className="w-4 h-4" />
|
||||
{exp.location}
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-gray-300 leading-relaxed mb-6 text-lg">
|
||||
{exp.description}
|
||||
</p>
|
||||
|
||||
{/* Achievements */}
|
||||
{exp.achievements && exp.achievements.length > 0 && (
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-semibold text-gray-400 mb-4 uppercase tracking-wide flex items-center gap-2">
|
||||
<Award className="w-4 h-4 text-yellow-400" />
|
||||
Principais Conquistas
|
||||
</h4>
|
||||
<div className="grid gap-3">
|
||||
{exp.achievements.map((achievement, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="flex items-start gap-3 p-3 rounded-lg bg-white/5 border border-white/5 hover:border-blue-500/20 transition-colors"
|
||||
>
|
||||
<div className="w-2 h-2 bg-gradient-to-r from-blue-400 to-purple-400 rounded-full mt-2 flex-shrink-0"></div>
|
||||
<span className="text-gray-300 text-sm leading-relaxed">
|
||||
{achievement}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Technologies */}
|
||||
{exp.technologies && exp.technologies.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-sm font-semibold text-gray-400 mb-3 uppercase tracking-wide flex items-center gap-2">
|
||||
<Zap className="w-4 h-4 text-orange-400" />
|
||||
Stack Tecnológica
|
||||
</h4>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{exp.technologies.slice(0, 6).map((tech) => (
|
||||
<span
|
||||
key={tech}
|
||||
className="px-3 py-1 bg-gray-800/50 text-gray-300 text-xs rounded-full border border-gray-700/50 hover:border-blue-500/30 transition-colors"
|
||||
>
|
||||
{tech}
|
||||
</span>
|
||||
))}
|
||||
{exp.technologies.length > 6 && (
|
||||
<span className="px-3 py-1 bg-gray-800/30 text-gray-500 text-xs rounded-full">
|
||||
+{exp.technologies.length - 6}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-1">
|
||||
<Briefcase className="w-4 h-4" />
|
||||
{exp.type}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-gray-300 leading-relaxed">
|
||||
{exp.description}
|
||||
</p>
|
||||
|
||||
{/* Achievements */}
|
||||
{exp.achievements.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-sm font-semibold text-blue-400 mb-2">
|
||||
Principais Conquistas:
|
||||
</h4>
|
||||
<ul className="space-y-1">
|
||||
{exp.achievements.map((achievement, idx) => (
|
||||
<li
|
||||
key={idx}
|
||||
className="text-sm text-gray-400 flex items-center gap-2"
|
||||
>
|
||||
<div className="w-1.5 h-1.5 bg-blue-400 rounded-full" />
|
||||
{achievement}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{/* Summary Stats */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: 0.6 }}
|
||||
viewport={{ once: true }}
|
||||
className="mt-20"
|
||||
>
|
||||
<div className="relative max-w-4xl mx-auto">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/10 via-purple-500/10 to-green-500/10 rounded-2xl blur-xl"></div>
|
||||
<div className="relative bg-gradient-to-r from-blue-500/5 to-green-500/5 border border-blue-500/20 rounded-2xl p-8 backdrop-blur-sm">
|
||||
<h4 className="text-2xl font-bold text-white mb-6 text-center">
|
||||
Impacto e Crescimento
|
||||
</h4>
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold text-blue-400 mb-2">
|
||||
3+
|
||||
</div>
|
||||
)}
|
||||
<div className="text-gray-400 text-sm">
|
||||
Anos de Experiência
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold text-purple-400 mb-2">
|
||||
2
|
||||
</div>
|
||||
<div className="text-gray-400 text-sm">
|
||||
Empresas Diferentes
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold text-green-400 mb-2">
|
||||
10+
|
||||
</div>
|
||||
<div className="text-gray-400 text-sm">
|
||||
Tecnologias Dominadas
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BentoGridItem>
|
||||
))}
|
||||
</BentoGrid>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user