feat: responsive app navbar

This commit is contained in:
mehedi-hasan 2024-04-09 16:38:46 +06:00
parent c6dcd75b84
commit ecaa606342
4 changed files with 269 additions and 1 deletions

View File

@ -0,0 +1,144 @@
"use client";
import * as React from "react";
import Link, { LinkProps } from "next/link";
import { useRouter } from "next/navigation";
import { cn } from "@/lib/utils";
import { Icons } from "@/components/icons";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { appNavItems, navItems } from "@/constants/data";
import { Button } from "./ui/button";
import { ScrollArea } from "./ui/scroll-area";
import { NavItem } from "@/types";
import { AlignRight } from "lucide-react";
const mobileNavMenu: NavItem[] = [
{
title: "Courses",
href: "#",
icon: "dashboard",
label: "Courses",
},
{
title: "Career Paths",
href: "#",
icon: "shieldQuestion",
label: "Career Paths",
},
{
title: "Community",
href: "#",
icon: "shieldQuestion",
label: "Community",
},
{
title: "Pricing",
href: "/pricing",
icon: "profile",
label: "Pricing",
},
];
export function MobileNav() {
const [open, setOpen] = React.useState(false);
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button
variant="ghost"
className="mr-2 px-0 text-base hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 md:hidden"
>
<AlignRight />
<span className="sr-only">Toggle Menu</span>
</Button>
</SheetTrigger>
<SheetContent side="right" className="pr-0">
<MobileLink
href="/"
className="flex items-center"
onOpenChange={setOpen}
>
<Icons.logo className="mr-2 h-4 w-4" />
<span className="font-bold">Skilld</span>
</MobileLink>
<ScrollArea className="my-4 h-[calc(100vh-8rem)] pb-10 pl-6">
<div className="flex flex-col space-y-3">
{appNavItems.mainNav.map(
(item) =>
item.href && (
<MobileLink
key={item.href}
href={item.href}
onOpenChange={setOpen}
>
{item.title}
</MobileLink>
),
)}
</div>
<div className="flex flex-col space-y-2">
{appNavItems.sidebarNav.map((item, index) => (
<div key={index} className="flex flex-col space-y-3 pt-6">
<h4 className="font-medium">{item.title}</h4>
{item?.items?.length &&
item.items.map((item) => (
<React.Fragment key={item.href}>
{!item.disabled &&
(item.href ? (
<MobileLink
href={item.href}
onOpenChange={setOpen}
className="text-muted-foreground"
>
{item.title}
{item.label && (
<span className="ml-2 rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000] no-underline group-hover:no-underline">
{item.label}
</span>
)}
</MobileLink>
) : (
item.title
))}
</React.Fragment>
))}
</div>
))}
</div>
</ScrollArea>
</SheetContent>
</Sheet>
);
}
interface MobileLinkProps extends LinkProps {
onOpenChange?: (open: boolean) => void;
children: React.ReactNode;
className?: string;
}
function MobileLink({
href,
onOpenChange,
className,
children,
...props
}: MobileLinkProps) {
const router = useRouter();
return (
<Link
href={href}
onClick={() => {
router.push(href.toString());
onOpenChange?.(false);
}}
className={cn(className)}
{...props}
>
{children}
</Link>
);
}

View File

@ -16,6 +16,17 @@ import {
} from "@/components/ui/navigation-menu";
import ThemeToggle from "./layout/ThemeToggle/theme-toggle";
import { buttonVariants } from "./ui/button";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
import { AlignRight } from "lucide-react";
import { NavItem } from "@/types";
import { MobileNav } from "./mobile-nav";
const careerPaths: { title: string; href: string; description: string }[] = [
{
@ -56,6 +67,8 @@ const careerPaths: { title: string; href: string; description: string }[] = [
},
];
export default function Navbar() {
return (
<header className="border-b py-3">
@ -64,7 +77,7 @@ export default function Navbar() {
<h2 className="text-xl font-bold">Skilld</h2>
</Link>
<div className="flex gap-8 items-center">
<div className="hidden md:flex gap-8 items-center">
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
@ -145,6 +158,23 @@ export default function Navbar() {
</Link>
<ThemeToggle />
</div>
<div className="md:hidden">
<MobileNav/>
{/* <Sheet>
<SheetTrigger>
<AlignRight />
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Skilld</SheetTitle>
</SheetHeader>
<div>
</div>
</SheetContent>
</Sheet> */}
</div>
</div>
</header>
);

View File

@ -1,4 +1,5 @@
import { NavItem } from "@/types";
import { MainNavItem, SidebarNavItem } from "@/types/nav";
export type User = {
id: number;
@ -131,3 +132,78 @@ export const questions = [
isNiche: false,
},
];
interface AppNavItem {
mainNav: MainNavItem[];
sidebarNav: SidebarNavItem[];
}
export const appNavItems: AppNavItem = {
mainNav: [
{
title: "Pricing",
href: "/pricing",
},
{
title: "Community",
href: "#",
},
],
sidebarNav: [
{
title: "Courses",
items: [
{
title: "Python Programming",
href: "#",
items: [],
},
{
title: "Web Dev With ReactJS",
href: "#",
items: [],
},
{
title: "Machine Learning Fundamentals",
href: "#",
items: [],
},
],
},
{
title: "Career Paths",
items: [
{
title: "Frontend Developer",
href: "#",
items: [],
},
{
title: "Backend Developer",
href: "#",
items: [],
},
{
title: "Full Stack Developer",
href: "#",
items: [],
},
{
title: "Mobile App Developer",
href: "#",
items: [],
},
{
title: "Game Developer",
href: "#",
items: [],
},
{
title: "Machine Learning Developer",
href: "#",
items: [],
},
],
},
],
};

18
src/types/nav.ts Normal file
View File

@ -0,0 +1,18 @@
import { Icons } from "@/components/icons"
export interface NavItem {
title: string
href?: string
disabled?: boolean
external?: boolean
icon?: keyof typeof Icons
label?: string
}
export interface NavItemWithChildren extends NavItem {
items: NavItemWithChildren[]
}
export interface MainNavItem extends NavItem {}
export interface SidebarNavItem extends NavItemWithChildren {}