Implementierung - SEO - 01.08.2025
This commit is contained in:
+17
-17
@@ -16,17 +16,17 @@ const Footer = () => {
|
||||
<h3 className="text-white text-base font-semibold mb-3">
|
||||
{t('footer.sections.contact.title')}
|
||||
</h3>
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="space-y-2">
|
||||
<a
|
||||
href={`mailto:${t('footer.sections.contact.email')}`}
|
||||
className="group flex items-center space-x-2 text-zinc-400 hover:text-white transition-colors text-sm"
|
||||
className="group flex items-center gap-2 text-zinc-400 hover:text-white transition-colors text-sm !p-0 !min-h-0 !min-w-0 w-fit"
|
||||
aria-label={t('footer.sections.contact.aria.emailLink')}
|
||||
>
|
||||
<Mail className="h-4 w-4 text-zinc-500 group-hover:text-white transition-colors" size={16} />
|
||||
<Mail className="h-4 w-4 text-zinc-500 group-hover:text-white transition-colors flex-shrink-0" size={16} />
|
||||
<span>{t('footer.sections.contact.email')}</span>
|
||||
</a>
|
||||
<div className="flex items-center space-x-2 text-zinc-400 text-sm">
|
||||
<MapPin className="h-4 w-4 text-zinc-500" size={16} />
|
||||
<div className="flex items-center gap-2 text-zinc-400 text-sm w-fit">
|
||||
<MapPin className="h-4 w-4 text-zinc-500 flex-shrink-0" size={16} />
|
||||
<span>{t('footer.sections.contact.location')}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,31 +34,31 @@ const Footer = () => {
|
||||
|
||||
{/* Navigation Section */}
|
||||
<div>
|
||||
<h3 className="text-white text-base font-semibold mb-3">
|
||||
<h3 className="text-white text-base font-semibold mb-3 text-left">
|
||||
{t('footer.sections.navigation.title')}
|
||||
</h3>
|
||||
<nav className="flex flex-col space-y-2">
|
||||
<Link
|
||||
to="/portfolio"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm w-fit !p-0 !min-h-0 !min-w-0"
|
||||
>
|
||||
{t('footer.sections.navigation.links.portfolio')}
|
||||
</Link>
|
||||
<Link
|
||||
to="/blog"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm w-fit !p-0 !min-h-0 !min-w-0"
|
||||
>
|
||||
{t('footer.sections.navigation.links.blog')}
|
||||
</Link>
|
||||
<Link
|
||||
to="/about"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm w-fit !p-0 !min-h-0 !min-w-0"
|
||||
>
|
||||
{t('footer.sections.navigation.links.about')}
|
||||
</Link>
|
||||
<Link
|
||||
to="/contact"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm"
|
||||
className="text-zinc-400 hover:text-white transition-colors text-sm w-fit !p-0 !min-h-0 !min-w-0"
|
||||
>
|
||||
{t('footer.sections.navigation.links.contact')}
|
||||
</Link>
|
||||
@@ -67,7 +67,7 @@ const Footer = () => {
|
||||
|
||||
{/* Social Media Section */}
|
||||
<div>
|
||||
<h3 className="text-white text-base font-semibold mb-3">
|
||||
<h3 className="text-white text-base font-semibold mb-3 text-left">
|
||||
{t('footer.sections.social.title')}
|
||||
</h3>
|
||||
<div className="flex space-x-4">
|
||||
@@ -75,7 +75,7 @@ const Footer = () => {
|
||||
href="https://www.linkedin.com/in/damjan-savić-720288127/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="group text-zinc-400 hover:text-white transition-colors"
|
||||
className="group text-zinc-400 hover:text-white transition-colors !p-0 !min-h-0 !min-w-0"
|
||||
aria-label={t('footer.sections.social.aria.linkedin')}
|
||||
>
|
||||
<Linkedin className="transform transition-transform group-hover:scale-110" size={20} />
|
||||
@@ -84,7 +84,7 @@ const Footer = () => {
|
||||
href="https://github.com/damjan1996"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="group text-zinc-400 hover:text-white transition-colors"
|
||||
className="group text-zinc-400 hover:text-white transition-colors !p-0 !min-h-0 !min-w-0"
|
||||
aria-label={t('footer.sections.social.aria.github')}
|
||||
>
|
||||
<Github className="transform transition-transform group-hover:scale-110" size={20} />
|
||||
@@ -95,19 +95,19 @@ const Footer = () => {
|
||||
{/* Legal Section */}
|
||||
<div className="border-t border-zinc-700/30 pt-4">
|
||||
<div className="flex flex-col space-y-4">
|
||||
<p className="text-zinc-400 text-xs text-center">
|
||||
<p className="text-zinc-400 text-xs text-left">
|
||||
© {currentYear} Damjan Savić. {t('footer.legal.copyright')}
|
||||
</p>
|
||||
<div className="flex justify-center space-x-4">
|
||||
<div className="flex space-x-4">
|
||||
<Link
|
||||
to="/privacy"
|
||||
className="text-zinc-400 hover:text-white text-xs transition-colors"
|
||||
className="text-zinc-400 hover:text-white text-xs transition-colors !p-0 !min-h-0 !min-w-0"
|
||||
>
|
||||
{t('footer.legal.links.privacy')}
|
||||
</Link>
|
||||
<Link
|
||||
to="/terms"
|
||||
className="text-zinc-400 hover:text-white text-xs transition-colors"
|
||||
className="text-zinc-400 hover:text-white text-xs transition-colors !p-0 !min-h-0 !min-w-0"
|
||||
>
|
||||
{t('footer.legal.links.terms')}
|
||||
</Link>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// C:\Development\Damjan Savic\Portfolio\src\components\LanguageSwitcher.tsx
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Globe } from 'lucide-react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
@@ -7,6 +7,7 @@ import { motion, AnimatePresence } from 'framer-motion';
|
||||
const LanguageSwitcher: React.FC = () => {
|
||||
const { i18n } = useTranslation();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isMobile, setIsMobile] = useState(false);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const languages = [
|
||||
@@ -29,9 +30,18 @@ const LanguageSwitcher: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
// Check if mobile on mount and resize
|
||||
const checkMobile = () => {
|
||||
setIsMobile(window.innerWidth < 768);
|
||||
};
|
||||
|
||||
checkMobile();
|
||||
window.addEventListener('resize', checkMobile);
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => {
|
||||
window.removeEventListener('resize', checkMobile);
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
@@ -56,13 +66,13 @@ const LanguageSwitcher: React.FC = () => {
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
initial={{ opacity: 0, y: isMobile ? 10 : -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
exit={{ opacity: 0, y: isMobile ? 10 : -10 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="absolute top-full right-0 mt-2 w-48 rounded-lg overflow-hidden
|
||||
className={`absolute ${isMobile ? 'bottom-full mb-2' : 'top-full mt-2'} right-0 w-48 rounded-lg overflow-hidden
|
||||
border border-zinc-800 bg-zinc-900/95 backdrop-blur-sm
|
||||
shadow-lg"
|
||||
shadow-lg`}
|
||||
role="listbox"
|
||||
aria-label="Languages"
|
||||
onKeyDown={handleKeyDown}
|
||||
|
||||
@@ -210,7 +210,15 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
initial={{ x: "100%" }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: "100%" }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||
transition={{
|
||||
type: "tween",
|
||||
duration: 0.3,
|
||||
ease: [0.4, 0, 0.2, 1]
|
||||
}}
|
||||
style={{
|
||||
willChange: 'transform',
|
||||
transform: 'translateZ(0)'
|
||||
}}
|
||||
className="fixed right-0 top-0 h-full w-80 bg-zinc-900/95 backdrop-blur-md shadow-xl md:hidden z-50 border-l border-zinc-800"
|
||||
>
|
||||
{/* Sidebar Header mit Close-Button */}
|
||||
|
||||
Reference in New Issue
Block a user