feat: add hero section and navigation components
Deploy Portfolio Selfmade / deploy (push) Successful in 31s

- Created HeroSection component for the landing page.
- Implemented Navigation component with smooth scrolling to sections.
- Added useNavigation hook to manage active section and scroll state.
- Introduced useScrollToSection hook for smooth scrolling functionality.

feat: add projects section with project cards

- Developed ProjectCard component to display individual project details.
- Created ProjectsSection component to showcase featured projects with filtering options.
- Added sample project data for demonstration.

feat: add skills section with skill cards

- Implemented SkillCard component to display individual skills.
- Created SkillsSection component to showcase skills with category filtering.
- Added sample skills data for demonstration.

style: update global styles and add custom scrollbar

- Imported Urbanist font and set it as the default font.
- Updated body background and text colors.
- Customized scrollbar styles for better aesthetics.

feat: add shared components and constants

- Created AnimatedSection, Button, and Footer components for reusability.
- Added COLORS and GRADIENT constants for consistent theming.
- Updated index files for shared components and hooks.

chore: update dependencies and configuration

- Added framer-motion for animations.
- Updated Tailwind CSS configuration for custom animations and colors.
- Adjusted TypeScript configuration for better path resolution.
This commit is contained in:
2026-05-10 14:34:54 +02:00
parent e85ce6a67b
commit 4ff07915b8
56 changed files with 1602 additions and 16 deletions
@@ -0,0 +1,87 @@
import React from 'react';
import { motion } from 'framer-motion';
import { ExternalLink } from 'lucide-react';
import { FaGithub } from 'react-icons/fa';
import type { Project } from '../../../shared/types';
interface ProjectCardProps {
project: Project;
index: number;
}
export const ProjectCard: React.FC<ProjectCardProps> = ({ project, index }) => {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
whileHover={{ y: -10 }}
className="group rounded-xl overflow-hidden border border-green-500/30 bg-gradient-to-br from-green-500/5 to-emerald-500/5 backdrop-blur-sm hover:border-green-500/60 transition-all duration-300"
>
{/* Image */}
<div className="relative h-64 overflow-hidden bg-gradient-to-br from-gray-900 to-black">
<img
src={project.image}
alt={project.title}
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 to-transparent"></div>
</div>
{/* Content */}
<div className="p-6">
{/* Category Badge */}
<div className="inline-block mb-4 px-3 py-1 rounded-full bg-green-500/20 border border-green-500/50">
<span className="text-green-400 text-xs font-semibold">{project.category}</span>
</div>
<h3 className="text-xl font-bold text-white mb-2">{project.title}</h3>
<p className="text-gray-400 text-sm mb-4 line-clamp-2">{project.description}</p>
{/* Tags */}
<div className="flex flex-wrap gap-2 mb-6">
{project.tags.slice(0, 3).map((tag) => (
<span
key={tag}
className="text-xs px-2 py-1 rounded border border-green-500/30 text-green-400"
>
{tag}
</span>
))}
{project.tags.length > 3 && (
<span className="text-xs px-2 py-1 text-gray-500">
+{project.tags.length - 3}
</span>
)}
</div>
{/* Links */}
<div className="flex gap-3">
{project.link && (
<motion.a
href={project.link}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
className="flex items-center gap-2 px-4 py-2 rounded-lg bg-green-500/20 hover:bg-green-500/30 text-green-400 transition-colors text-sm font-medium"
>
<ExternalLink size={16} />
Live
</motion.a>
)}
{project.github && (
<motion.a
href={project.github}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
className="flex items-center gap-2 px-4 py-2 rounded-lg border border-green-500/30 hover:border-green-500/60 text-gray-300 hover:text-white transition-colors text-sm font-medium"
>
<FaGithub size={16} />
Code
</motion.a>
)}
</div>
</div>
</motion.div>
);
};
@@ -0,0 +1,79 @@
import React, { useState } from 'react';
import { motion } from 'framer-motion';
import { projectsData } from '../data/projectsData';
import { ProjectCard } from './ProjectCard';
import AnimatedSection from '../../../shared/components/AnimatedSection';
import type { Project } from '../../../shared/types';
type Category = 'All' | 'Web Apps' | 'UI Components' | 'Full Stack';
export const ProjectsSection: React.FC = () => {
const [selectedCategory, setSelectedCategory] = useState<Category>('All');
const categories: Category[] = ['All', 'Web Apps', 'UI Components', 'Full Stack'];
const filteredProjects = projectsData.filter(
(project: Project) =>
selectedCategory === 'All' || project.category === selectedCategory
);
return (
<AnimatedSection id="projects" className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-7xl mx-auto">
{/* Section Header */}
<div className="text-center mb-16">
<motion.div
initial={{ opacity: 0, y: -20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="inline-block px-4 py-2 rounded-full border border-green-500/50 bg-green-500/10 mb-6"
>
<span className="text-green-400 text-sm font-medium">My Work</span>
</motion.div>
<h2 className="text-4xl sm:text-5xl font-bold text-white mb-4">
Featured Projects
</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
Showcasing my best work and achievements
</p>
</div>
{/* Category Filter */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="flex flex-wrap justify-center gap-3 mb-12"
>
{categories.map((category) => (
<motion.button
key={category}
onClick={() => setSelectedCategory(category)}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className={`px-6 py-2 rounded-full font-medium transition-all duration-300 ${
selectedCategory === category
? 'bg-green-500 text-black'
: 'border border-green-500/30 text-gray-300 hover:border-green-500/60'
}`}
>
{category}
</motion.button>
))}
</motion.div>
{/* Projects Grid */}
<motion.div
layout
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
>
{filteredProjects.map((project: Project, index: number) => (
<ProjectCard key={project.id} project={project} index={index} />
))}
</motion.div>
</div>
</AnimatedSection>
);
};
@@ -0,0 +1,37 @@
import type { Project } from '../../../shared/types';
export const projectsData: Project[] = [
{
id: '1',
title: 'E-Commerce Platform',
description:
'Full-stack e-commerce platform with product catalog, shopping cart, and payment integration using Stripe',
image: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=800&h=600&fit=crop',
tags: ['React', 'Next.js', 'TypeScript', 'Tailwind CSS', 'MongoDB'],
category: 'Full Stack',
link: '#',
github: '#',
},
{
id: '2',
title: 'Task Management Dashboard',
description:
'A collaborative task management application with real-time updates, user authentication, and advanced filtering',
image: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=800&h=600&fit=crop',
tags: ['React', 'Firebase', 'TypeScript', 'Tailwind CSS'],
category: 'Web Apps',
link: '#',
github: '#',
},
{
id: '3',
title: 'Component Library',
description:
'A comprehensive reusable component library with Storybook documentation and design system tokens',
image: 'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=800&h=600&fit=crop',
tags: ['React', 'Storybook', 'Tailwind CSS', 'TypeScript'],
category: 'UI Components',
link: '#',
github: '#',
},
];
+1
View File
@@ -0,0 +1 @@
export { ProjectsSection } from './components/ProjectsSection';