mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-13 07:38:33 +08:00
fix(sidebar): suppress collapse->expand transition flash on fresh load (#5306)
* fix(sidebar): suppress collapse->expand transition flash on fresh load The pre-paint script sets the correct --sidebar-width, but store rehydration re-applies it during hydration and the always-on width/slide transitions animate that re-apply, reading as a collapse->expand flash. Suppress sidebar transitions during the boot window via a new html.sidebar-booting class (mirroring html.sidebar-resizing), lifted after the first paint via double-rAF so user toggles and the fullscreen slide still animate. * chore(sidebar): convert boot-guard comment to TSDoc
This commit is contained in:
@@ -110,6 +110,18 @@ html.sidebar-resizing .sidebar-shell-inner {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
/* Suppress sidebar transitions during the initial hydration window. The
|
||||
pre-paint script sets the correct --sidebar-width, but store rehydration
|
||||
re-applies it a tick later; without this guard that re-apply animates the
|
||||
rail, reading as a collapse -> expand flash on a fresh page load. Removed
|
||||
after the first paint (see workspace-chrome.tsx) so user-driven toggles and
|
||||
the fullscreen slide still animate. */
|
||||
html.sidebar-booting .sidebar-container,
|
||||
html.sidebar-booting .sidebar-shell-outer,
|
||||
html.sidebar-booting .sidebar-shell-inner {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.panel-container {
|
||||
width: var(--panel-width);
|
||||
}
|
||||
|
||||
+26
-1
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useLayoutEffect } from 'react'
|
||||
import { useEffect, useLayoutEffect, useRef } from 'react'
|
||||
import { cn } from '@sim/emcn'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { Sidebar } from '@/app/workspace/[workspaceId]/w/components/sidebar/sidebar'
|
||||
@@ -47,6 +47,8 @@ export function WorkspaceChrome({
|
||||
children,
|
||||
initialSidebarCollapsed = false,
|
||||
}: WorkspaceChromeProps) {
|
||||
const rafRef = useRef(0)
|
||||
|
||||
const pathname = usePathname()
|
||||
const isFullscreen = isFullscreenPath(pathname)
|
||||
|
||||
@@ -66,6 +68,29 @@ export function WorkspaceChrome({
|
||||
*/
|
||||
const isCollapsed = hasHydrated ? storeIsCollapsed : initialSidebarCollapsed
|
||||
|
||||
/**
|
||||
* Suppresses sidebar transitions across the initial hydration window. The
|
||||
* pre-paint script already set the correct `--sidebar-width`, but the store
|
||||
* rehydration below re-applies it a tick later; without this guard that
|
||||
* re-apply animates the rail, reading as a collapse -> expand flash on a
|
||||
* fresh load. Applied before the rehydrate effect so the class is in place
|
||||
* ahead of the width mutation, then lifted after the first paint so
|
||||
* user-driven collapse toggles and the fullscreen slide still animate.
|
||||
*/
|
||||
useLayoutEffect(() => {
|
||||
const root = document.documentElement
|
||||
root.classList.add('sidebar-booting')
|
||||
const raf1 = requestAnimationFrame(() => {
|
||||
const raf2 = requestAnimationFrame(() => root.classList.remove('sidebar-booting'))
|
||||
rafRef.current = raf2
|
||||
})
|
||||
rafRef.current = raf1
|
||||
return () => {
|
||||
cancelAnimationFrame(rafRef.current)
|
||||
root.classList.remove('sidebar-booting')
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Hydrate the persisted width before paint (collapse comes from the cookie/prop).
|
||||
useLayoutEffect(() => {
|
||||
void useSidebarStore.persist.rehydrate()
|
||||
|
||||
Reference in New Issue
Block a user