refactor: współdzielony LangSwitcher także w nagłówkach podstron
Przełącznik siedział w Header.tsx, który renderuje się tylko na landingu — PrivacyPolicyPage i PlatformPage mają własne <header>. Z /en/privacy i /en/platforma nie dało się wrócić na PL inaczej niż przez stronę główną albo ręczną edycję URL-a. Wyciągnięty do src/components/LangSwitcher.tsx i wstawiony w oba nagłówki obok linku powrotnego. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3e452191de
commit
13ffb8754b
|
|
@ -1,39 +1,8 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Menu, X } from 'lucide-react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { localizePath, setLang, useLang, type Lang } from '../i18n';
|
||||
|
||||
const LANGS: Lang[] = ['pl', 'en'];
|
||||
|
||||
// PL / EN toggle. Buttons rather than links: switching is a client-side
|
||||
// navigation (setLang), so a real href would reload the whole document.
|
||||
const LangSwitcher = ({ onSwitch }: { onSwitch?: () => void }) => {
|
||||
const lang = useLang();
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-sm font-medium" role="group" aria-label="Język / Language">
|
||||
{LANGS.map((code, i) => (
|
||||
<React.Fragment key={code}>
|
||||
{i > 0 && <span aria-hidden="true" className="text-muted/40">/</span>}
|
||||
<button
|
||||
type="button"
|
||||
lang={code}
|
||||
aria-current={code === lang ? 'true' : undefined}
|
||||
onClick={() => {
|
||||
setLang(code);
|
||||
onSwitch?.();
|
||||
}}
|
||||
className={`uppercase tracking-wide transition-colors ${
|
||||
code === lang ? 'text-foreground' : 'text-muted hover:text-foreground'
|
||||
}`}
|
||||
>
|
||||
{code}
|
||||
</button>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
import { localizePath, useLang } from '../i18n';
|
||||
import LangSwitcher from './LangSwitcher';
|
||||
|
||||
const Header = () => {
|
||||
const lang = useLang();
|
||||
|
|
|
|||
44
src/components/LangSwitcher.tsx
Normal file
44
src/components/LangSwitcher.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import React from 'react';
|
||||
import { setLang, useLang, type Lang } from '../i18n';
|
||||
|
||||
const LANGS: Lang[] = ['pl', 'en'];
|
||||
|
||||
/**
|
||||
* PL / EN toggle. Buttons rather than links: switching is a client-side
|
||||
* navigation (setLang), so a real href would reload the whole document.
|
||||
*
|
||||
* Shared by the landing Header and the standalone pages' own headers — without
|
||||
* it on those pages, /en/privacy and /en/platforma have no way back to Polish
|
||||
* short of editing the URL.
|
||||
*
|
||||
* @param onSwitch runs after the language changes — used to close the mobile menu.
|
||||
*/
|
||||
const LangSwitcher = ({ onSwitch }: { onSwitch?: () => void }) => {
|
||||
const lang = useLang();
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-sm font-medium" role="group" aria-label="Język / Language">
|
||||
{LANGS.map((code, i) => (
|
||||
<React.Fragment key={code}>
|
||||
{i > 0 && <span aria-hidden="true" className="text-muted/40">/</span>}
|
||||
<button
|
||||
type="button"
|
||||
lang={code}
|
||||
aria-current={code === lang ? 'true' : undefined}
|
||||
onClick={() => {
|
||||
setLang(code);
|
||||
onSwitch?.();
|
||||
}}
|
||||
className={`uppercase tracking-wide transition-colors ${
|
||||
code === lang ? 'text-foreground' : 'text-muted hover:text-foreground'
|
||||
}`}
|
||||
>
|
||||
{code}
|
||||
</button>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LangSwitcher;
|
||||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { ArrowRight, Building2, CheckCircle2, ChevronRight, Home } from 'lucide-react';
|
||||
import Footer from './Footer';
|
||||
import { localizePath, useLang } from '../i18n';
|
||||
import LangSwitcher from './LangSwitcher';
|
||||
|
||||
// Standalone product page at /platforma (and /en/platforma). The copy is not
|
||||
// localized yet — the site only translates contact.* and privacy.* — but the
|
||||
|
|
@ -16,9 +17,12 @@ const PlatformPage = () => {
|
|||
<a href={localizePath('/', lang)} className="text-2xl font-bold tracking-tight hover:opacity-80 transition-opacity">
|
||||
human<span className="text-primary">AI</span>
|
||||
</a>
|
||||
<div className="flex items-center gap-6">
|
||||
<a href={localizePath('/', lang)} className="text-sm text-muted hover:text-foreground transition-colors">
|
||||
← Wróć na stronę główną
|
||||
</a>
|
||||
<LangSwitcher />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { localizePath, useLang, useT } from '../i18n';
|
||||
import Footer from './Footer';
|
||||
import LangSwitcher from './LangSwitcher';
|
||||
|
||||
const PrivacyPolicyPage = () => {
|
||||
const t = useT();
|
||||
|
|
@ -14,9 +15,12 @@ const PrivacyPolicyPage = () => {
|
|||
<a href={home} className="text-2xl font-bold tracking-tight hover:opacity-80 transition-opacity">
|
||||
human<span className="text-primary">AI</span>
|
||||
</a>
|
||||
<div className="flex items-center gap-6">
|
||||
<a href={home} className="text-sm text-muted hover:text-foreground transition-colors">
|
||||
{t.privacy.backToHome}
|
||||
</a>
|
||||
<LangSwitcher />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue