feat(nav): add full-width mobile glass dock

This commit is contained in:
2026-10-01 14:52:09 +03:30
parent 4d17066939
commit e45f647c1d
5 changed files with 45 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
import type { Metadata } from "next";
import type { Metadata, Viewport } from "next";
import localFont from "next/font/local";
import { Suspense } from "react";
import MobileBottomNav from "@/components/MobileBottomNav";
@@ -18,6 +18,12 @@ const vazirmatn = localFont({
fallback: ["Tahoma", "Arial", "sans-serif"],
});
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
viewportFit: "cover",
};
export async function generateMetadata(): Promise<Metadata> {
const siteContent = await getCmsSiteContent();
const title = siteContent.seo.title || siteContent.official_name;
@@ -61,7 +67,7 @@ export default async function RootLayout({
<RouteProgress />
</Suspense>
<Navbar siteContent={siteContent} />
<div className="flex min-h-[calc(100svh-4.5rem)] flex-1 flex-col pb-28 md:pb-0">
<div className="flex min-h-[calc(100svh-4.5rem)] flex-1 flex-col pb-[calc(5.5rem+env(safe-area-inset-bottom))] md:pb-0">
<div id="main-content" tabIndex={-1} className="flex-1 outline-none">
{children}
</div>

View File

@@ -28,7 +28,7 @@ export default function Footer({ siteContent }: { siteContent: SiteContent }) {
].filter((contact) => contact !== null);
return (
<footer className="bg-footer text-footer-foreground" dir="rtl">
<footer className="bg-footer pb-[calc(5.5rem+env(safe-area-inset-bottom))] text-footer-foreground md:pb-0" dir="rtl">
<div className="container mx-auto px-4 py-10 md:py-12">
<div className="grid gap-9 sm:grid-cols-2 lg:grid-cols-[1.5fr_0.8fr_1fr]">
<div className="space-y-4">

View File

@@ -63,13 +63,10 @@ export default function MobileBottomNav({ siteContent }: { siteContent: SiteCont
];
return (
<div
className="fixed inset-x-0 z-50 px-4 md:hidden"
style={{ bottom: "calc(env(safe-area-inset-bottom) + 0.9rem)" }}
>
<div className="fixed inset-x-0 bottom-0 z-50 md:hidden">
<nav
aria-label="ناوبری اصلی موبایل"
className="mx-auto flex w-full max-w-md items-center justify-between rounded-2xl border border-border bg-background/95 px-1.5 py-1.5 shadow-lg backdrop-blur-xl"
className="mobile-bottom-nav flex w-full items-stretch justify-around px-2 pt-2 pb-[calc(env(safe-area-inset-bottom)+0.5rem)]"
dir="rtl"
>
{items.map((item) => {
@@ -81,14 +78,21 @@ export default function MobileBottomNav({ siteContent }: { siteContent: SiteCont
key={item.key}
to={item.href}
className={cn(
"flex min-h-11 min-w-0 flex-1 flex-col items-center justify-center gap-0.5 rounded-xl px-1 py-1.5 text-[10px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"relative flex min-h-[4.25rem] min-w-0 flex-1 flex-col items-center justify-center gap-1 rounded-xl px-1 pt-2 pb-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
active
? "bg-secondary text-primary"
: "text-muted-foreground hover:bg-secondary hover:text-foreground",
? "text-primary"
: "text-foreground/75 hover:text-foreground",
)}
aria-current={active ? "page" : undefined}
>
<Icon aria-hidden="true" className="h-4 w-4" />
<span
aria-hidden="true"
className={cn(
"absolute top-0.5 h-0.5 w-5 rounded-full transition-colors",
active ? "bg-primary" : "bg-transparent",
)}
/>
<Icon aria-hidden="true" className="h-6 w-6 shrink-0" />
<span className="max-w-full truncate">{item.label}</span>
</Link>
);

View File

@@ -120,7 +120,7 @@ export default function Navbar({ siteContent }: { siteContent: SiteContent }) {
return (
<nav
aria-label="ناوبری اصلی"
className="sticky top-0 z-40 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/85"
className="sticky top-0 z-40 border-b border-border bg-background/95 pt-[env(safe-area-inset-top)] backdrop-blur supports-[backdrop-filter]:bg-background/85 md:pt-0"
dir="rtl"
>
<div className="container mx-auto px-4 py-2">

View File

@@ -127,6 +127,28 @@ All colors MUST be HSL.
@apply bg-background font-sans text-foreground;
}
.mobile-bottom-nav {
border-top: 1px solid hsl(var(--border) / 0.7);
background-color: hsl(var(--background) / 0.82);
box-shadow: 0 -0.75rem 2rem hsl(var(--foreground) / 0.08);
-webkit-backdrop-filter: blur(1.25rem) saturate(1.35);
backdrop-filter: blur(1.25rem) saturate(1.35);
}
@supports not (backdrop-filter: blur(1px)) {
.mobile-bottom-nav {
background-color: hsl(var(--background));
}
}
@media (prefers-reduced-transparency: reduce) {
.mobile-bottom-nav {
background-color: hsl(var(--background));
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
}
:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 3px;