feat: set up basic project structure and initial styling
This commit initializes the project with a basic Next.js setup, including: - Integration of `tailwindcss` and `tw-animate-css` for styling. - Definition of a comprehensive color palette using CSS variables for both light and dark themes, supporting a theming system. - Implementation of a custom `aurora` keyframe animation. - Configuration of global CSS styles for `border` and `body` elements. - Setup of `next.config.ts` with image optimization, performance enhancements, and security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy). - Update of `package.json` to include new dependencies for UI components (`class-variance-authority`, `clsx`, `lucide-react`, `motion`, `tailwind-merge`, `tailwindcss-animate`) and development tools (`@biomejs/biome`, `@tailwindcss/postcss`, `tw-animate-css`). - Refinement of `app/layout.tsx` to include comprehensive metadata for SEO (title, description, keywords, authors, Open Graph, Twitter cards, robots), preconnect/dns-prefetch links for external resources, favicon, manifest, and mobile app meta tags. - Restructuring of `app/page.tsx` to use dynamic imports for various sections (Hero, About, Skills, Experience, Projects, Contact, WorkModalities) to improve performance, and integration of `Squares` component for background effects. This foundational commit prepares the application for further development by establishing a robust and performant base.
This commit is contained in:
1 parent
ca9e70a53e
commit
90cf3c73ad
37 files changed
+3898
-118
No files matched your search
@@ -0,0 +1,135 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "motion/react";
|
||||
import { MagicCard } from "@/components/magicui/magic-card";
|
||||
import {
|
||||
Code,
|
||||
Database,
|
||||
Cloud,
|
||||
Cpu,
|
||||
Smartphone,
|
||||
Zap,
|
||||
GitBranch,
|
||||
TestTube,
|
||||
} from "lucide-react";
|
||||
import { usePortfolioData } from "@/lib/usePortfolioData";
|
||||
|
||||
// Mapa de ícones para as categorias
|
||||
const iconMap = {
|
||||
Code: Code,
|
||||
Database: Database,
|
||||
Cloud: Cloud,
|
||||
Cpu: Cpu,
|
||||
Smartphone: Smartphone,
|
||||
Zap: Zap,
|
||||
GitBranch: GitBranch,
|
||||
TestTube: TestTube,
|
||||
};
|
||||
|
||||
// Mapa de cores para garantir que o Tailwind inclua as classes no bundle
|
||||
const colorMap = {
|
||||
"text-blue-440": "bg-blue-400",
|
||||
"text-blue-400": "bg-blue-400",
|
||||
"text-green-400": "bg-blue-400",
|
||||
"text-purple-400": "bg-blue-400",
|
||||
"text-red-400": "bg-blue-400",
|
||||
"text-yellow-400": "bg-blue-400",
|
||||
"text-pink-400": "bg-blue-400",
|
||||
"text-indigo-400": "bg-blue-400",
|
||||
};
|
||||
|
||||
export default function Skills() {
|
||||
const { data, loading, error } = usePortfolioData();
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<section id="skills" className="py-20 px-4">
|
||||
<div className="max-w-6xl 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>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !data) {
|
||||
return (
|
||||
<section id="skills" className="py-20 px-4">
|
||||
<div className="max-w-6xl mx-auto text-center">
|
||||
<p className="text-red-400">Erro ao carregar dados de habilidades.</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
const skillCategories = data.skills.technical;
|
||||
|
||||
return (
|
||||
<section id="skills" className="py-20 px-4">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
viewport={{ once: true }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-6">
|
||||
Habilidades Técnicas
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||
Tecnologias e ferramentas que utilizo para criar soluções inovadoras
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{skillCategories.map((category, index) => {
|
||||
const IconComponent =
|
||||
iconMap[category.icon as keyof typeof iconMap] || Code;
|
||||
return (
|
||||
<motion.div
|
||||
key={category.category}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: index * 0.1 }}
|
||||
viewport={{ once: true }}
|
||||
>
|
||||
<div className="p-6 space-y-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`p-3 rounded-lg ${category.bgColor}`}>
|
||||
<IconComponent className={`w-6 h-6 ${category.color}`} />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold">
|
||||
{category.category}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
{/* Skills List */}
|
||||
<div className="space-y-2">
|
||||
{category.skills.map((skill, skillIndex) => (
|
||||
<div
|
||||
key={skillIndex}
|
||||
className="flex items-center gap-2 text-gray-300"
|
||||
>
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
colorMap[category.color as keyof typeof colorMap] ||
|
||||
"bg-gray-400"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-sm">{skill}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user