refactor: eliminate all hardcoded strings in TSX components, enforce project rules in AGENTS.md, lock body scroll in cookie modal

This commit is contained in:
2026-08-26 03:09:15 +02:00
parent 8c6f3d2633
commit 434237e916
17 changed files with 475 additions and 245 deletions
+62 -50
View File
@@ -17,10 +17,12 @@ interface FooterProps {
phone?: string | null
email?: string | null
items?: FooterNavItem[]
privacyHref?: string
privacyLabel?: string
cookieHref?: string
cookieLabel?: string
privacyHref?: string | null
privacyLabel?: string | null
cookieHref?: string | null
cookieLabel?: string | null
navTitle?: string | null
contactTitle?: string | null
}
export function Footer({
@@ -33,10 +35,12 @@ export function Footer({
phone,
email,
items,
privacyHref = '/polityka-prywatnosci',
privacyLabel = 'Polityka Prywatności',
cookieHref = '/polityka-cookies',
cookieLabel = 'Polityka Cookies',
privacyHref,
privacyLabel,
cookieHref,
cookieLabel,
navTitle,
contactTitle,
}: FooterProps) {
return (
<footer className="bg-[#1f1f1f] text-[#d0d0d0] py-16 border-t-4 border-[#FFED00]">
@@ -59,18 +63,22 @@ export function Footer({
{footerTagline}
</p>
)}
<div className="text-xs text-[#888888] font-mono space-y-1 pt-2 border-t border-[#333333]">
{nip && <div>NIP: <span className="text-[#e0e0e0] font-semibold">{nip}</span></div>}
{regon && <div>REGON: <span className="text-[#e0e0e0] font-semibold">{regon}</span></div>}
</div>
{(nip || regon) && (
<div className="text-xs text-[#888888] font-mono space-y-1 pt-2 border-t border-[#333333]">
{nip && <div>NIP: <span className="text-[#e0e0e0] font-semibold">{nip}</span></div>}
{regon && <div>REGON: <span className="text-[#e0e0e0] font-semibold">{regon}</span></div>}
</div>
)}
</div>
{/* Navigation Links */}
{items && items.length > 0 && (
<div className="space-y-4">
<div className="text-xs font-black uppercase tracking-widest text-[#FFED00] border-b border-[#333333] pb-2">
Nawigacja
</div>
{navTitle && (
<div className="text-xs font-black uppercase tracking-widest text-[#FFED00] border-b border-[#333333] pb-2">
{navTitle}
</div>
)}
<ul className="space-y-2.5 text-xs font-bold uppercase tracking-wider">
{items.map((item, idx) => (
<li key={item.id || idx}>
@@ -84,54 +92,58 @@ export function Footer({
)}
{/* Contact Details */}
<div className="space-y-4">
<div className="text-xs font-black uppercase tracking-widest text-[#FFED00] border-b border-[#333333] pb-2">
Kontakt
{(phone || email || address || city) && (
<div className="space-y-4">
{contactTitle && (
<div className="text-xs font-black uppercase tracking-widest text-[#FFED00] border-b border-[#333333] pb-2">
{contactTitle}
</div>
)}
<ul className="space-y-3 text-xs">
{phone && (
<li className="flex items-center gap-2.5">
<Phone className="h-4 w-4 text-[#FFED00] shrink-0" />
<a href={`tel:${phone.replace(/\s+/g, '')}`} className="text-white hover:text-[#FFED00] font-mono font-black text-sm">
{phone}
</a>
</li>
)}
{email && (
<li className="flex items-center gap-2.5">
<Mail className="h-4 w-4 text-[#FFED00] shrink-0" />
<a href={`mailto:${email}`} className="text-[#d0d0d0] hover:text-white font-medium">
{email}
</a>
</li>
)}
{(address || city) && (
<li className="flex items-start gap-2.5">
<MapPin className="h-4 w-4 text-[#FFED00] shrink-0 mt-0.5" />
<span className="text-[#a0a0a0]">
{address}
{address && city ? ', ' : ''}
{city}
</span>
</li>
)}
</ul>
</div>
<ul className="space-y-3 text-xs">
{phone && (
<li className="flex items-center gap-2.5">
<Phone className="h-4 w-4 text-[#FFED00] shrink-0" />
<a href={`tel:${phone.replace(/\s+/g, '')}`} className="text-white hover:text-[#FFED00] font-mono font-black text-sm">
{phone}
</a>
</li>
)}
{email && (
<li className="flex items-center gap-2.5">
<Mail className="h-4 w-4 text-[#FFED00] shrink-0" />
<a href={`mailto:${email}`} className="text-[#d0d0d0] hover:text-white font-medium">
{email}
</a>
</li>
)}
{(address || city) && (
<li className="flex items-start gap-2.5">
<MapPin className="h-4 w-4 text-[#FFED00] shrink-0 mt-0.5" />
<span className="text-[#a0a0a0]">
{address}
{address && city ? ', ' : ''}
{city}
</span>
</li>
)}
</ul>
</div>
)}
</div>
{/* Bottom Bar with Privacy & Cookie Links */}
<div className="mt-12 pt-8 border-t border-[#333333] flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-[#888888]">
<div>
© {new Date().getFullYear()} {companyName}. Wszelkie prawa zastrzeżone.
© {new Date().getFullYear()} {companyName}
</div>
<div className="flex items-center gap-6 text-xs font-bold uppercase tracking-wider">
{privacyHref && (
{privacyHref && privacyLabel && (
<a href={privacyHref} className="text-[#a0a0a0] hover:text-[#FFED00] transition-colors flex items-center gap-1.5">
<ShieldCheck className="h-3.5 w-3.5 text-[#FFED00]" />
<span>{privacyLabel}</span>
</a>
)}
{cookieHref && (
{cookieHref && cookieLabel && (
<a href={cookieHref} className="text-[#a0a0a0] hover:text-[#FFED00] transition-colors flex items-center gap-1.5">
<Cookie className="h-3.5 w-3.5 text-[#FFED00]" />
<span>{cookieLabel}</span>