https://dev.kronoz.win/r/marzneshin.git
1import {
2 Header,
3 ResizableHandle,
4 ResizablePanel,
5 ResizablePanelGroup,
6 Toaster,
7 Loading,
8 HeaderLogo,
9 HeaderMenu,
10} from "@marzneshin/common/components";
11import { useAuth } from "@marzneshin/modules/auth";
12import { DashboardSidebar, ToggleButton } from "@marzneshin/features/sidebar";
13import { usePanelToggle } from "@marzneshin/features/sidebar/use-panel-toggle";
14import { useScreenBreakpoint } from "@marzneshin/common/hooks/use-screen-breakpoint";
15import { cn } from "@marzneshin/common/utils";
16import { Suspense } from "react";
17import {
18 Outlet,
19 Link,
20 createFileRoute,
21 redirect
22} from "@tanstack/react-router";
23import { useGithubRepoStatsQuery, GithubRepo } from "@marzneshin/features/github-repo";
24import { CommandBox } from "@marzneshin/features/search-command";
25import { DashboardBottomMenu } from "@marzneshin/features/bottom-menu";
26
27export const DashboardLayout = () => {
28 const isDesktop = useScreenBreakpoint("md");
29 const {
30 collapsed,
31 panelRef,
32 setCollapsed,
33 toggleCollapse,
34 } = usePanelToggle(isDesktop);
35 const { isSudo } = useAuth();
36 const { data: stats } = useGithubRepoStatsQuery()
37
38 return (
39 <div className="flex flex-col w-screen h-screen">
40 <Header
41 start={
42 <>
43 <Link to="/">
44 <HeaderLogo />
45 </Link>
46 {isDesktop && (
47
48 <ToggleButton
49 collapsed={collapsed}
50 onToggle={toggleCollapse}
51 />
52 )}
53 </>
54 }
55 center={<CommandBox />}
56 end={
57 <>
58 <GithubRepo {...stats} variant={isDesktop ? "full" : "mini"} />
59 <HeaderMenu />
60 </>
61 }
62 />
63 <div className="flex flex-1 overflow-hidden">
64 {isDesktop ? (
65 <ResizablePanelGroup direction="horizontal" className="flex h-full w-full">
66 <ResizablePanel
67 collapsible
68 collapsedSize={2}
69 onCollapse={() => setCollapsed(true)}
70 onExpand={() => setCollapsed(false)}
71 minSize={15}
72 className={cn("w-[120px] min-w-[70px]")}
73 defaultSize={20}
74 ref={panelRef}
75 maxSize={30}
76 >
77 <DashboardSidebar
78 collapsed={collapsed}
79 setCollapsed={setCollapsed}
80 />
81 </ResizablePanel>
82 <ResizableHandle withHandle className="w-[2px]" />
83 <ResizablePanel className="flex flex-col h-full">
84 <main className="flex-grow flex flex-col overflow-y-auto">
85 <Suspense fallback={<Loading />}>
86 <Outlet />
87 </Suspense>
88 </main>
89 </ResizablePanel>
90 </ResizablePanelGroup>
91 ) : (
92 <div className="flex flex-col h-full w-full">
93 <main className="flex flex-col h-full overflow-y-auto">
94 <Suspense fallback={<Loading />}>
95 <Outlet />
96 </Suspense>
97 <footer className="h-30 border-t-3 shrink-0 py-2 px-5">
98 <DashboardBottomMenu variant={isSudo() ? "sudo-admin" : "admin"} />
99 </footer>
100 </main>
101 </div>
102 )}
103 </div>
104 <Toaster position="top-center" />
105 </div>
106 );
107};
108
109export const Route = createFileRoute("/_dashboard")({
110 component: () => <DashboardLayout />,
111 beforeLoad: async () => {
112 const loggedIn = await useAuth.getState().isLoggedIn();
113 if (!loggedIn) {
114 throw redirect({
115 to: "/login",
116 });
117 }
118 },
119});