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