mirror of
https://gitlab.massbug.com/massbug/judge4c.git
synced 2025-07-04 09:41:34 +00:00
feat(dashboard): refactor layout and remove unused components, integrate new sidebar and breadcrumb structure
This commit is contained in:
parent
e41b1e4590
commit
dc42896efe
@ -1,26 +1,49 @@
|
||||
import { Navbar } from "@/components/navbar";
|
||||
import { Sidebar } from "@/components/sidebar";
|
||||
import {
|
||||
SidebarInset,
|
||||
SidebarProvider,
|
||||
SidebarTrigger,
|
||||
} from "@/components/ui/sidebar";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { AppSidebar } from "@/components/app-sidebar";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
|
||||
interface DashboardLayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const DashboardLayout = ({ children }: DashboardLayoutProps) => {
|
||||
export default function DashboardLayout({ children }: DashboardLayoutProps) {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<div className="flex w-full h-full">
|
||||
<div className="fixed left-0 top-0 hidden lg:block lg:w-[264px] h-full overflow-y-auto">
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div className="lg:pl-[264px] w-full">
|
||||
<div className="mx-auto max-w-screen-2xl h-full">
|
||||
<Navbar />
|
||||
<main className="h-full py-8 px-6 flex flex-col">{children}</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SidebarProvider>
|
||||
<AppSidebar />
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12">
|
||||
<div className="flex items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<Separator orientation="vertical" className="mr-2 h-4" />
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem className="hidden md:block">
|
||||
<BreadcrumbLink href="#">
|
||||
Building Your Application
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator className="hidden md:block" />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col p-4 pt-0">{children}</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardLayout;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { redirect } from "next/navigation";
|
||||
import { getCurrent } from "@/features/auth/actions";
|
||||
import { CreateWorkspaceForm } from "@/features/workspaces/components/create-workspace-form";
|
||||
|
||||
export default async function HomePage() {
|
||||
export default async function DashboardPage() {
|
||||
const user = await getCurrent();
|
||||
|
||||
if (!user) redirect("/sign-in");
|
||||
|
@ -1,49 +0,0 @@
|
||||
import { AppSidebar } from "@/components/app-sidebar";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import {
|
||||
SidebarInset,
|
||||
SidebarProvider,
|
||||
SidebarTrigger,
|
||||
} from "@/components/ui/sidebar";
|
||||
|
||||
interface DashboardLayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function DashboardLayout({ children }: DashboardLayoutProps) {
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<AppSidebar />
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12">
|
||||
<div className="flex items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<Separator orientation="vertical" className="mr-2 h-4" />
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem className="hidden md:block">
|
||||
<BreadcrumbLink href="#">
|
||||
Building Your Application
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator className="hidden md:block" />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col p-4 pt-0">{children}</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
);
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { getCurrent } from "@/features/auth/actions";
|
||||
import { CreateWorkspaceForm } from "@/features/workspaces/components/create-workspace-form";
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const user = await getCurrent();
|
||||
|
||||
if (!user) redirect("/sign-in");
|
||||
|
||||
return (
|
||||
<div className="h-full p-4">
|
||||
<CreateWorkspaceForm />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Sidebar } from "./sidebar";
|
||||
import { Button } from "./ui/button";
|
||||
import { MenuIcon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Sheet, SheetContent, SheetTrigger } from "./ui/sheet";
|
||||
|
||||
export const MobileSidebar = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
setIsOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<Sheet modal={false} open={isOpen} onOpenChange={setIsOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="secondary" className="lg:hidden">
|
||||
<MenuIcon className="size-4" />
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" className="p-0">
|
||||
<Sidebar />
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
import { UserButton } from "@/features/auth/components/user-button";
|
||||
import { MobileSidebar } from "./mobile-sidebar";
|
||||
|
||||
export const Navbar = () => {
|
||||
return (
|
||||
<nav className="pt-4 px-6 flex items-center justify-between">
|
||||
<div className="flex-col hidden lg:flex">
|
||||
<h1 className="text-2xl font-semibold">Home</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Monitor all of your projects and tasks here
|
||||
</p>
|
||||
</div>
|
||||
<MobileSidebar />
|
||||
<UserButton />
|
||||
</nav>
|
||||
);
|
||||
};
|
@ -1,61 +0,0 @@
|
||||
import {
|
||||
GoHome,
|
||||
GoHomeFill,
|
||||
GoCheckCircle,
|
||||
GoCheckCircleFill,
|
||||
} from "react-icons/go";
|
||||
import Link from "next/link";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { SettingsIcon, UsersIcon } from "lucide-react";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
label: "Home",
|
||||
href: "",
|
||||
icon: GoHome,
|
||||
activeIcon: GoHomeFill,
|
||||
},
|
||||
{
|
||||
label: "My Tasks",
|
||||
href: "/tasks",
|
||||
icon: GoCheckCircle,
|
||||
activeIcon: GoCheckCircleFill,
|
||||
},
|
||||
{
|
||||
label: "Settings",
|
||||
href: "/settings",
|
||||
icon: SettingsIcon,
|
||||
activeIcon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
label: "Members",
|
||||
href: "/members",
|
||||
icon: UsersIcon,
|
||||
activeIcon: UsersIcon,
|
||||
},
|
||||
];
|
||||
|
||||
export const Navigation = () => {
|
||||
return (
|
||||
<ul className="flex flex-col">
|
||||
{routes.map((item) => {
|
||||
const isActive = false;
|
||||
const Icon = isActive ? item.activeIcon : item.icon;
|
||||
|
||||
return (
|
||||
<Link key={item.href} href={item.href}>
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center gap-2.5 p-2.5 rounded-md font-medium hover:text-primary transition",
|
||||
isActive && "shadow-sm hover:opacity-100 text-primary"
|
||||
)}
|
||||
>
|
||||
<Icon className="size-5" />
|
||||
{item.label}
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
};
|
@ -1,23 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { Navigation } from "./navigation";
|
||||
import { Separator } from "./ui/separator";
|
||||
|
||||
export const Sidebar = () => {
|
||||
return (
|
||||
<aside className="h-full p-4 w-full">
|
||||
<Link href="/">
|
||||
<Image
|
||||
src="/logo.svg"
|
||||
alt="logo"
|
||||
width={100}
|
||||
height={50}
|
||||
style={{ width: "auto", height: "auto" }}
|
||||
priority
|
||||
/>
|
||||
</Link>
|
||||
<Separator className="my-4" />
|
||||
<Navigation />
|
||||
</aside>
|
||||
);
|
||||
};
|
@ -1,74 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { useLogout } from "../api/use-logout";
|
||||
import { Loader, LogOut } from "lucide-react";
|
||||
import { useCurrent } from "../api/use-current";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
|
||||
export const UserButton = () => {
|
||||
const { mutate: logout } = useLogout();
|
||||
const { data: user, isLoading } = useCurrent();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="size-10 rounded-full flex items-center justify-center border">
|
||||
<Loader className="size-4 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { name, email } = user;
|
||||
|
||||
const avatarFallback = name
|
||||
? name.charAt(0).toUpperCase()
|
||||
: email.charAt(0).toUpperCase() ?? "U";
|
||||
|
||||
return (
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger className="outline-none relative">
|
||||
<Avatar className="size-10 hover:opacity-75 transition border">
|
||||
<AvatarFallback className="font-medium flex items-center justify-center">
|
||||
{avatarFallback}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
side="bottom"
|
||||
className="w-60"
|
||||
sideOffset={10}
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center gap-2 px-2.5 py-4">
|
||||
<Avatar className="size-[52px] hover:opacity-75 transition border">
|
||||
<AvatarFallback className="text-xl font-medium flex items-center justify-center">
|
||||
{avatarFallback}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<p className="text-sm font-medium">{name || "User"}</p>
|
||||
<p className="text-xs">{email}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Separator className="mb-1" />
|
||||
<DropdownMenuItem
|
||||
onClick={() => logout()}
|
||||
className="h-10 flex items-center justify-center font-medium cursor-pointer"
|
||||
>
|
||||
<LogOut className="size-4 mr-2" />
|
||||
Log out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user