Initial commit: Portfolio Website
Vollständige Next.js 15 Portfolio-Website mit: - Blog-System mit 100+ Artikeln - Supabase-Integration - Responsive Design mit Tailwind CSS - TypeScript-Konfiguration - Testing-Setup mit Vitest und Playwright Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import { getTranslations, getLocale } from 'next-intl/server';
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { Calendar, Tag, ExternalLink } from 'lucide-react';
|
||||
|
||||
// Project data embedded directly for SSG
|
||||
const projectsData = [
|
||||
{
|
||||
slug: 'ai-data-reader',
|
||||
title: 'AI Document Reader',
|
||||
excerpt: 'KI-gestützte Dokumentenanalyse mit OLLAMA und Python',
|
||||
date: '2024-01',
|
||||
technologies: ['Python', 'OLLAMA', 'FastAPI', 'React'],
|
||||
category: 'AI Development',
|
||||
},
|
||||
{
|
||||
slug: 'smart-warehouse',
|
||||
title: 'Smart Warehouse RFID',
|
||||
excerpt: 'RFID-basiertes Lagerverwaltungssystem mit IoT-Integration',
|
||||
date: '2024-02',
|
||||
technologies: ['Python', 'RFID', 'IoT', 'PostgreSQL'],
|
||||
category: 'IoT',
|
||||
},
|
||||
{
|
||||
slug: 'website-mit-ki',
|
||||
title: 'Portfolio mit KI',
|
||||
excerpt: 'Moderne Portfolio-Website mit KI-Integration',
|
||||
date: '2024-03',
|
||||
technologies: ['Next.js', 'TypeScript', 'Tailwind', 'Supabase'],
|
||||
category: 'Full-Stack',
|
||||
},
|
||||
];
|
||||
|
||||
const Projects = async () => {
|
||||
const t = await getTranslations('pages.home.projects');
|
||||
const locale = await getLocale();
|
||||
|
||||
return (
|
||||
<section id="projects" className="py-24">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between items-center mb-12">
|
||||
<h2 className="text-3xl font-bold text-zinc-100">
|
||||
{t('title')}
|
||||
</h2>
|
||||
<Link
|
||||
href={`/${locale}/portfolio`}
|
||||
className="text-zinc-400 hover:text-white transition-colors duration-300"
|
||||
>
|
||||
{t('viewAll')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{projectsData.map((project) => (
|
||||
<Link
|
||||
key={project.slug}
|
||||
href={`/${locale}/portfolio/${project.slug}`}
|
||||
className="group relative block bg-zinc-900/50 backdrop-blur-sm
|
||||
rounded-xl shadow-lg hover:shadow-2xl
|
||||
ring-1 ring-zinc-800 hover:ring-zinc-700
|
||||
transition-all duration-500 focus:outline-none focus:ring-2
|
||||
focus:ring-zinc-600 focus:ring-offset-2 focus:ring-offset-zinc-950
|
||||
transform hover:-translate-y-1"
|
||||
>
|
||||
<div className="relative overflow-hidden rounded-xl">
|
||||
{/* Image Container */}
|
||||
<div className="aspect-[16/9] w-full relative overflow-hidden bg-zinc-900">
|
||||
<Image
|
||||
src={`/images/projects/${project.slug}/cover.avif`}
|
||||
alt={project.title}
|
||||
fill
|
||||
sizes="(max-width: 640px) 350px, (max-width: 768px) 400px, (max-width: 1024px) 550px, 400px"
|
||||
className="object-cover transition-transform duration-700 group-hover:scale-110"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative -mt-2 p-6 bg-zinc-900 z-10">
|
||||
<div className="flex items-center gap-4 mb-4 text-zinc-500">
|
||||
{project.date && (
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Calendar className="h-4 w-4" />
|
||||
<span>{project.date}</span>
|
||||
</div>
|
||||
)}
|
||||
{project.technologies.length > 0 && (
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Tag className="h-4 w-4" />
|
||||
<span>{project.technologies.length} Technologies</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h3 className="text-xl font-semibold text-white mb-3 group-hover:text-zinc-100 transition-colors duration-300">
|
||||
{project.title}
|
||||
</h3>
|
||||
<p className="text-zinc-400 text-sm line-clamp-2 mb-4 group-hover:text-zinc-300 transition-colors duration-300">
|
||||
{project.excerpt}
|
||||
</p>
|
||||
|
||||
{/* Tags */}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{project.technologies.slice(0, 3).map((tag, tagIndex) => (
|
||||
<span
|
||||
key={tagIndex}
|
||||
className="px-3 py-1 bg-zinc-800/50 text-sm text-zinc-400 rounded-full
|
||||
ring-1 ring-zinc-700/50 group-hover:ring-zinc-600/50
|
||||
group-hover:bg-zinc-800/70 group-hover:text-zinc-300
|
||||
transition-all duration-300"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
{project.technologies.length > 3 && (
|
||||
<span className="text-sm text-zinc-600">
|
||||
+{project.technologies.length - 3} more
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Link Icon */}
|
||||
<div className="absolute top-6 right-6 p-2.5 rounded-full
|
||||
bg-zinc-800/60 backdrop-blur-sm ring-1 ring-zinc-700/50
|
||||
opacity-0 group-hover:opacity-100
|
||||
transform translate-y-2 group-hover:translate-y-0
|
||||
transition-all duration-300">
|
||||
<ExternalLink className="h-4 w-4 text-zinc-400" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Projects;
|
||||
Reference in New Issue
Block a user