feat(frontend): improve responsive navigation shell
This commit is contained in:
@@ -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) {
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user