2026-05-12 19:10:59 +02:00
|
|
|
import React from 'react';
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
import { localizePath, stripLangPrefix, useLang } from '../i18n';
|
2026-05-12 19:10:59 +02:00
|
|
|
|
|
|
|
|
const Footer = () => {
|
|
|
|
|
const currentYear = new Date().getFullYear();
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
const lang = useLang();
|
2026-07-31 15:03:37 +02:00
|
|
|
|
|
|
|
|
// Same reasoning as the /#section nav links below: this footer is shared with
|
|
|
|
|
// /privacy and /platforma, so the logo needs a real href to get home from
|
|
|
|
|
// there. On the homepage that href would mean a full reload, so intercept the
|
|
|
|
|
// click and scroll to the top instead.
|
|
|
|
|
const handleLogoClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
if (stripLangPrefix(window.location.pathname) !== '/') return;
|
2026-07-31 15:03:37 +02:00
|
|
|
e.preventDefault();
|
|
|
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2026-05-12 19:10:59 +02:00
|
|
|
return (
|
|
|
|
|
<footer className="py-12 border-t border-white/5 bg-background">
|
|
|
|
|
<div className="container mx-auto px-6">
|
|
|
|
|
<div className="grid md:grid-cols-4 gap-12 mb-12">
|
|
|
|
|
<div className="col-span-2">
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
<a href={localizePath('/', lang)} onClick={handleLogoClick} className="text-2xl font-bold tracking-tight mb-4 block">
|
2026-05-12 19:10:59 +02:00
|
|
|
human<span className="text-primary">AI</span>
|
|
|
|
|
</a>
|
|
|
|
|
<p className="text-muted max-w-xs mb-6">
|
|
|
|
|
ludzka strona AI — budujemy praktyczne systemy AI dla ludzi i organizacji.
|
|
|
|
|
</p>
|
2026-06-23 16:46:45 +02:00
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<a href="mailto:hello@gethumanai.pl" className="text-foreground/80 hover:text-primary transition-colors">
|
|
|
|
|
hello@gethumanai.pl
|
|
|
|
|
</a>
|
|
|
|
|
<a href="mailto:support@gethumanai.pl" className="text-foreground/80 hover:text-primary transition-colors">
|
|
|
|
|
support@gethumanai.pl
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
2026-05-12 19:10:59 +02:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<h4 className="font-bold mb-6 text-sm uppercase tracking-wider">Nawigacja</h4>
|
|
|
|
|
<ul className="space-y-4">
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
<li><a href={localizePath('/#offerings', lang)} className="text-muted hover:text-foreground transition-colors">Oferta</a></li>
|
|
|
|
|
<li><a href={localizePath('/platforma', lang)} className="text-muted hover:text-foreground transition-colors">Platforma</a></li>
|
|
|
|
|
<li><a href={localizePath('/#contact', lang)} className="text-muted hover:text-foreground transition-colors">Kontakt</a></li>
|
2026-05-12 19:10:59 +02:00
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<h4 className="font-bold mb-6 text-sm uppercase tracking-wider">Prywatność</h4>
|
|
|
|
|
<ul className="space-y-4">
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
<li><a href={localizePath('/privacy', lang)} className="text-muted hover:text-foreground transition-colors">Polityka prywatności</a></li>
|
|
|
|
|
<li><a href={localizePath('/privacy#cookies', lang)} className="text-muted hover:text-foreground transition-colors">Cookies</a></li>
|
2026-05-12 19:10:59 +02:00
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="pt-8 border-t border-white/5 flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-muted">
|
|
|
|
|
<p>© {currentYear} humanAI. Wszelkie prawa zastrzeżone.</p>
|
|
|
|
|
<div className="flex gap-8">
|
|
|
|
|
<span className="hover:text-foreground transition-colors cursor-pointer">LinkedIn</span>
|
|
|
|
|
<span className="hover:text-foreground transition-colors cursor-pointer">X / Twitter</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</footer>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default Footer;
|