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:
Evandro Fonseca Junior committed 2025-10-11 18:25:41 -03:00
1 parent 367ca8f495
commit 6ec67c8f5a
11 files changed
+1540 -464

No files matched your search

+239 -72
View File
@@ -2,16 +2,100 @@
import { motion } from "motion/react";
import { BentoGrid, BentoGridItem } from "@/components/magicui/bento-grid";
import { ExternalLink, Github } from "lucide-react";
import {
ExternalLink,
Github,
Star,
Zap,
Globe,
Cpu,
Code2,
} from "lucide-react";
import { usePortfolioData } from "@/lib/usePortfolioData";
// Configuração de cores e ícones por categoria
const categoryConfig = {
"full-stack": {
color: "from-blue-500 to-blue-600",
bgColor: "bg-blue-500/10",
borderColor: "border-blue-500/20",
icon: Globe,
iconColor: "text-blue-400",
},
iot: {
color: "from-purple-500 to-purple-600",
bgColor: "bg-purple-500/10",
borderColor: "border-purple-500/20",
icon: Cpu,
iconColor: "text-purple-400",
},
api: {
color: "from-orange-500 to-orange-600",
bgColor: "bg-orange-500/10",
borderColor: "border-orange-500/20",
icon: Code2,
iconColor: "text-orange-400",
},
web: {
color: "from-green-500 to-green-600",
bgColor: "bg-green-500/10",
borderColor: "border-green-500/20",
icon: Globe,
iconColor: "text-green-400",
},
desktop: {
color: "from-emerald-500 to-emerald-600",
bgColor: "bg-emerald-500/10",
borderColor: "border-emerald-500/20",
icon: Code2,
iconColor: "text-emerald-400",
},
};
// Função para gerar estrelas de complexidade
const ComplexityStars = ({ complexity }: { complexity: number }) => {
return (
<div className="flex items-center gap-1">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className={`w-3 h-3 ${
i < complexity ? "text-yellow-400 fill-yellow-400" : "text-gray-600"
}`}
/>
))}
</div>
);
};
// Componente de Badge
const ProjectBadge = ({ badge, index }: { badge: string; index: number }) => {
const badgeColors = [
"bg-blue-500/20 text-blue-400 border-blue-500/30",
"bg-green-500/20 text-green-400 border-green-500/30",
"bg-purple-500/20 text-purple-400 border-purple-500/30",
"bg-orange-500/20 text-orange-400 border-orange-500/30",
"bg-red-500/20 text-red-400 border-red-500/30",
];
return (
<span
className={`px-2 py-1 text-xs font-medium rounded-full border ${
badgeColors[index % badgeColors.length]
}`}
>
{badge}
</span>
);
};
export default function Projects() {
const { data, loading, error } = usePortfolioData();
if (loading) {
return (
<section id="projects" 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,7 +108,7 @@ export default function Projects() {
if (error || !data) {
return (
<section id="projects" 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 projetos.</p>
</div>
</section>
@@ -35,7 +119,7 @@ export default function Projects() {
return (
<section id="projects" className="py-20 px-4 mx-auto">
<div className="max-w-6xl mx-auto">
<div className="max-w-7xl mx-auto">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
@@ -43,91 +127,174 @@ export default function Projects() {
viewport={{ once: true }}
className="text-center mb-16"
>
<h2 className="text-4xl md:text-5xl font-bold mb-6">
<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">
Projetos em Destaque
</h2>
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
Alguns dos projetos que desenvolvi, demonstrando minhas habilidades
e paixão por tecnologia
<p className="text-xl text-gray-300 max-w-3xl mx-auto">
Uma seleção dos projetos que desenvolvi, demonstrando minha evolução
técnica e capacidade de entregar soluções completas em diferentes
domínios
</p>
</motion.div>
<BentoGrid className="gap-6">
{projects.map((project, index) => (
<BentoGridItem
key={project.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-2">
{project.title}
</h3>
<div className="flex flex-wrap gap-2 mb-3">
{project.technologies.map((tech) => (
{projects.map((project, index) => {
const config =
categoryConfig[project.category as keyof typeof categoryConfig] ||
categoryConfig["web"];
const IconComponent = config.icon;
return (
<BentoGridItem
key={project.id}
colSpan={index <= 1 ? 2 : 1} // NutriScan e Twins Lab em destaque
className={`group hover:scale-105 transition-all duration-300 hover:shadow-2xl ${config.borderColor} border-2 bg-white/5 backdrop-blur-sm`}
>
<motion.div
className="space-y-5 h-full"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: index * 0.1 }}
viewport={{ once: true }}
>
{/* Header com ícone e badges */}
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className={`p-3 rounded-xl ${config.bgColor}`}>
<IconComponent
className={`w-6 h-6 ${config.iconColor}`}
/>
</div>
<div>
<h3 className="text-xl font-bold text-white mb-1">
{project.title}
</h3>
<p className="text-sm text-gray-400 font-medium">
{project.subtitle}
</p>
</div>
</div>
<div className="flex gap-2">
{project.demoUrl && (
<a
href={project.demoUrl}
target="_blank"
rel="noopener noreferrer"
className="p-2 rounded-lg bg-green-500/20 text-green-400 hover:bg-green-500/30 transition-all duration-300 hover:scale-110"
aria-label="Ver demo"
>
<ExternalLink className="w-4 h-4" />
</a>
)}
{project.githubUrl && (
<a
href={project.githubUrl}
target="_blank"
rel="noopener noreferrer"
className="p-2 rounded-lg bg-gray-500/20 text-gray-400 hover:bg-gray-500/30 transition-all duration-300 hover:scale-110"
aria-label="Ver código"
>
<Github className="w-4 h-4" />
</a>
)}
</div>
</div>
{/* Badges */}
<div className="flex flex-wrap gap-2">
{project.badges.map((badge, idx) => (
<ProjectBadge key={badge} badge={badge} index={idx} />
))}
</div>
{/* Description */}
<p className="text-gray-300 leading-relaxed text-sm">
{project.description}
</p>
{/* Tecnologias principais */}
<div>
<h4 className="text-xs font-semibold text-gray-400 mb-2 uppercase tracking-wide">
Stack Principal
</h4>
<div className="flex flex-wrap gap-1">
{project.technologies.slice(0, 4).map((tech) => (
<span
key={tech}
className="px-2 py-1 bg-blue-500/20 text-blue-400 text-xs rounded-full border border-blue-500/30"
className="px-2 py-1 bg-gray-800/50 text-gray-300 text-xs rounded border border-gray-700/50"
>
{tech}
</span>
))}
{project.technologies.length > 4 && (
<span className="px-2 py-1 bg-gray-800/30 text-gray-500 text-xs rounded">
+{project.technologies.length - 4}
</span>
)}
</div>
</div>
<div className="flex gap-2">
<a
href={project.demoUrl}
className="p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
aria-label="Ver demo"
>
<ExternalLink className="w-4 h-4" />
</a>
<a
href={project.githubUrl}
className="p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
aria-label="Ver código"
>
<Github className="w-4 h-4" />
</a>
{/* Features principais */}
<div>
<h4 className="text-xs font-semibold text-gray-400 mb-2 uppercase tracking-wide">
Destaques
</h4>
<ul className="space-y-1">
{project.features.slice(0, 3).map((feature, idx) => (
<li
key={idx}
className="text-xs text-gray-400 flex items-start gap-2"
>
<Zap className="w-3 h-3 text-yellow-400 mt-0.5 flex-shrink-0" />
<span>{feature}</span>
</li>
))}
</ul>
</div>
</div>
{/* Description */}
<p className="text-gray-300 leading-relaxed">
{project.description}
</p>
{/* Features */}
<div>
<h4 className="text-sm font-semibold text-blue-400 mb-2">
Funcionalidades:
</h4>
<ul className="space-y-1">
{project.features.map((feature, 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" />
{feature}
</li>
))}
</ul>
</div>
{/* Status */}
<div className="pt-2 border-t border-white/10">
<span className="text-xs text-blue-400 font-medium">
{project.status}
</span>
</div>
</div>
</BentoGridItem>
))}
{/* Footer com complexidade e status */}
<div className="pt-4 border-t border-white/10 flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="text-xs text-gray-500">
Complexidade:
</span>
<ComplexityStars
complexity={project.metrics?.complexity || 3}
/>
</div>
<span
className={`text-xs font-medium px-2 py-1 rounded-full ${
project.status === "Em Produção"
? "bg-green-500/20 text-green-400 border border-green-500/30"
: "bg-blue-500/20 text-blue-400 border border-blue-500/30"
}`}
>
{project.status}
</span>
</div>
</motion.div>
</BentoGridItem>
);
})}
</BentoGrid>
{/* Call to Action */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.5 }}
viewport={{ once: true }}
className="text-center mt-16"
>
<div className="inline-flex items-center gap-2 bg-gradient-to-r from-blue-500/10 to-purple-500/10 px-6 py-3 rounded-full border border-blue-500/20">
<div className="w-2 h-2 bg-blue-400 rounded-full animate-pulse"></div>
<span className="text-sm text-blue-300 font-medium">
Todos os projetos são desenvolvidos individualmente, demonstrando
capacidade full-stack completa
</span>
</div>
</motion.div>
</div>
</section>
);