Bjornpool's picture
Initial commit - TruthScan AI v2.0 master thesis
a7e77af
Raw History Blame
3.29 kB
/**
* Globalny komponent nawigacji aplikacji.
*
* Odpowiada za:
* - prezentacj臋 g艂贸wnej nawigacji mi臋dzy widokami,
* - obs艂ug臋 zmiany j臋zyka interfejsu (PL / EN),
* - prze艂膮czanie trybu jasnego i ciemnego,
* - wizualne wskazanie aktywnej trasy.
*/
"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { motion } from "framer-motion";
import LanguageSwitcher from "./LanguageSwitcher";
import DarkModeToggle from "./DarkModeToggle";
type Lang = "pl" | "en" | "no";
export default function NavBar() {
const pathname = usePathname();
const [language, setLanguage] = useState<Lang>("pl");
useEffect(() => {
const stored = localStorage.getItem("lang");
if (stored === "pl" || stored === "en" || stored === "no") setLanguage(stored as Lang);
}, []);
useEffect(() => {
localStorage.setItem("lang", language);
if (typeof document !== "undefined") document.documentElement.lang = language;
window.dispatchEvent(new CustomEvent("app:langchange", { detail: language }));
}, [language]);
const links = [
{ href: "/", labelPl: "Strona g艂贸wna", labelEn: "Home", labelNo: "Hjem", icon: "馃彔" },
{ href: "/dashboard", labelPl: "Dashboard", labelEn: "Dashboard", labelNo: "Dashbord", icon: "馃搳" },
{ href: "/saved", labelPl: "Zapisane", labelEn: "Saved", labelNo: "Lagrede", icon: "馃捑" },
];
return (
<nav className="sticky top-0 z-50 bg-gray-100 dark:bg-gray-900 shadow-md border-b border-gray-300/20 dark:border-gray-700/50">
<div className="w-full flex justify-between items-center px-4 md:px-6 h-14">
<div className="flex items-center gap-6">
<div
className="hidden sm:block text-base font-semibold text-blue-600 dark:text-blue-400 select-none cursor-default"
aria-label="TruthScan AI"
role="img"
>
TruthScan AI
</div>
<div className="flex items-center gap-6 relative">
{links.map(({ href, labelPl, labelEn, labelNo, icon }) => {
const active = pathname === href || (href !== "/" && pathname.startsWith(href));
return (
<div key={href} className="relative">
<Link href={href} className="inline-flex items-center gap-1.5">
{icon && (
<span
aria-hidden="true"
className="text-[18px] leading-none inline-block translate-y-[1px]"
>
{icon}
</span>
)}
{language === "pl" ? labelPl : language === "no" ? labelNo : labelEn}
</Link>
{active && (
<motion.div
layoutId="nav-indicator"
className="absolute -bottom-1 left-0 right-0 h-[2px] bg-blue-600 dark:bg-blue-400 rounded-full"
transition={{ type: "spring", stiffness: 400, damping: 30 }}
/>
)}
</div>
);
})}
</div>
</div>
<div className="flex items-center gap-2">
<LanguageSwitcher language={language} setLanguage={setLanguage} />
<DarkModeToggle />
</div>
</div>
</nav>
);
}