feat(admin): add MobileTabBar with 4 primary tabs + More trigger
This commit is contained in:
@@ -0,0 +1,94 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Link from "next/link";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import MoreSheet from "@/components/admin/MoreSheet";
|
||||||
|
|
||||||
|
const TABS = [
|
||||||
|
{ label: "Home", href: "/admin/v2", icon: HomeIcon },
|
||||||
|
{ label: "Orders", href: "/admin/v2/orders", icon: OrdersIcon },
|
||||||
|
{ label: "Stops", href: "/admin/v2/stops", icon: StopsIcon },
|
||||||
|
{ label: "Products", href: "/admin/v2/products", icon: ProductsIcon },
|
||||||
|
];
|
||||||
|
|
||||||
|
function HomeIcon({ active }: { active: boolean }) {
|
||||||
|
return (
|
||||||
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={active ? 2.5 : 2}>
|
||||||
|
<path d="M3 12L12 3l9 9M5 10v10h14V10" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function OrdersIcon({ active }: { active: boolean }) {
|
||||||
|
return (
|
||||||
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={active ? 2.5 : 2}>
|
||||||
|
<path d="M3 3h2l2 13h12l2-9H6" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
<circle cx="9" cy="20" r="1.5" /><circle cx="18" cy="20" r="1.5" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function StopsIcon({ active }: { active: boolean }) {
|
||||||
|
return (
|
||||||
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={active ? 2.5 : 2}>
|
||||||
|
<path d="M12 22s8-7.5 8-13a8 8 0 10-16 0c0 5.5 8 13 8 13z" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
<circle cx="12" cy="9" r="2.5" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function ProductsIcon({ active }: { active: boolean }) {
|
||||||
|
return (
|
||||||
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={active ? 2.5 : 2}>
|
||||||
|
<path d="M3 7l9-4 9 4v10l-9 4-9-4V7z" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
<path d="M3 7l9 4 9-4M12 11v10" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MobileTabBar() {
|
||||||
|
const pathname = usePathname();
|
||||||
|
const [moreOpen, setMoreOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<nav
|
||||||
|
aria-label="Primary"
|
||||||
|
className="fixed bottom-0 left-0 right-0 z-30 grid grid-cols-5 border-t"
|
||||||
|
style={{
|
||||||
|
height: "60px",
|
||||||
|
backgroundColor: "var(--color-bg)",
|
||||||
|
borderColor: "var(--color-surface-3)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{TABS.map((tab) => {
|
||||||
|
const active = pathname === tab.href || pathname?.startsWith(tab.href + "/");
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={tab.href}
|
||||||
|
href={tab.href}
|
||||||
|
className="flex flex-col items-center justify-center gap-0.5 active:scale-95 transition-transform"
|
||||||
|
style={{ color: active ? "var(--color-accent)" : "var(--color-text-muted)" }}
|
||||||
|
>
|
||||||
|
<tab.icon active={active} />
|
||||||
|
<span className="text-[12px] font-semibold" style={{ letterSpacing: "0.02em" }}>{tab.label}</span>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setMoreOpen(true)}
|
||||||
|
className="flex flex-col items-center justify-center gap-0.5 active:scale-95 transition-transform"
|
||||||
|
style={{ color: "var(--color-text-muted)" }}
|
||||||
|
aria-label="Open more menu"
|
||||||
|
>
|
||||||
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<circle cx="5" cy="12" r="2" /><circle cx="12" cy="12" r="2" /><circle cx="19" cy="12" r="2" />
|
||||||
|
</svg>
|
||||||
|
<span className="text-[12px] font-semibold" style={{ letterSpacing: "0.02em" }}>More</span>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
<MoreSheet open={moreOpen} onClose={() => setMoreOpen(false)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MobileTabBar;
|
||||||
Reference in New Issue
Block a user