From 8a3adacd38e597d8705de9c4beefca4a87712293 Mon Sep 17 00:00:00 2001 From: parsaaghayi Date: Wed, 23 Sep 2026 23:45:18 +0330 Subject: [PATCH] feat(admin): collapsible sidebar and responsive data tables with custom scroll --- .../admin-panel/src/components/Layout.tsx | 39 +++++++-- .../admin-panel/src/components/Sidebar.tsx | 84 ++++++++++++++++--- .../admin-panel/src/components/Topbar.tsx | 18 +++- frontend/admin-panel/src/index.css | 17 ++++ frontend/admin-panel/src/pages/Orders.tsx | 6 +- .../admin-panel/src/pages/Transactions.tsx | 4 +- frontend/admin-panel/src/pages/Users.tsx | 52 ++++++------ 7 files changed, 171 insertions(+), 49 deletions(-) diff --git a/frontend/admin-panel/src/components/Layout.tsx b/frontend/admin-panel/src/components/Layout.tsx index 816e7fa..41b2020 100644 --- a/frontend/admin-panel/src/components/Layout.tsx +++ b/frontend/admin-panel/src/components/Layout.tsx @@ -1,17 +1,44 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Outlet } from 'react-router-dom'; import Sidebar from './Sidebar'; import Topbar from './Topbar'; export default function Layout() { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const [isCollapsed, setIsCollapsed] = useState(() => { + try { + return localStorage.getItem('canina_admin_sidebar_collapsed') === 'true'; + } catch { + return false; + } + }); + + const toggleCollapse = () => { + setIsCollapsed((prev) => { + const next = !prev; + try { + localStorage.setItem('canina_admin_sidebar_collapsed', String(next)); + } catch {} + return next; + }); + }; return ( -
- -
- setIsMobileMenuOpen(!isMobileMenuOpen)} /> -
+
+ +
+ setIsMobileMenuOpen(!isMobileMenuOpen)} + isCollapsed={isCollapsed} + toggleCollapse={toggleCollapse} + /> +
diff --git a/frontend/admin-panel/src/components/Sidebar.tsx b/frontend/admin-panel/src/components/Sidebar.tsx index 3c22c32..bb4f2e1 100644 --- a/frontend/admin-panel/src/components/Sidebar.tsx +++ b/frontend/admin-panel/src/components/Sidebar.tsx @@ -57,9 +57,10 @@ interface MenuGroup { interface SidebarProps { isOpen: boolean; setIsOpen: (val: boolean) => void; + isCollapsed?: boolean; } -export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) { +export default function Sidebar({ isOpen, setIsOpen, isCollapsed = false }: SidebarProps) { const location = useLocation(); const [newOrdersCount, setNewOrdersCount] = useState(0); const intervalRef = useRef | null>(null); @@ -239,34 +240,97 @@ export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) { )}