feat: add Polish and English language switcher
This commit is contained in:
@@ -7,11 +7,14 @@ import { NAV_ITEMS } from "@/lib/constants";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { InstallPWAButton } from "@/components/ui/install-pwa-button";
|
||||
import { ThemeToggle } from "@/components/ui/theme-toggle";
|
||||
import { LanguageToggle } from "@/components/ui/language-toggle";
|
||||
import { useI18n } from "@/lib/i18n";
|
||||
|
||||
const icons = [CloudSun, TriangleAlert, Droplets];
|
||||
|
||||
export function AppShell({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
const { t } = useI18n();
|
||||
return (
|
||||
<div className="min-h-screen overflow-x-hidden bg-[radial-gradient(circle_at_top_left,rgba(125,211,252,0.28),transparent_34%),radial-gradient(circle_at_88%_18%,rgba(129,140,248,0.18),transparent_31%)] dark:bg-[radial-gradient(circle_at_top_left,rgba(14,116,144,0.22),transparent_34%),radial-gradient(circle_at_88%_18%,rgba(49,46,129,0.22),transparent_31%)]">
|
||||
<header className="sticky top-0 z-40 border-b border-white/25 bg-white/30 backdrop-blur-2xl dark:border-white/10 dark:bg-slate-950/30">
|
||||
@@ -19,31 +22,32 @@ export function AppShell({ children }: { children: React.ReactNode }) {
|
||||
<Link href="/" className="text-2xl font-semibold tracking-[-0.09em] text-slate-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500 dark:text-white">
|
||||
wtr<span className="text-sky-600 dark:text-sky-300">.</span>
|
||||
</Link>
|
||||
<nav aria-label="Główna nawigacja" className="hidden items-center gap-1 md:flex">
|
||||
<nav aria-label={t("nav.main")} className="hidden items-center gap-1 md:flex">
|
||||
{NAV_ITEMS.map((item) => {
|
||||
const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
|
||||
return (
|
||||
<Link key={item.href} href={item.href} className={cn("rounded-full px-4 py-2 text-sm font-medium transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500", active ? "bg-white/60 text-slate-950 shadow-sm dark:bg-white/15 dark:text-white" : "text-slate-600 hover:bg-white/35 dark:text-slate-300 dark:hover:bg-white/10")}>
|
||||
{item.label}
|
||||
{t(item.labelKey)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
<div className="flex items-center gap-2">
|
||||
<InstallPWAButton />
|
||||
<LanguageToggle />
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main className="mx-auto max-w-7xl px-4 pb-28 pt-5 sm:px-6 sm:pt-8 lg:px-8">{children}</main>
|
||||
<nav aria-label="Mobilna nawigacja" className="fixed inset-x-3 bottom-3 z-50 flex justify-around rounded-[1.4rem] border border-white/40 bg-white/65 p-1.5 shadow-glass backdrop-blur-2xl dark:border-white/10 dark:bg-slate-950/65 md:hidden">
|
||||
<nav aria-label={t("nav.mobile")} className="fixed inset-x-3 bottom-3 z-50 flex justify-around rounded-[1.4rem] border border-white/40 bg-white/65 p-1.5 shadow-glass backdrop-blur-2xl dark:border-white/10 dark:bg-slate-950/65 md:hidden">
|
||||
{NAV_ITEMS.map((item, index) => {
|
||||
const Icon = icons[index];
|
||||
const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
|
||||
return (
|
||||
<Link key={item.href} href={item.href} className={cn("flex min-w-[5rem] flex-col items-center gap-1 rounded-2xl px-3 py-2 text-[0.68rem] font-medium transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500", active ? "bg-slate-950 text-white dark:bg-white dark:text-slate-950" : "text-slate-600 dark:text-slate-300")}>
|
||||
<Icon className="size-4" />
|
||||
{item.label}
|
||||
{t(item.labelKey)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
import { useState, type PropsWithChildren } from "react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ServiceWorkerRegister } from "@/components/layout/service-worker-register";
|
||||
import { I18nProvider } from "@/lib/i18n";
|
||||
|
||||
export function Providers({ children }: PropsWithChildren) {
|
||||
const [queryClient] = useState(() => new QueryClient());
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{children}
|
||||
<ServiceWorkerRegister />
|
||||
</QueryClientProvider>
|
||||
<I18nProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{children}
|
||||
<ServiceWorkerRegister />
|
||||
</QueryClientProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user