feat(frontend): add mobile bottom nav and redesign profile
This commit is contained in:
99
src/components/MobileBottomNav.tsx
Normal file
99
src/components/MobileBottomNav.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
"use client";
|
||||
|
||||
import type { ComponentType } from "react";
|
||||
import { CalendarDays, CircleUserRound, Home, Newspaper } from "lucide-react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useAuth } from "@/contexts/AuthContext";
|
||||
import { Link } from "@/lib/router";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type NavItem = {
|
||||
key: string;
|
||||
label: string;
|
||||
href: string;
|
||||
icon: ComponentType<{ className?: string }>;
|
||||
matches: (pathname: string) => boolean;
|
||||
};
|
||||
|
||||
const isProfileOrAuthPath = (pathname: string) =>
|
||||
pathname === "/profile" ||
|
||||
pathname.startsWith("/profile/") ||
|
||||
pathname === "/auth" ||
|
||||
pathname.startsWith("/auth/") ||
|
||||
pathname.startsWith("/reset-password") ||
|
||||
pathname.startsWith("/verify-email");
|
||||
|
||||
export default function MobileBottomNav() {
|
||||
const pathname = usePathname() || "/";
|
||||
const { isAuthenticated } = useAuth();
|
||||
|
||||
if (pathname.startsWith("/admin") || pathname === "/logout") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const items: NavItem[] = [
|
||||
{
|
||||
key: "home",
|
||||
label: "خانه",
|
||||
href: "/",
|
||||
icon: Home,
|
||||
matches: (current) => current === "/",
|
||||
},
|
||||
{
|
||||
key: "events",
|
||||
label: "رویدادها",
|
||||
href: "/events",
|
||||
icon: CalendarDays,
|
||||
matches: (current) => current === "/events" || current.startsWith("/events/"),
|
||||
},
|
||||
{
|
||||
key: "blog",
|
||||
label: "بلاگ",
|
||||
href: "/blog",
|
||||
icon: Newspaper,
|
||||
matches: (current) => current === "/blog" || current.startsWith("/blog/"),
|
||||
},
|
||||
{
|
||||
key: "account",
|
||||
label: isAuthenticated ? "پروفایل" : "حساب",
|
||||
href: isAuthenticated ? "/profile" : "/auth",
|
||||
icon: CircleUserRound,
|
||||
matches: isProfileOrAuthPath,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-x-0 z-50 px-4 md:hidden"
|
||||
style={{ bottom: "calc(env(safe-area-inset-bottom) + 0.9rem)" }}
|
||||
>
|
||||
<nav
|
||||
aria-label="Mobile navigation"
|
||||
className="mx-auto flex w-full max-w-sm items-center justify-between rounded-[1.75rem] border border-white/20 bg-background/70 px-2 py-2 shadow-[0_18px_60px_rgba(15,23,42,0.18)] backdrop-blur-2xl dark:border-white/10 dark:bg-slate-950/65"
|
||||
dir="rtl"
|
||||
>
|
||||
{items.map((item) => {
|
||||
const active = item.matches(pathname);
|
||||
const Icon = item.icon;
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={item.key}
|
||||
to={item.href}
|
||||
className={cn(
|
||||
"flex min-w-0 flex-1 flex-col items-center justify-center gap-1 rounded-2xl px-2 py-2 text-[11px] font-medium transition-all",
|
||||
active
|
||||
? "bg-primary text-primary-foreground shadow-sm"
|
||||
: "text-muted-foreground hover:bg-white/30 hover:text-foreground dark:hover:bg-white/10",
|
||||
)}
|
||||
aria-current={active ? "page" : undefined}
|
||||
>
|
||||
<Icon className={cn("h-5 w-5", active ? "scale-105" : "")} />
|
||||
<span>{item.label}</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user