feat(frontend): improve responsive navigation shell

This commit is contained in:
2026-05-01 00:27:03 +03:30
parent bba1be1f71
commit 2aa4b2b4cd
3 changed files with 402 additions and 138 deletions

View File

@@ -19,10 +19,13 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
const { t, lang, setLanguage } = useTranslation()
const { theme, setTheme } = useTheme()
const navigate = useNavigate()
const [showLogoutModal, setShowLogoutModal] = useState(false)
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
const [user, setUser] = useState<any>(null)
const dropdownRef = useRef<HTMLDivElement>(null)
const isFa = lang === "fa"
const isDarkMode =
theme === "dark" ||
@@ -61,6 +64,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
setIsDropdownOpen(false)
}
}
document.addEventListener("mousedown", handleClickOutside)
return () => document.removeEventListener("mousedown", handleClickOutside)
}, [])
@@ -88,6 +92,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
const toggleLanguage = () => {
const newLang = isFa ? "en" : "fa"
if (setLanguage) {
setLanguage(newLang)
} else {
@@ -98,7 +103,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
return (
<>
<header className="sticky top-0 z-50 flex items-center justify-between border-b border-slate-200/80 bg-white/70 px-8 py-6 backdrop-blur-md transition-colors dark:border-slate-800/80 dark:bg-slate-900/70">
<header className="sticky top-0 z-50 flex items-center justify-between border-b border-slate-200/80 bg-white/70 px-4 py-4 backdrop-blur-md transition-colors md:px-8 md:py-6 dark:border-slate-800/80 dark:bg-slate-900/70">
<div className="flex items-center gap-3">
<button
type="button"
@@ -108,19 +113,40 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
>
<Menu className="h-5 w-5" />
</button>
<div className="flex cursor-pointer items-center gap-2" onClick={() => navigate("/")}>
<span className="relative z-20 flex items-center gap-2 text-xl font-bold tracking-tight text-slate-900 dark:text-slate-50">
<Command className="h-7 w-7" />
{t.title || "Qlockify"}
</span>
</div>
<div
className="flex cursor-pointer items-center gap-2"
onClick={() => navigate("/")}
>
<span className="relative z-20 flex items-center gap-2 text-lg font-bold tracking-tight text-slate-900 md:text-xl dark:text-slate-50">
<Command className="h-6 w-6 md:h-7 md:w-7" />
Qlockify.ir
</span>
</div>
</div>
<div className="flex items-center gap-4">
{/* Mobile navbar: theme toggle + notification bell */}
<div className="flex items-center gap-2 md:hidden">
<button
type="button"
onClick={toggleTheme}
className="inline-flex h-9 w-9 items-center justify-center rounded-lg text-slate-600 transition-colors hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800"
title={isDarkMode ? t.lightMode || "Light Mode" : t.darkMode || "Dark Mode"}
>
{isDarkMode ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}
</button>
{user && <NotificationBell />}
</div>
{/* Desktop navbar: keep the old controls here */}
<div className="hidden items-center gap-4 md:flex">
{user && <WorkspaceSelector />}
{user ? (
<>
<NotificationBell />
<div className="relative" ref={dropdownRef}>
<button
onClick={() => setIsDropdownOpen((current) => !current)}
@@ -141,8 +167,10 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
{isDropdownOpen && (
<div
dir="rtl"
className={`absolute ${isFa ? "left-0" : "right-0"} z-50 mt-2 w-56 overflow-hidden rounded-lg border border-slate-200 bg-white py-2 shadow-lg ring-1 ring-black ring-opacity-5 dark:border-slate-800 dark:bg-slate-900`}
dir={isFa ? "rtl" : "ltr"}
className={`absolute ${
isFa ? "left-0" : "right-0"
} z-50 mt-2 w-56 overflow-hidden rounded-lg border border-slate-200 bg-white py-2 shadow-lg ring-1 ring-black ring-opacity-5 dark:border-slate-800 dark:bg-slate-900`}
>
<div className="mb-2 border-b border-slate-100 px-4 py-2 dark:border-slate-800">
<p className="truncate text-sm font-semibold text-slate-800 dark:text-slate-400">
@@ -151,6 +179,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
: user.email}
</p>
</div>
<button
onClick={() => {
navigate("/profile")
@@ -166,8 +195,16 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
onClick={toggleTheme}
className="flex w-full items-center gap-3 px-4 py-2.5 text-sm text-slate-700 transition-colors hover:bg-slate-100 dark:text-slate-200 dark:hover:bg-slate-800"
>
{isDarkMode ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
<span>{isDarkMode ? (t.lightMode || "Light Mode") : (t.darkMode || "Dark Mode")}</span>
{isDarkMode ? (
<Sun className="h-4 w-4" />
) : (
<Moon className="h-4 w-4" />
)}
<span>
{isDarkMode
? t.lightMode || "Light Mode"
: t.darkMode || "Dark Mode"}
</span>
</button>
<button
@@ -178,7 +215,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
<span>{isFa ? "English" : "فارسی"}</span>
</button>
<div className="my-1 h-px bg-slate-200 dark:bg-slate-800"></div>
<div className="my-1 h-px bg-slate-200 dark:bg-slate-800" />
<button
onClick={() => {
@@ -197,6 +234,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
) : (
<>
<SettingsMenu />
<Button
onClick={() => navigate("/auth")}
className="bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-700"
@@ -210,7 +248,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
{showLogoutModal && (
<div
className="fixed inset-0 z-60 flex items-center justify-center bg-black/50 px-4"
className="fixed inset-0 z-[80] flex items-center justify-center bg-black/50 px-4"
onClick={() => setShowLogoutModal(false)}
>
<div
@@ -220,9 +258,12 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
<h2 className="mb-2 text-lg font-bold text-slate-900 dark:text-white">
{t.confirmLogoutTitle || "Confirm Logout"}
</h2>
<p className="mb-6 text-slate-600 dark:text-slate-400">
{t.confirmLogoutMessage || "Are you sure you want to log out of your account?"}
{t.confirmLogoutMessage ||
"Are you sure you want to log out of your account?"}
</p>
<div className="flex justify-end gap-3">
<Button
variant="outline"
@@ -231,6 +272,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
>
{t.actions?.cancel || "Cancel"}
</Button>
<Button
variant="destructive"
onClick={handleLogout}
@@ -244,4 +286,4 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
)}
</>
)
}
}