2025-12-23 17:09:40 +03:00
|
|
|
import React, { useState, useEffect } from "react";
|
|
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
|
import { Link } from "react-scroll";
|
|
|
|
|
import LanguageSwitcher from "../LanguageSwitcher/LanguageSwitcher";
|
|
|
|
|
import "../../index.css";
|
|
|
|
|
|
|
|
|
|
const Navbar = () => {
|
|
|
|
|
const { t, i18n } = useTranslation();
|
|
|
|
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
|
|
|
const [activeSection, setActiveSection] = useState("home");
|
2025-12-23 22:00:31 +03:00
|
|
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
|
|
|
|
|
|
|
|
// Initialize dark mode
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const savedTheme = localStorage.getItem("theme");
|
|
|
|
|
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
|
|
|
const shouldEnableDarkMode = savedTheme === "dark" || (!savedTheme && prefersDark);
|
|
|
|
|
|
|
|
|
|
setIsDarkMode(shouldEnableDarkMode);
|
|
|
|
|
if (shouldEnableDarkMode) {
|
|
|
|
|
document.documentElement.classList.add("dark");
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
2025-12-23 17:09:40 +03:00
|
|
|
|
|
|
|
|
const toggleMenu = () => {
|
|
|
|
|
setMenuOpen(!menuOpen);
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-23 22:00:31 +03:00
|
|
|
// Toggle dark/light mode
|
|
|
|
|
const toggleDarkMode = () => {
|
|
|
|
|
const newDarkMode = !isDarkMode;
|
|
|
|
|
setIsDarkMode(newDarkMode);
|
|
|
|
|
|
|
|
|
|
if (newDarkMode) {
|
|
|
|
|
document.documentElement.classList.add("dark");
|
|
|
|
|
localStorage.setItem("theme", "dark");
|
|
|
|
|
} else {
|
|
|
|
|
document.documentElement.classList.remove("dark");
|
|
|
|
|
localStorage.setItem("theme", "light");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2025-12-23 17:09:40 +03:00
|
|
|
// Handle scroll to update active section
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const handleScroll = () => {
|
|
|
|
|
const sections = ["home", "services", "about", "contact"];
|
|
|
|
|
const scrollPosition = window.scrollY + 100;
|
|
|
|
|
|
|
|
|
|
for (const section of sections) {
|
|
|
|
|
const element =
|
|
|
|
|
document.getElementById(section) ||
|
|
|
|
|
document.querySelector(`[name="${section}"]`);
|
|
|
|
|
if (element) {
|
|
|
|
|
const offsetTop = element.offsetTop;
|
|
|
|
|
const offsetHeight = element.offsetHeight;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
scrollPosition >= offsetTop &&
|
|
|
|
|
scrollPosition < offsetTop + offsetHeight
|
|
|
|
|
) {
|
|
|
|
|
setActiveSection(section);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.addEventListener("scroll", handleScroll);
|
|
|
|
|
return () => window.removeEventListener("scroll", handleScroll);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Update document direction when language changes
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (i18n.language === "ar") {
|
|
|
|
|
document.documentElement.dir = "rtl";
|
|
|
|
|
document.documentElement.lang = "ar";
|
|
|
|
|
} else {
|
|
|
|
|
document.documentElement.dir = "ltr";
|
|
|
|
|
document.documentElement.lang = i18n.language;
|
|
|
|
|
}
|
|
|
|
|
}, [i18n.language]);
|
|
|
|
|
|
|
|
|
|
const navItems = [
|
|
|
|
|
{ key: "home", label: t("nav.home") },
|
|
|
|
|
{ key: "services", label: t("nav.services") },
|
|
|
|
|
{ key: "about", label: t("nav.about") },
|
|
|
|
|
{ key: "contact", label: t("nav.contact") },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<nav className="bg-white/10 backdrop-blur-lg fixed top-0 w-full z-50 shadow h-14">
|
|
|
|
|
<div className="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto py-2 px-4">
|
|
|
|
|
{/* الشعار */}
|
|
|
|
|
<img
|
|
|
|
|
src="src/assets/TPS-logo.png"
|
|
|
|
|
className="h-8 sm:h-10 md:h-12 transition-all duration-300"
|
|
|
|
|
alt="TPS Logo"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{/* الجانب الأيمن */}
|
|
|
|
|
<div className="flex items-center md:order-2 space-x-1 md:space-x-0 rtl:space-x-reverse relative">
|
2025-12-23 22:00:31 +03:00
|
|
|
<button
|
|
|
|
|
onClick={toggleDarkMode}
|
|
|
|
|
type="button"
|
|
|
|
|
className="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 ml-2 transition-colors duration-200"
|
|
|
|
|
aria-label={isDarkMode ? "Light Mode" : "Dark Mode"}
|
|
|
|
|
title={isDarkMode ? "Light Mode" : "Dark Mode"}
|
|
|
|
|
>
|
|
|
|
|
{isDarkMode ? (
|
|
|
|
|
<svg className="w-5 h-5 text-yellow-500" fill="currentColor" viewBox="0 0 20 20">
|
|
|
|
|
<path fillRule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clipRule="evenodd" />
|
|
|
|
|
</svg>
|
|
|
|
|
) : (
|
|
|
|
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
|
|
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
|
|
|
|
|
</svg>
|
|
|
|
|
)}
|
|
|
|
|
</button>
|
|
|
|
|
|
2025-12-23 17:09:40 +03:00
|
|
|
{/* Language Switcher */}
|
|
|
|
|
<LanguageSwitcher />
|
|
|
|
|
|
|
|
|
|
{/* زر القائمة للجوال */}
|
|
|
|
|
<button
|
|
|
|
|
onClick={toggleMenu}
|
|
|
|
|
type="button"
|
|
|
|
|
className="inline-flex items-center right--30 p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700 ml-2"
|
|
|
|
|
aria-controls="navbar-menu"
|
|
|
|
|
aria-expanded={menuOpen}
|
|
|
|
|
>
|
|
|
|
|
<span className="sr-only">Open main menu</span>
|
|
|
|
|
<svg className="w-5 h-5" viewBox="0 0 17 14" fill="none">
|
|
|
|
|
<path
|
|
|
|
|
d="M1 1h15M1 7h15M1 13h15"
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
strokeWidth="2"
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* روابط الأقسام */}
|
|
|
|
|
<div
|
|
|
|
|
className={`w-full md:flex md:w-auto md:order-1 transition-all duration-300 ease-in-out ${
|
|
|
|
|
menuOpen ? "block" : "hidden"
|
|
|
|
|
}`}
|
|
|
|
|
id="navbar-menu"
|
|
|
|
|
>
|
|
|
|
|
<ul className="flex flex-col md:flex-row bg-white dark:bg-gray-900 md:bg-transparent md:dark:bg-transparent p-4 md:p-0 rounded-lg shadow-md md:shadow-none space-y-2 md:space-y-0 md:space-x-6 mt-4 md:mt-0 divide-y divide-gray-200 md:divide-y-0">
|
|
|
|
|
{navItems.map((item) => (
|
|
|
|
|
<li key={item.key} className="pt-2 md:pt-0">
|
|
|
|
|
<Link
|
|
|
|
|
to={item.key}
|
|
|
|
|
smooth
|
|
|
|
|
duration={500}
|
|
|
|
|
spy={true}
|
|
|
|
|
offset={0}
|
|
|
|
|
onSetActive={() => setActiveSection(item.key)}
|
|
|
|
|
className={`block text-center md:inline cursor-pointer text-lg font-semibold transition duration-200 ${
|
|
|
|
|
activeSection === item.key
|
|
|
|
|
? "text-yellow-500"
|
|
|
|
|
: "text-gray-800 dark:text-white hover:text-yellow-500"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
{item.label}
|
|
|
|
|
</Link>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</nav>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default Navbar;
|