diff --git a/dashboard/src/components/sidebar/sidebar-item.tsx b/dashboard/src/components/sidebar/sidebar-item.tsx index 4a132ae..07e474a 100644 --- a/dashboard/src/components/sidebar/sidebar-item.tsx +++ b/dashboard/src/components/sidebar/sidebar-item.tsx @@ -1,38 +1,50 @@ - -import { Link } from '@tanstack/react-router' -import { FC } from 'react' -import { SidebarItem as SidebarItemType } from './types' -import { cn } from '@marzneshin/utils'; -import { VariantProps, cva } from 'class-variance-authority'; -import { useSidebarContext } from './sidebar-provider'; +import { Link } from "@tanstack/react-router"; +import type { FC } from "react"; +import type { SidebarItem as SidebarItemType } from "./types"; +import { cn } from "@marzneshin/utils"; +import { type VariantProps, cva } from "class-variance-authority"; +import { useSidebarContext } from "./sidebar-provider"; const sidebarItemVariants = cva("w-full rounded-lg border p-2", { variants: { variant: { default: "bg-primary-foreground text-primary hover:bg-accent", - active: "bg-primary text-primary-foreground" + active: "bg-primary text-primary-foreground", }, size: { default: "", - collapsed: "" - } - } + collapsed: "", + }, + }, }); - -export interface SidebarItemProps extends - React.HTMLAttributes, +export interface SidebarItemProps + extends React.HTMLAttributes, VariantProps { item: SidebarItemType; } -export const SidebarItem: FC = ({ item, className, variant }) => { - const { collapsed } = useSidebarContext(); +export const SidebarItem: FC = ({ + item, + className, + variant, +}) => { + const { collapsed, setOpen } = useSidebarContext(); return ( -
  • - - {item.icon}{!collapsed && item.title} +
  • + setOpen?.(false)} + className={cn("flex flex-row items-center justify-center", { + "-justify-center gap-2": !collapsed, + })} + > + {item.icon} + {!collapsed && item.title}
  • - ) -} + ); +}; diff --git a/dashboard/src/components/sidebar/sidebar-provider.tsx b/dashboard/src/components/sidebar/sidebar-provider.tsx index 67ef4d6..317d33e 100644 --- a/dashboard/src/components/sidebar/sidebar-provider.tsx +++ b/dashboard/src/components/sidebar/sidebar-provider.tsx @@ -1,10 +1,12 @@ import { createContext, useContext } from "react"; -import { SidebarItemGroup } from "./types"; +import type { SidebarItemGroup } from "./types"; interface SidebarContextProps { sidebar: SidebarItemGroup; collapsed: boolean; setCollapsed: (state: boolean) => void; + open?: boolean; + setOpen?: (state: boolean) => void; } export const SidebarContext = createContext(null); @@ -12,6 +14,8 @@ export const SidebarContext = createContext(null); export const useSidebarContext = () => { const ctx = useContext(SidebarContext); if (!ctx) - throw new Error('Sidebar.* component must be rendered as child of Sidebar '); + throw new Error( + "Sidebar.* component must be rendered as child of Sidebar ", + ); return ctx; -} +}; diff --git a/dashboard/src/components/sidebar/sidebar.tsx b/dashboard/src/components/sidebar/sidebar.tsx index d8a35ef..87b6447 100644 --- a/dashboard/src/components/sidebar/sidebar.tsx +++ b/dashboard/src/components/sidebar/sidebar.tsx @@ -1,7 +1,8 @@ -import { FC, PropsWithChildren } from "react"; -import { SidebarContext } from "./sidebar-provider" -import { SidebarItemGroup } from "./types" -import { VariantProps, cva } from "class-variance-authority" +import type { FC, PropsWithChildren } from "react"; +import { useMemo } from "react"; +import { SidebarContext } from "./sidebar-provider"; +import type { SidebarItemGroup } from "./types"; +import { type VariantProps, cva } from "class-variance-authority"; import { cn } from "@marzneshin/utils"; import { SidebarHeader } from "./sidebar-header"; import { SidebarFooter } from "./sidebar-footer"; @@ -10,45 +11,60 @@ import { SidebarItem } from "./sidebar-item"; import { SidebarGroup } from "./sidebar-group"; const sidebarVariants = cva("flex flex-col justify-between h-full w-full", { - variants: { - variant: { - default: "" - } - } + variants: { + variant: { + default: "", + }, + }, }); interface ContentComposition { - Header: typeof SidebarHeader; - Footer: typeof SidebarFooter; - Body: typeof SidebarBody; - Group: typeof SidebarGroup; - Item: typeof SidebarItem; + Header: typeof SidebarHeader; + Footer: typeof SidebarFooter; + Body: typeof SidebarBody; + Group: typeof SidebarGroup; + Item: typeof SidebarItem; } export interface SidebarProps - extends React.HTMLAttributes, + extends React.HTMLAttributes, VariantProps { - sidebar: SidebarItemGroup; - collapsed: boolean; - setCollapsed: (state: boolean) => void; + sidebar: SidebarItemGroup; + collapsed: boolean; + setCollapsed: (state: boolean) => void; + open?: boolean; + setOpen?: (state: boolean) => void; } -const Sidebar: FC & ContentComposition = - ({ collapsed, setCollapsed, sidebar, variant, className, children, ...props }) => { - return ( - -
    - {children} -
    -
    - ) - } +const Sidebar: FC & ContentComposition = ({ + collapsed, + setCollapsed, + sidebar, + variant, + className, + setOpen, + open, + children, + ...props +}) => { + const contextValue = useMemo( + () => ({ sidebar, collapsed, setCollapsed, open, setOpen }), + [sidebar, collapsed, setCollapsed, open, setOpen], + ); + return ( + +
    + {children} +
    +
    + ); +}; Sidebar.Header = SidebarHeader; Sidebar.Footer = SidebarFooter; Sidebar.Body = SidebarBody; Sidebar.Item = SidebarItem; Sidebar.Group = SidebarGroup; -Sidebar.displayName = "Sidebar" +Sidebar.displayName = "Sidebar"; -export { Sidebar, sidebarVariants } +export { Sidebar, sidebarVariants }; diff --git a/dashboard/src/features/sidebar/sidebar.tsx b/dashboard/src/features/sidebar/sidebar.tsx index 28389b5..a130bcd 100644 --- a/dashboard/src/features/sidebar/sidebar.tsx +++ b/dashboard/src/features/sidebar/sidebar.tsx @@ -5,48 +5,54 @@ import { sidebarItems } from "."; import { cn } from "@marzneshin/utils"; interface DashboardSidebarProps { - collapsed: boolean; - setCollapsed: (state: boolean) => void; + collapsed: boolean; + setCollapsed: (state: boolean) => void; + open?: boolean; + setOpen?: (state: boolean) => void; } export const DashboardSidebar: FC = ({ - collapsed, - setCollapsed, + collapsed, + setCollapsed, + setOpen, + open, }) => { - const router = useRouterState(); - const currentActivePath = router.location.pathname; + const router = useRouterState(); + const currentActivePath = router.location.pathname; - return ( - - ); + return ( + + ); }; diff --git a/dashboard/src/features/sidebar/use-panel-toggle.ts b/dashboard/src/features/sidebar/use-panel-toggle.ts index 6494847..9d57e86 100644 --- a/dashboard/src/features/sidebar/use-panel-toggle.ts +++ b/dashboard/src/features/sidebar/use-panel-toggle.ts @@ -1,5 +1,5 @@ import { useRef, useState } from "react"; -import { ImperativePanelHandle } from "react-resizable-panels"; +import type { ImperativePanelHandle } from "react-resizable-panels"; export const usePanelToggle = (isDesktop: boolean) => { const [collapsed, setCollapsed] = useState(false); @@ -22,5 +22,13 @@ export const usePanelToggle = (isDesktop: boolean) => { } }; - return { collapsed, open, panelRef, setCollapsed, setOpen, toggleCollapse, toggleOpen }; + return { + collapsed, + open, + panelRef, + setCollapsed, + setOpen, + toggleCollapse, + toggleOpen, + }; }; diff --git a/dashboard/src/routes/_dashboard.tsx b/dashboard/src/routes/_dashboard.tsx index 23e4169..f90087a 100644 --- a/dashboard/src/routes/_dashboard.tsx +++ b/dashboard/src/routes/_dashboard.tsx @@ -1,103 +1,102 @@ import { - Drawer, - DrawerContent, - Header, - ResizableHandle, - ResizablePanel, - ResizablePanelGroup, - Toaster, + Drawer, + DrawerContent, + Header, + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, + Toaster, } from "@marzneshin/components"; import { useAuth } from "@marzneshin/features/auth"; -import { - DashboardSidebar, - ToggleButton, -} from "@marzneshin/features/sidebar"; +import { DashboardSidebar, ToggleButton } from "@marzneshin/features/sidebar"; import { usePanelToggle } from "@marzneshin/features/sidebar/use-panel-toggle"; import { useScreenBreakpoint } from "@marzneshin/hooks/use-screen-breakpoint"; import { cn } from "@marzneshin/utils"; import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"; export const DashboardLayout = () => { - const isDesktop = useScreenBreakpoint("md"); - const { - collapsed, - panelRef, - open, - setCollapsed, - setOpen, - toggleCollapse, - toggleOpen, - } = usePanelToggle(isDesktop); + const isDesktop = useScreenBreakpoint("md"); + const { + collapsed, + panelRef, + open, + setCollapsed, + setOpen, + toggleCollapse, + toggleOpen, + } = usePanelToggle(isDesktop); - return ( -
    -
    -
    - -
    -
    - {isDesktop ? ( - - setCollapsed(true)} - onExpand={() => setCollapsed(false)} - minSize={15} - className={cn("w-[120px] min-w-[70px]")} - defaultSize={20} - ref={panelRef} - maxSize={30} - > - - - - -
    - - -
    -
    -
    - ) : ( -
    - -
    - - -
    -
    - )} + return ( +
    +
    +
    + +
    +
    + {isDesktop ? ( + + setCollapsed(true)} + onExpand={() => setCollapsed(false)} + minSize={15} + className={cn("w-[120px] min-w-[70px]")} + defaultSize={20} + ref={panelRef} + maxSize={30} + > + + + + +
    + + +
    +
    +
    + ) : ( +
    + +
    + + +
    - ); + )} +
    + ); }; export const Route = createFileRoute("/_dashboard")({ - component: () => , + component: () => , - beforeLoad: async () => { - const loggedIn = await useAuth.getState().isLoggedIn(); - if (!loggedIn) { - throw redirect({ - to: "/login", - }); - } - }, + beforeLoad: async () => { + const loggedIn = await useAuth.getState().isLoggedIn(); + if (!loggedIn) { + throw redirect({ + to: "/login", + }); + } + }, });