feat: redesign Header and Footer to match premium UI

This commit is contained in:
MichalC
2026-08-31 23:16:57 +02:00
parent c2b3e6a616
commit 93c98e1c42
2 changed files with 127 additions and 103 deletions
+31 -28
View File
@@ -27,54 +27,57 @@ export function Footer({
const phone = getLocText(companyInfo.phone); const phone = getLocText(companyInfo.phone);
const email = getLocText(companyInfo.email); const email = getLocText(companyInfo.email);
const hours = getLocText(companyInfo.hours); const hours = getLocText(companyInfo.hours);
const whatsapp = companyInfo.whatsappNumber?.[currentLocaleCode] || companyInfo.whatsappNumber?.pl || process.env.NEXT_PUBLIC_WHATSAPP_NUMBER || '';
const assocTitle = getLocText(association.title); const assocTitle = getLocText(association.title);
const assocLink = association.link; const assocLink = association.link;
const assocLogo = association.logo; const assocLogo = association.logo;
return ( return (
<footer className="bg-muted py-12 md:py-16 border-t border-border mt-auto"> <footer className="bg-card py-16 md:py-24 mt-auto">
<div className="container-premium grid grid-cols-1 md:grid-cols-3 gap-12 md:gap-8"> <div className="container-premium grid grid-cols-1 md:grid-cols-3 gap-16 md:gap-12">
{/* Kolumna 1: Dane kontaktowe */} {/* Kolumna 1: Dane kontaktowe */}
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-6">
<Link href={`/${currentLocaleCode}`} className="group flex items-center gap-3 w-fit mb-2"> <Link href={`/${currentLocaleCode}`} className="group flex items-center gap-3 w-fit mb-4">
<div className="w-10 h-10 rounded bg-[var(--accent-color)] text-white flex items-center justify-center font-heading font-bold text-xl group-hover:bg-[var(--accent-hover-color)] transition-colors shadow-sm"> <div className="w-10 h-10 rounded bg-accent text-white flex items-center justify-center font-heading font-bold text-xl group-hover:bg-accent-hover transition-colors shadow-sm">
JK JK
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<span className="font-heading font-bold text-lg leading-tight tracking-tight text-foreground"> <span className="font-heading font-bold text-lg leading-tight tracking-tight text-foreground">
Finanz- & Lohnbuchhaltung Finanz- & Lohnbuchhaltung
</span> </span>
<span className="text-xs text-muted-foreground uppercase tracking-widest font-medium"> <span className="text-xs text-foreground/60 uppercase tracking-widest font-medium">
Dipl.-Ing. Janusz Kędzierski Dipl.-Ing. Janusz Kędzierski
</span> </span>
</div> </div>
</Link> </Link>
<ul className="flex flex-col gap-3 text-sm text-muted-foreground mt-2"> <h3 className="text-sm font-semibold text-foreground/60 uppercase tracking-wider">
{currentLocaleCode === 'de' ? 'Kontakt' : 'Kontakt'}
</h3>
<ul className="flex flex-col gap-4 text-sm text-foreground/80">
{address && ( {address && (
<li className="flex items-start gap-3"> <li className="flex items-start gap-3">
<MapPin size={18} className="shrink-0 text-foreground/50 mt-0.5" /> <MapPin size={18} className="shrink-0 text-foreground/40 mt-0.5" />
<span className="whitespace-pre-line">{address}</span> <span className="whitespace-pre-line">{address}</span>
</li> </li>
)} )}
{phone && ( {phone && (
<li className="flex items-center gap-3"> <li className="flex items-center gap-3">
<Phone size={18} className="shrink-0 text-foreground/50" /> <Phone size={18} className="shrink-0 text-foreground/40" />
<a href={`tel:${phone.replace(/\s+/g, '')}`} className="hover:text-foreground transition-colors">{phone}</a> <a href={`tel:${phone.replace(/\s+/g, '')}`} className="hover:text-accent transition-colors">{phone}</a>
</li> </li>
)} )}
{email && ( {email && (
<li className="flex items-center gap-3"> <li className="flex items-center gap-3">
<Mail size={18} className="shrink-0 text-foreground/50" /> <Mail size={18} className="shrink-0 text-foreground/40" />
<a href={`mailto:${email}`} className="hover:text-foreground transition-colors">{email}</a> <a href={`mailto:${email}`} className="hover:text-accent transition-colors">{email}</a>
</li> </li>
)} )}
{hours && ( {hours && (
<li className="flex items-start gap-3"> <li className="flex items-start gap-3">
<Clock size={18} className="shrink-0 text-foreground/50 mt-0.5" /> <Clock size={18} className="shrink-0 text-foreground/40 mt-0.5" />
<span className="whitespace-pre-line">{hours}</span> <span className="whitespace-pre-line">{hours}</span>
</li> </li>
)} )}
@@ -82,36 +85,36 @@ export function Footer({
</div> </div>
{/* Kolumna 2: Nawigacja / Linki */} {/* Kolumna 2: Nawigacja / Linki */}
<div className="flex flex-col gap-4 md:px-8"> <div className="flex flex-col gap-6 md:px-8">
<h3 className="font-heading font-semibold text-lg text-foreground"> <h3 className="text-sm font-semibold text-foreground/60 uppercase tracking-wider">
{currentLocaleCode === 'de' ? 'Navigation' : 'Nawigacja'} {currentLocaleCode === 'de' ? 'Navigation' : 'Nawigacja'}
</h3> </h3>
<nav className="flex flex-col gap-3"> <nav className="flex flex-col gap-4">
{navItems.map((page, index) => ( {navItems.map((page, index) => (
<LocalizedLink <LocalizedLink
key={index} key={index}
page={page} page={page}
currentLocaleCode={currentLocaleCode} currentLocaleCode={currentLocaleCode}
className="text-sm font-medium text-muted-foreground hover:text-foreground transition-colors w-fit" className="text-foreground/80 hover:text-accent font-medium transition-colors w-fit"
/> />
))} ))}
</nav> </nav>
</div> </div>
{/* Kolumna 3: Stowarzyszenie */} {/* Kolumna 3: Stowarzyszenie */}
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-6">
<h3 className="font-heading font-semibold text-lg text-foreground"> <h3 className="text-sm font-semibold text-foreground/60 uppercase tracking-wider">
{currentLocaleCode === 'de' ? 'Mitgliedschaft' : 'Członkostwo'} {currentLocaleCode === 'de' ? 'Mitgliedschaft' : 'Członkostwo'}
</h3> </h3>
<div className="bg-background border border-border p-5 rounded-xl shadow-sm flex flex-col gap-4 items-start"> <div className="bg-background border border-border p-6 rounded-2xl shadow-sm flex flex-col gap-5 items-start">
<span className="text-sm text-muted-foreground leading-relaxed"> <span className="text-sm text-foreground/80 leading-relaxed font-medium">
{assocTitle} {assocTitle}
</span> </span>
{assocLogo && typeof assocLogo === 'object' && assocLogo.url && ( {assocLogo && typeof assocLogo === 'object' && assocLogo.url && (
<img <img
src={assocLogo.url} src={assocLogo.url}
alt={assocLogo.alt || 'Logo'} alt={assocLogo.alt || 'Logo'}
className="h-12 w-auto object-contain" className="h-14 w-auto object-contain"
/> />
)} )}
{assocLink && ( {assocLink && (
@@ -119,10 +122,10 @@ export function Footer({
href={assocLink} href={assocLink}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center gap-2 text-sm font-semibold text-[var(--accent-color)] hover:text-[var(--accent-hover-color)] transition-colors mt-2 group" className="flex items-center gap-2 text-sm font-semibold text-accent hover:text-accent-hover transition-colors mt-2 group"
> >
<span>{currentLocaleCode === 'de' ? 'Website besuchen' : 'Odwiedź stronę'}</span> <span>{currentLocaleCode === 'de' ? 'Website besuchen' : 'Odwiedź stronę'}</span>
<ExternalLink size={14} className="group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform" /> <ExternalLink size={16} className="group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform" />
</a> </a>
)} )}
</div> </div>
@@ -130,11 +133,11 @@ export function Footer({
</div> </div>
<div className="container-premium mt-12 pt-8 border-t border-border/50 flex flex-col sm:flex-row justify-between items-center gap-4 text-xs text-muted-foreground"> <div className="container-premium mt-16 pt-8 border-t border-border flex flex-col md:flex-row justify-between items-center gap-6 text-sm text-foreground/50">
<p>© {new Date().getFullYear()} Finanz- & Lohnbuchhaltung Dipl.-Ing. Janusz Kędzierski. {currentLocaleCode === 'de' ? 'Alle Rechte vorbehalten.' : 'Wszelkie prawa zastrzeżone.'}</p> <p>© {new Date().getFullYear()} Finanz- & Lohnbuchhaltung Dipl.-Ing. Janusz Kędzierski. {currentLocaleCode === 'de' ? 'Alle Rechte vorbehalten.' : 'Wszelkie prawa zastrzeżone.'}</p>
<p className="flex items-center gap-1"> <p className="flex items-center gap-2 font-medium">
{currentLocaleCode === 'de' ? 'Erstellt von' : 'Realizacja:'} {currentLocaleCode === 'de' ? 'Erstellt von' : 'Realizacja:'}
<a href="#" className="font-medium hover:text-foreground transition-colors">Intecion</a> <a href="#" className="hover:text-accent transition-colors">Intecion</a>
</p> </p>
</div> </div>
</footer> </footer>
+96 -75
View File
@@ -4,7 +4,7 @@ import Link from "next/link";
import { ThemeSwitcher } from "../ThemeSwitcher"; import { ThemeSwitcher } from "../ThemeSwitcher";
import { LanguageSwitcher } from "../LanguageSwitcher"; import { LanguageSwitcher } from "../LanguageSwitcher";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { useState } from "react"; import { useState, useEffect } from "react";
import { Menu, X, MessageCircle } from "lucide-react"; import { Menu, X, MessageCircle } from "lucide-react";
import { i18n } from '../../i18n.config'; import { i18n } from '../../i18n.config';
import { LocalizedLink } from '../LocalizedLink'; import { LocalizedLink } from '../LocalizedLink';
@@ -12,97 +12,118 @@ import { LocalizedLink } from '../LocalizedLink';
export function Header({ navItems = [] }: { navItems?: any[] }) { export function Header({ navItems = [] }: { navItems?: any[] }) {
const pathname = usePathname(); const pathname = usePathname();
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isScrolled, setIsScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 10);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
// Zabezpieczenie przed błędem, gdy pathname jest puste podczas SSR
const currentLocaleCode = (pathname?.split('/').filter(Boolean)[0]) || i18n.defaultLocale; const currentLocaleCode = (pathname?.split('/').filter(Boolean)[0]) || i18n.defaultLocale;
const currentLocale = i18n.locales.find(l => l.code === currentLocaleCode) || i18n.locales[0]; const currentLocale = i18n.locales.find(l => l.code === currentLocaleCode) || i18n.locales[0];
return ( return (
<header className="fixed top-0 left-0 right-0 z-40 bg-background/80 backdrop-blur-md border-b border-border"> <>
<div className="container-premium h-24 flex items-center justify-between"> <header
{/* Logo */} className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
<Link href={`/${currentLocale.code}`} className="group flex items-center gap-3 z-50 relative"> isScrolled
<div className="w-10 h-10 rounded bg-[var(--accent-color)] text-white flex items-center justify-center font-heading font-bold text-xl group-hover:bg-[var(--accent-hover-color)] transition-colors shadow-sm"> ? "bg-background/90 backdrop-blur-md shadow-sm border-b border-border py-4"
JK : "bg-transparent py-6"
</div> }`}
<div className="flex flex-col"> >
<span className="font-heading font-bold text-lg leading-tight tracking-tight text-foreground"> <div className="container-premium flex items-center justify-between">
Finanz- & Lohnbuchhaltung {/* Logo */}
</span> <Link href={`/${currentLocale.code}`} className="group flex items-center gap-3 z-50">
<span className="text-xs text-muted-foreground uppercase tracking-widest font-medium"> <div className="w-10 h-10 rounded bg-accent text-white flex items-center justify-center font-heading font-bold text-xl group-hover:bg-accent-hover transition-colors shadow-sm">
Dipl.-Ing. Janusz Kędzierski JK
</span> </div>
</div> <div className="flex flex-col">
</Link> <span className="font-heading font-bold text-lg leading-tight tracking-tight text-foreground">
Finanz- & Lohnbuchhaltung
</span>
<span className="text-xs text-foreground/60 uppercase tracking-widest font-medium">
Dipl.-Ing. Janusz Kędzierski
</span>
</div>
</Link>
{/* Desktop Navigation */} {/* Desktop Navigation */}
<nav className="hidden lg:flex items-center gap-8 absolute left-1/2 -translate-x-1/2"> <nav className="hidden xl:flex items-center gap-10">
{navItems.map((page, index) => (
<LocalizedLink
key={index}
page={page}
currentLocaleCode={currentLocale.code}
className="text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
/>
))}
</nav>
{/* Right Actions & Hamburger */}
<div className="flex items-center gap-3 z-50 relative">
<div className="hidden sm:flex items-center gap-3 mr-2">
<Link
href={process.env.NEXT_PUBLIC_WHATSAPP_NUMBER ? `https://wa.me/${process.env.NEXT_PUBLIC_WHATSAPP_NUMBER}` : '#'}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center w-10 h-10 rounded-full bg-green-500 hover:bg-green-600 text-white transition-colors"
aria-label="WhatsApp"
>
<MessageCircle size={20} />
</Link>
<div className="w-px h-6 bg-border" />
</div>
<ThemeSwitcher />
<LanguageSwitcher />
<button
className="lg:hidden w-10 h-10 flex items-center justify-center text-foreground rounded-full hover:bg-accent transition-colors ml-2"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label="Toggle menu"
>
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</div>
{/* Mobile Navigation */}
{isMobileMenuOpen && (
<div className="lg:hidden absolute top-24 left-0 right-0 bg-background border-b border-border p-6 shadow-xl flex flex-col gap-6 animate-in fade-in slide-in-from-top-4 duration-200">
<nav className="flex flex-col gap-4">
{navItems.map((page, index) => ( {navItems.map((page, index) => (
<LocalizedLink <LocalizedLink
key={index} key={index}
page={page} page={page}
currentLocaleCode={currentLocale.code} currentLocaleCode={currentLocale.code}
className="text-lg font-medium text-foreground py-2 border-b border-border/50" className="text-sm font-medium text-foreground/80 hover:text-accent transition-colors"
onClick={() => setIsMobileMenuOpen(false)}
/> />
))} ))}
</nav> </nav>
<div className="flex items-center justify-center sm:hidden mt-4 pt-4 border-t border-border/50"> {/* Right Actions & Hamburger */}
<Link <div className="flex items-center gap-4 z-50">
href={process.env.NEXT_PUBLIC_WHATSAPP_NUMBER ? `https://wa.me/${process.env.NEXT_PUBLIC_WHATSAPP_NUMBER}` : '#'} <div className="hidden sm:flex items-center gap-4">
target="_blank" <Link
rel="noopener noreferrer" href={process.env.NEXT_PUBLIC_WHATSAPP_NUMBER ? `https://wa.me/${process.env.NEXT_PUBLIC_WHATSAPP_NUMBER}` : '#'}
className="flex items-center gap-2 bg-green-500 hover:bg-green-600 text-white px-6 py-3 rounded-full transition-colors w-full justify-center" target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-5 py-2.5 rounded-full bg-green-500 hover:bg-green-600 text-white transition-colors font-medium text-sm shadow-sm"
>
<MessageCircle size={18} />
<span className="hidden lg:inline">WhatsApp</span>
</Link>
<div className="w-px h-6 bg-border mx-2 hidden xl:block" />
</div>
<div className="flex items-center gap-2">
<ThemeSwitcher />
<LanguageSwitcher />
</div>
<button
className="xl:hidden w-11 h-11 flex items-center justify-center text-foreground rounded-full hover:bg-accent/10 transition-colors ml-1"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label="Toggle menu"
> >
<MessageCircle size={20} /> {isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
<span className="font-medium">Napisz na WhatsApp</span> </button>
</Link>
</div> </div>
</div> </div>
)} </header>
</header>
{/* Mobile Fullscreen Navigation */}
<div
className={`fixed inset-0 z-40 bg-background/95 backdrop-blur-xl transition-all duration-300 xl:hidden flex flex-col justify-center items-center ${
isMobileMenuOpen ? "opacity-100 visible" : "opacity-0 invisible pointer-events-none"
}`}
>
<nav className="flex flex-col gap-8 text-center w-full px-6">
{navItems.map((page, index) => (
<LocalizedLink
key={index}
page={page}
currentLocaleCode={currentLocale.code}
className="text-2xl font-bold text-foreground hover:text-accent transition-colors"
onClick={() => setIsMobileMenuOpen(false)}
/>
))}
</nav>
<div className="absolute bottom-12 left-0 right-0 px-6 sm:hidden flex flex-col items-center">
<div className="w-full h-px bg-border/50 mb-8 max-w-xs" />
<Link
href={process.env.NEXT_PUBLIC_WHATSAPP_NUMBER ? `https://wa.me/${process.env.NEXT_PUBLIC_WHATSAPP_NUMBER}` : '#'}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 bg-green-500 hover:bg-green-600 text-white px-8 py-4 rounded-full transition-colors w-full max-w-xs shadow-lg"
>
<MessageCircle size={24} />
<span className="font-bold text-lg">WhatsApp</span>
</Link>
</div>
</div>
</>
); );
} }