fix(core): persist sidebar open state and width to prevent flash on load (#12743)

https://github.com/user-attachments/assets/6b61c9f2-80bd-4f2c-943d-1fd610a69ecf

This PR change updates the sidebar initialization so it reads the open
and width values from persistent storage. This prevents the UI from
flashing open by default on startup.

Both left and right sidebars restore correctly from the last known state
from storage.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Sidebar and workbench panels now retain their open/closed status and
width based on your previously saved preferences, providing a more
personalized and consistent experience across sessions.
- **Tests**
- Added comprehensive tests to ensure sidebar state persistence and
behavior are reliable and consistent.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Norkz <richardlora557@gmail.com>
This commit is contained in:
Richard LoraandNorkz authored and GitHub committed 2025-06-23 10:46:10 +00:00
1 parent 4507c88792
commit 74106ba7c6
3 files changed
+59 -5

No files matched your search

@@ -0,0 +1,54 @@
import { Framework, MemoryMemento } from '@toeverything/infra';
import { beforeEach, describe, expect, test } from 'vitest';
import { AppSidebarState } from '../../providers/storage';
import { AppSidebar } from '../app-sidebar';
describe('AppSidebar', () => {
let framework: Framework;
let memento: MemoryMemento;
let sidebar: AppSidebar;
beforeEach(() => {
framework = new Framework();
memento = new MemoryMemento();
framework.entity(AppSidebar, [AppSidebarState]);
framework.impl(AppSidebarState, memento);
sidebar = framework.provider().get(AppSidebar);
});
test('default values', () => {
expect(sidebar.open$.value).toBe(true);
expect(sidebar.width$.value).toBe(248);
expect(sidebar.smallScreenMode$.value).toBe(false);
expect(sidebar.hovering$.value).toBe(false);
});
test('state setters update live data and storage', () => {
sidebar.setOpen(false);
expect(sidebar.open$.value).toBe(false);
expect(memento.get('open')).toBe(false);
sidebar.toggleSidebar();
expect(sidebar.open$.value).toBe(true);
expect(memento.get('open')).toBe(true);
sidebar.setWidth(260);
expect(sidebar.width$.value).toBe(260);
expect(memento.get('width')).toBe(260);
sidebar.setSmallScreenMode(true);
expect(sidebar.smallScreenMode$.value).toBe(true);
sidebar.setHovering(true);
expect(sidebar.hovering$.value).toBe(true);
sidebar.setPreventHovering(true);
expect(sidebar.preventHovering$.value).toBe(true);
sidebar.setResizing(true);
expect(sidebar.resizing$.value).toBe(true);
});
test('getCachedAppSidebarOpenState', () => {
sidebar.setOpen(false);
expect(sidebar.getCachedAppSidebarOpenState()).toBe(false);
});
});
@@ -21,14 +21,14 @@ export class AppSidebar extends Entity {
this.appSidebarState
.watch<boolean>(APP_SIDEBAR_STATE.OPEN)
.pipe(map(value => value ?? true)),
true
this.appSidebarState.get<boolean>(APP_SIDEBAR_STATE.OPEN) ?? true
);
width$ = LiveData.from(
this.appSidebarState
.watch<number>(APP_SIDEBAR_STATE.WIDTH)
.pipe(map(value => value ?? 248)),
248
this.appSidebarState.get<number>(APP_SIDEBAR_STATE.WIDTH) ?? 248
);
/**
@@ -58,14 +58,14 @@ export class Workbench extends Entity {
});
sidebarOpen$ = LiveData.from(
this.globalState.watch<boolean>(sidebarOpenKey),
false
this.globalState.get<boolean>(sidebarOpenKey) ?? false
);
setSidebarOpen(open: boolean) {
this.globalState.set(sidebarOpenKey, open);
}
sidebarWidth$ = LiveData.from(
this.globalState.watch<number>(sidebarWidthKey),
320
this.globalState.get<number>(sidebarWidthKey) ?? 320
);
setSidebarWidth(width: number) {
this.globalState.set(sidebarWidthKey, width);
@@ -73,7 +73,7 @@ export class Workbench extends Entity {
workspaceSelectorOpen$ = LiveData.from(
this.globalState.watch<boolean>(workspaceSelectorOpenKey),
false
this.globalState.get<boolean>(workspaceSelectorOpenKey) ?? false
);
setWorkspaceSelectorOpen(open: boolean) {
this.globalState.set(workspaceSelectorOpenKey, open);