Skip to content

Commit

Permalink
feat(saas): Mobile responsive app sidenav
Browse files Browse the repository at this point in the history
  • Loading branch information
alifarooq9 committed May 6, 2024
1 parent 9f1df73 commit 358da4f
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 17 deletions.
2 changes: 1 addition & 1 deletion starterkits/saas/src/app/(app)/(user)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function DashboardPage() {
description={dashboardPageConfig.description}
>
<div className="grid gap-6">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Expand Down
25 changes: 25 additions & 0 deletions starterkits/saas/src/app/(app)/_components/app-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { MobileSidenav } from "@/app/(app)/_components/mobile-sidenav";
import { Icons } from "@/components/ui/icons";

type AppHeaderProps = {
sidebarNavIncludeIds?: string[];
sidebarNavRemoveIds?: string[];
showOrgSwitcher?: boolean;
};

export function AppHeader({
sidebarNavIncludeIds,
sidebarNavRemoveIds,
showOrgSwitcher,
}: AppHeaderProps) {
return (
<header className="sticky top-0 flex h-14 items-center gap-4 border-b border-border bg-background">
<MobileSidenav
showOrgSwitcher={showOrgSwitcher}
sidebarNavIncludeIds={sidebarNavIncludeIds}
sidebarNavRemoveIds={sidebarNavRemoveIds}
/>
<Icons.logo hideTextOnMobile={false} />
</header>
);
}
10 changes: 9 additions & 1 deletion starterkits/saas/src/app/(app)/_components/layout-shell.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AppHeader } from "@/app/(app)/_components/app-header";
import { Sidebar, SidebarLoading } from "@/app/(app)/_components/sidebar";
import { Suspense } from "react";

Expand Down Expand Up @@ -26,7 +27,7 @@ export function AppLayoutShell({
}: AppLayoutProps) {
return (
<div className="container flex items-start gap-8">
<div className="sticky left-0 top-0 hidden h-screen w-52 flex-shrink-0 md:block lg:w-60 ">
<div className="sticky left-0 top-0 hidden h-screen w-52 flex-shrink-0 lg:block xl:w-60 ">
<Suspense fallback={<SidebarLoading />}>
<Sidebar
sidebarNavIncludeIds={sideNavIncludedIds}
Expand All @@ -36,6 +37,13 @@ export function AppLayoutShell({
</Suspense>
</div>
<section className="min-h-screen w-full flex-grow">
<div className="block lg:hidden">
<AppHeader
showOrgSwitcher={showOrgSwitcher}
sidebarNavIncludeIds={sideNavIncludedIds}
sidebarNavRemoveIds={sideNavRemoveIds}
/>
</div>
{children}
</section>
</div>
Expand Down
35 changes: 35 additions & 0 deletions starterkits/saas/src/app/(app)/_components/mobile-sidenav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Sidebar } from "@/app/(app)/_components/sidebar";
import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { MenuIcon } from "lucide-react";

type MobileSideNavProps = {
sidebarNavIncludeIds?: string[];
sidebarNavRemoveIds?: string[];
showOrgSwitcher?: boolean;
};

export function MobileSidenav({
showOrgSwitcher,
sidebarNavIncludeIds,
sidebarNavRemoveIds,
}: MobileSideNavProps) {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="outline" size="iconSmall">
<MenuIcon className="h-4 w-4" />
<p className="sr-only">Open menu</p>
</Button>
</SheetTrigger>
<SheetContent side="left" className="px-3 pb-20 pt-10">
<Sidebar
showLogo={false}
showOrgSwitcher={showOrgSwitcher}
sidebarNavIncludeIds={sidebarNavIncludeIds}
sidebarNavRemoveIds={sidebarNavRemoveIds}
/>
</SheetContent>
</Sheet>
);
}
30 changes: 18 additions & 12 deletions starterkits/saas/src/app/(app)/_components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type SideNavProps = {
sidebarNavIncludeIds?: string[];
sidebarNavRemoveIds?: string[];
showOrgSwitcher?: boolean;
showLogo?: boolean;
};

/**
Expand All @@ -31,6 +32,7 @@ export async function Sidebar({
sidebarNavIncludeIds,
sidebarNavRemoveIds,
showOrgSwitcher = true,
showLogo = true,
}: SideNavProps) {
const user = await getUser();

Expand All @@ -52,17 +54,21 @@ export async function Sidebar({

return (
<aside className={cn("h-full w-full")}>
<div className={cn(" flex h-16 items-center justify-between")}>
<Link
href={siteUrls.dashboard.home}
className={cn("z-10 transition-transform hover:scale-90")}
>
<Icons.logo
className="text-xl"
iconProps={{ className: "w-6 h-6 fill-primary" }}
/>
</Link>
</div>
{showLogo && (
<div className={cn("flex h-16 items-center justify-between")}>
<Link
href={siteUrls.dashboard.home}
className={cn(
"z-10 transition-transform hover:scale-90",
)}
>
<Icons.logo
className="text-xl"
iconProps={{ className: "w-6 h-6 fill-primary" }}
/>
</Link>
</div>
)}

<div className="py-2">
<UserDropdown user={user} />
Expand All @@ -78,7 +84,7 @@ export async function Sidebar({
)}

<ScrollArea style={{ height: "calc(100vh - 10.5rem)" }}>
<div className="h-full w-full py-2">
<div className="h-full w-full py-2 pb-10">
<SidebarNav
sidebarNavIncludeIds={sidebarNavIncludeIds}
sidebarNavRemoveIds={sidebarNavRemoveIds}
Expand Down
2 changes: 1 addition & 1 deletion starterkits/saas/src/app/(web)/_components/mobile-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function MobileNav() {
</SheetTrigger>
<SheetContent side="left">
<SheetHeader>
<Icons.logo />
<Icons.logo hideTextOnMobile={false} />
</SheetHeader>
<ul className="space-y-3 py-8">
<li onClick={() => setIsOpen(false)}>
Expand Down
12 changes: 10 additions & 2 deletions starterkits/saas/src/components/ui/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ export const Icons = {
iconProps,
as,
className,
hideTextOnMobile = true,
}: {
iconProps?: IconProps;
as?: ElementType;
className?: string;
hideTextOnMobile?: boolean;
}) => {
const Comp = as ?? "div";
return (
Expand All @@ -22,12 +24,18 @@ export const Icons = {
>
<Icons.logoIcon
className={cn(
"h-6 w-6 fill-primary sm:h-5 sm:w-5",
"fill-primary",
iconProps?.className,
hideTextOnMobile ? "h-6 w-6 sm:h-5 sm:w-5" : "h-5 w-5",
)}
{...iconProps}
/>
<span className="hidden font-bold sm:block">
<span
className={cn(
"font-bold",
hideTextOnMobile && "hidden sm:block",
)}
>
{siteConfig.name}
</span>
</Comp>
Expand Down

0 comments on commit 358da4f

Please sign in to comment.