feat: localize content to German across various components and add profile image

This commit is contained in:
2026-05-10 21:18:16 +02:00
parent 430e02c8ce
commit a7e62e84fa
14 changed files with 264 additions and 131 deletions
@@ -1,16 +1,16 @@
import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Menu, X } from 'lucide-react';
import { useNavigation } from '../hooks/useNavigation';
import { useScrollToSection } from '../../../shared/hooks/useScrollToSection';
import Button from '../../../shared/components/Button';
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Menu, X } from "lucide-react";
import { useNavigation } from "../hooks/useNavigation";
import { useScrollToSection } from "../../../shared/hooks/useScrollToSection";
import Button from "../../../shared/components/Button";
const navItems = [
{ id: 'home', label: 'Über mich' },
{ id: 'skills', label: 'Fähigkeiten' },
{ id: 'projects', label: 'Projekte' },
{ id: 'experience', label: 'Erfahrung' },
{ id: 'contact', label: 'Kontakt' },
{ id: "home", label: "Über mich" },
{ id: "skills", label: "Fähigkeiten" },
{ id: "projects", label: "Projekte" },
{ id: "experience", label: "Erfahrung" },
{ id: "contact", label: "Kontakt" },
];
export const Navigation: React.FC = () => {
@@ -27,81 +27,98 @@ export const Navigation: React.FC = () => {
<motion.nav
initial={{ y: -120 }}
animate={{ y: 0 }}
transition={{ duration: 0.45, ease: 'easeOut' }}
className={`fixed top-0 w-full z-50 transition-all duration-300 ${
transition={{ duration: 0.45, ease: "easeOut" }}
className={`fixed top-0 w-full z-50 ${
isScrolled
? 'bg-black/90 backdrop-blur-xl border-b border-green-500/20 shadow-lg shadow-emerald-500/5'
: 'bg-transparent'
? "bg-black/90 backdrop-blur-xl border-b border-green-500/20 shadow-lg shadow-emerald-500/5"
: "bg-transparent"
}`}
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo */}
<motion.div
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="text-2xl font-bold text-green-500 cursor-pointer"
onClick={() => handleNavClick('home')}
onClick={() => handleNavClick("home")}
>
&lt;/&gt; Robert Bretz
</motion.div>
{/* Desktop Navigation */}
<div className="hidden md:flex gap-8">
{navItems.map((item) => (
<motion.button
key={item.id}
onClick={() => handleNavClick(item.id)}
className={`text-sm font-medium transition-colors duration-300 pb-2 border-b-2 ${
whileHover={activeSection !== item.id ? { color: '#ffffff' } : {}}
className={`text-sm font-medium pb-2 border-b-2 ${
activeSection === item.id
? 'text-green-500 border-green-500'
: 'text-gray-300 border-transparent hover:text-white'
? "text-green-500 border-green-500"
: "text-gray-300 border-transparent"
}`}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
{item.label}
</motion.button>
))}
</div>
{/* Desktop CTA + Mobile Toggle */}
<div className="flex items-center gap-3">
<div className="hidden md:block">
<motion.div
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="hidden md:block"
>
<Button variant="primary" size="sm">
Anfrage
</Button>
</div>
</motion.div>
<button
{/* Mobile Menu Toggle */}
<motion.button
type="button"
aria-label="Open mobile menu"
className="md:hidden p-2 rounded-full border border-green-500/20 bg-green-500/10 text-green-400 hover:text-white hover:border-green-500 transition-all"
className="md:hidden p-2 rounded-full border border-green-500/20 bg-green-500/10 text-green-400"
onClick={() => setIsOpen((prev) => !prev)}
whileHover={{ scale: 1.1, borderColor: "#22c55e", color: "#ffffff" }}
whileTap={{ scale: 0.9 }}
>
{isOpen ? <X size={22} /> : <Menu size={22} />}
</button>
</motion.button>
</div>
</div>
</div>
{/* Mobile Menu */}
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
className="md:hidden bg-black/95 border-t border-green-500/20"
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.3, ease: "easeInOut" }}
className="md:hidden bg-black/95 border-t border-green-500/20 overflow-hidden"
>
<div className="px-6 py-6 space-y-4">
{navItems.map((item) => (
<button
<div className="px-6 py-6 space-y-2">
{navItems.map((item, index) => (
<motion.button
key={item.id}
onClick={() => handleNavClick(item.id)}
className={`w-full text-left text-lg font-medium px-4 py-3 rounded-xl transition-colors duration-300 ${
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.05 }}
whileHover={activeSection !== item.id ? { scale: 1.02, x: 4, backgroundColor: 'rgba(255,255,255,0.05)' } : { scale: 1.02, x: 4 }}
whileTap={{ scale: 0.98 }}
className={`w-full text-left text-lg font-medium px-4 py-3 rounded-xl ${
activeSection === item.id
? 'bg-green-500/15 text-green-400'
: 'text-gray-300 hover:bg-white/5 hover:text-white'
? "bg-green-500/15 text-green-400"
: "text-gray-300"
}`}
>
{item.label}
</button>
</motion.button>
))}
</div>
</motion.div>
@@ -109,4 +126,4 @@ export const Navigation: React.FC = () => {
</AnimatePresence>
</motion.nav>
);
};
};