Skip to content

Commit 181ca0c

Browse files
committed
fix(ui): proper resizing width when collapsing sidebar
1 parent 677492f commit 181ca0c

File tree

5 files changed

+22
-94
lines changed

5 files changed

+22
-94
lines changed

dashboard/src/components/charts/AllNodesStackedBarChart.tsx

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ export function AllNodesStackedBarChart() {
221221
const [modalOpen, setModalOpen] = useState(false)
222222
const [selectedData, setSelectedData] = useState<any>(null)
223223
const [currentDataIndex, setCurrentDataIndex] = useState(0)
224-
const [chartKey, setChartKey] = useState(0)
225224

226225
const chartContainerRef = useRef<HTMLDivElement>(null)
227226

@@ -230,61 +229,6 @@ export function AllNodesStackedBarChart() {
230229
const { data: nodesData } = useGetNodes(undefined, { query: { enabled: true } })
231230
const { resolvedTheme } = useTheme()
232231

233-
// Improved resize handling
234-
useEffect(() => {
235-
let timeoutId: NodeJS.Timeout
236-
237-
const handleResize = () => {
238-
clearTimeout(timeoutId)
239-
// Debounce to avoid excessive re-renders
240-
timeoutId = setTimeout(() => {
241-
setChartKey(prev => prev + 1)
242-
}, 150)
243-
}
244-
245-
// Listen to window resize
246-
window.addEventListener('resize', handleResize)
247-
248-
// Use ResizeObserver on the chart container and its parent
249-
const resizeObserver = new ResizeObserver(handleResize)
250-
251-
// Observe the chart container
252-
if (chartContainerRef.current) {
253-
resizeObserver.observe(chartContainerRef.current)
254-
}
255-
256-
// Observe main content area (catches sidebar changes)
257-
const mainContent = document.querySelector('main') || document.querySelector('[role="main"]') || document.getElementById('main-content')
258-
if (mainContent) {
259-
resizeObserver.observe(mainContent)
260-
}
261-
262-
// Observe body for class/attribute changes (sidebar state)
263-
const mutationObserver = new MutationObserver(handleResize)
264-
mutationObserver.observe(document.body, {
265-
attributes: true,
266-
attributeFilter: ['class', 'data-sidebar-state', 'data-state'],
267-
childList: false,
268-
subtree: false
269-
})
270-
271-
// Also observe the sidebar element itself if it exists
272-
const sidebar = document.querySelector('[data-sidebar]') || document.querySelector('aside')
273-
if (sidebar) {
274-
mutationObserver.observe(sidebar, {
275-
attributes: true,
276-
attributeFilter: ['class', 'data-state'],
277-
})
278-
}
279-
280-
return () => {
281-
clearTimeout(timeoutId)
282-
window.removeEventListener('resize', handleResize)
283-
resizeObserver.disconnect()
284-
mutationObserver.disconnect()
285-
}
286-
}, [])
287-
288232
// Navigation handler for modal
289233
const handleModalNavigate = (index: number) => {
290234
if (chartData && chartData[index]) {
@@ -637,9 +581,8 @@ export function AllNodesStackedBarChart() {
637581
className="max-h-[400px] min-h-[200px]"
638582
/>
639583
) : (
640-
<div className="mx-auto w-full max-w-[70rem]">
584+
<div className="mx-auto w-full">
641585
<ChartContainer
642-
key={chartKey}
643586
dir={'ltr'}
644587
config={chartConfig}
645588
className="max-h-[400px] min-h-[200px] w-full"
@@ -695,6 +638,7 @@ export function AllNodesStackedBarChart() {
695638
fill={chartConfig[node.name]?.color || `hsl(var(--chart-${(idx % 5) + 1}))`}
696639
radius={nodeList.length === 1 ? [4, 4, 4, 4] : idx === 0 ? [0, 0, 4, 4] : idx === nodeList.length - 1 ? [4, 4, 0, 0] : [0, 0, 0, 0]}
697640
cursor="pointer"
641+
className='rounded-t-xl overflow-hidden'
698642
/>
699643
))}
700644
</BarChart>

dashboard/src/components/charts/AreaCostumeChart.tsx

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { Button } from '@/components/ui/button'
1212
import { Clock, History, Cpu, MemoryStick } from 'lucide-react'
1313
import { dateUtils } from '@/utils/dateFormatter'
1414
import { useTheme } from 'next-themes'
15-
import { useSidebar } from '@/components/ui/sidebar'
1615

1716
type DataPoint = {
1817
time: string
@@ -156,13 +155,11 @@ const isNodeRealtimeStats = (stats: SystemStats | NodeRealtimeStats): stats is N
156155
export function AreaCostumeChart({ nodeId, currentStats, realtimeStats }: AreaCostumeChartProps) {
157156
const { t } = useTranslation()
158157
const { resolvedTheme } = useTheme()
159-
const { state: sidebarState } = useSidebar()
160158
const [statsHistory, setStatsHistory] = useState<DataPoint[]>([])
161159
const [isLoading, setIsLoading] = useState(true)
162160
const [error, setError] = useState<Error | null>(null)
163161
const [dateRange, setDateRange] = useState<DateRange | undefined>(undefined)
164162
const [viewMode, setViewMode] = useState<'realtime' | 'historical'>('realtime')
165-
const [chartKey, setChartKey] = useState(0) // Force chart refresh
166163

167164
// Add refs for chart container
168165
const chartContainerRef = useRef<HTMLDivElement>(null)
@@ -207,27 +204,6 @@ export function AreaCostumeChart({ nodeId, currentStats, realtimeStats }: AreaCo
207204
setViewMode('realtime')
208205
}, [nodeId])
209206

210-
// INSTANT sidebar state change detection - ZERO delay
211-
useEffect(() => {
212-
if (statsHistory.length > 0) {
213-
setChartKey(k => k + 1)
214-
}
215-
}, [sidebarState, statsHistory.length])
216-
217-
// INSTANT resize handling - ZERO delay
218-
useEffect(() => {
219-
const handleResize = () => {
220-
if (statsHistory.length > 0) {
221-
setChartKey(k => k + 1)
222-
}
223-
}
224-
225-
window.addEventListener('resize', handleResize)
226-
return () => {
227-
window.removeEventListener('resize', handleResize)
228-
}
229-
}, [statsHistory.length])
230-
231207
// Toggle between real-time and historical view
232208
const toggleViewMode = () => {
233209
if (viewMode === 'realtime') {
@@ -468,7 +444,6 @@ export function AreaCostumeChart({ nodeId, currentStats, realtimeStats }: AreaCo
468444
) : (
469445
<div
470446
ref={chartContainerRef}
471-
key={`chart-container-${chartKey}`} // Force container refresh
472447
className="h-[280px] w-full sm:h-[320px] lg:h-[360px] transition-all duration-300 ease-in-out"
473448
>
474449
<ChartContainer dir="ltr" config={chartConfig} className="h-full w-full">

dashboard/src/components/dialogs/UserModal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import GroupsSelector from '@/components/common/GroupsSelector'
33
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
44
import { Button } from '@/components/ui/button'
55
import { Calendar } from '@/components/ui/calendar'
6-
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
6+
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
77
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
88
import { Input } from '@/components/ui/input'
99
import { LoaderButton } from '@/components/ui/loader-button'
@@ -1308,6 +1308,9 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
13081308
<DialogTitle className={`${dir === 'rtl' ? 'text-right' : 'text-left'}`}>
13091309
{editingUser ? t('userDialog.editUser', { defaultValue: 'Edit User' }) : t('createUser', { defaultValue: 'Create User' })}
13101310
</DialogTitle>
1311+
<DialogDescription className="sr-only">
1312+
{editingUser ? t('userDialog.editUser', { defaultValue: 'Edit User' }) : t('createUser', { defaultValue: 'Create User' })}
1313+
</DialogDescription>
13111314
</DialogHeader>
13121315
<Form {...form}>
13131316
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">

dashboard/src/components/ui/sidebar.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,11 @@ const SidebarRail = React.forwardRef<HTMLButtonElement, React.ComponentProps<'bu
295295
'group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar',
296296
'[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
297297
'[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
298+
'group-data-[collapsible=icon]:translate-x-0 group-data-[collapsible=icon]:after:left-full group-data-[collapsible=icon]:after:w-[1px]',
299+
'[[data-side=left][data-collapsible=icon]_&]:right-0 [[data-side=left][data-collapsible=icon]_&]:translate-x-0',
300+
'[[data-side=right][data-collapsible=icon]_&]:left-0 [[data-side=right][data-collapsible=icon]_&]:translate-x-0',
298301
'hover:after:w-[4px] hover:after:bg-sidebar-accent',
302+
'group-data-[collapsible=icon]:hover:after:w-[2px]',
299303
'after:transition-all after:duration-200',
300304
'hover:bg-sidebar/5',
301305
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',
@@ -318,7 +322,7 @@ const SidebarInset = React.forwardRef<HTMLDivElement, React.ComponentProps<'main
318322
<main
319323
ref={ref}
320324
className={cn(
321-
'relative flex min-h-svh flex-1 flex-col bg-background',
325+
'relative flex min-h-svh min-w-0 flex-1 flex-col bg-background overflow-x-hidden',
322326
'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow',
323327
className,
324328
)}

dashboard/src/pages/_dashboard.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AppSidebar } from '@/components/layout/sidebar'
33
import PageTransition from '@/components/PageTransition'
44
import RouteGuard from '@/components/RouteGuard'
55
import { TopLoadingBar } from '@/components/TopLoadingBar'
6-
import { SidebarProvider } from '@/components/ui/sidebar'
6+
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar'
77
import { getCurrentAdmin } from '@/service/api'
88
import { Outlet } from 'react-router'
99

@@ -18,17 +18,19 @@ export const clientLoader = async (): Promise<any> => {
1818

1919
export default function DashboardLayout() {
2020
return (
21-
<SidebarProvider>
21+
<SidebarProvider className=''>
2222
<RouteGuard>
2323
<TopLoadingBar />
24-
<div className="flex w-full flex-col lg:flex-row">
24+
<div className='flex w-full flex-col lg:flex-row'>
2525
<AppSidebar />
26-
<div className="flex min-h-screen w-full flex-col justify-between gap-y-4">
27-
<PageTransition duration={250}>
28-
<Outlet />
29-
</PageTransition>
30-
<Footer />
31-
</div>
26+
<SidebarInset>
27+
<div className="flex min-h-screen w-full flex-col justify-between gap-y-4">
28+
<PageTransition duration={250}>
29+
<Outlet />
30+
</PageTransition>
31+
<Footer />
32+
</div>
33+
</SidebarInset>
3234
</div>
3335
</RouteGuard>
3436
</SidebarProvider>

0 commit comments

Comments
 (0)