Skip to content

Commit 0572103

Browse files
milanmajchrakclaude
andcommitted
fix(ssr-overlay): render admin-sidebar gutter on the server so logged-in reload doesn't shift
Follow-up to the anti-flicker overlay: with the overlay in place, an authenticated user's hard reload still showed the content visibly jump right by the admin-sidebar width at the moment the snapshot was removed. Root cause is independent of the overlay (the overlay just makes it a visible "reveal"): RootComponent computes the @slideSidebarPadding (outer-wrapper padding-left) from `cssService.getVariable('--ds-admin-sidebar-fixed-element-width')`, but that store is only populated in the browser (AppComponent.storeCSSVariables -> getComputedStyle). On the server the variable never resolves, `skipWhile(!val)` blocks forever, and the SSR HTML renders `outer-wrapper { padding-left: 0 }`. The browser then resolves the real width and applies `padding-left: 55px`, so the whole authenticated page (and the SSR snapshot, which is just that server HTML) jumps right by the sidebar width on reveal. Fix: on the server, fall back to the compiled default sidebar width (see $ds-admin-sidebar-* in src/styles/_bootstrap_variables.scss) so the SSR layout already reserves the gutter; in the browser keep waiting for the real, theme-overridable value. Non-admins are unaffected (state stays 'hidden' -> 0). Verified locally (authenticated admin, real UA, throttled hard reload): - SSR HTML outer-wrapper inline style is now `padding-left:55px` (was `padding-left:0`). - snapshot vs settled `#main-content` x = 55px in both -> horizontal shift at reveal = 0px (was 55px). Refs: dspace-customers#725, PR #1321 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 3079e57 commit 0572103

1 file changed

Lines changed: 14 additions & 4 deletions

File tree

src/app/root/root.component.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { first, map, skipWhile, startWith } from 'rxjs/operators';
2-
import { Component, Input, OnInit } from '@angular/core';
2+
import { Component, Inject, Input, OnInit, PLATFORM_ID } from '@angular/core';
3+
import { isPlatformServer } from '@angular/common';
34
import { Router } from '@angular/router';
45

56
import { combineLatest as combineLatestObservable, Observable, of } from 'rxjs';
@@ -42,20 +43,29 @@ export class RootComponent implements OnInit {
4243
private router: Router,
4344
private cssService: CSSVariableService,
4445
private menuService: MenuService,
45-
private windowService: HostWindowService
46+
private windowService: HostWindowService,
47+
@Inject(PLATFORM_ID) private platformId: any,
4648
) {
4749
this.notificationOptions = environment.notifications;
4850
}
4951

5052
ngOnInit() {
5153
this.isSidebarVisible$ = this.menuService.isMenuVisibleWithVisibleSections(MenuID.ADMIN);
5254

55+
// The CSS-variable store is only populated in the browser (from getComputedStyle in
56+
// AppComponent.storeCSSVariables). On the server it stays empty, so skipWhile(!val) would block
57+
// forever and the @slideSidebarPadding animation renders the outer-wrapper with padding-left:0.
58+
// The browser then resolves the real width and applies it, so for an authenticated user the whole
59+
// page (and the anti-flicker SSR snapshot, which is just the server HTML) visibly jumps right by
60+
// the sidebar width once the overlay is removed. On the server, fall back to the compiled default
61+
// width (see $ds-admin-sidebar-* in src/styles/_bootstrap_variables.scss) so the SSR layout already
62+
// reserves the gutter and matches the CSR; in the browser keep waiting for the real, theme-overridable value.
5363
this.expandedSidebarWidth$ = this.cssService.getVariable('--ds-admin-sidebar-total-width').pipe(
54-
skipWhile((val) => !val),
64+
isPlatformServer(this.platformId) ? map((val) => val || '305px') : skipWhile((val) => !val),
5565
first(),
5666
);
5767
this.collapsedSidebarWidth$ = this.cssService.getVariable('--ds-admin-sidebar-fixed-element-width').pipe(
58-
skipWhile((val) => !val),
68+
isPlatformServer(this.platformId) ? map((val) => val || '55px') : skipWhile((val) => !val),
5969
first(),
6070
);
6171

0 commit comments

Comments
 (0)