Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/app/root/root.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
{{ 'root.skip-to-content' | translate }}
</button>

<div class="outer-wrapper" [class.d-none]="shouldShowFullscreenLoader" [ngClass]="browserOsClasses.asObservable() | async" [@slideSidebarPadding]="{
value: ((isSidebarVisible$ | async) !== true ? 'hidden' : (slideSidebarOver$ | async) ? 'unpinned' : 'pinned'),
params: { collapsedWidth: (collapsedSidebarWidth$ | async), expandedWidth: (expandedSidebarWidth$ | async) }
}">
<div class="outer-wrapper" [class.d-none]="shouldShowFullscreenLoader"
[ngClass]="browserOsClasses.asObservable() | async"
[class.ds-admin-sidebar-animate]="gutterTransitionEnabled"
[class.ds-admin-sidebar-hidden]="(sidebarPaddingState$ | async) === 'hidden'"
[class.ds-admin-sidebar-unpinned]="(sidebarPaddingState$ | async) === 'unpinned'"
[class.ds-admin-sidebar-pinned]="(sidebarPaddingState$ | async) === 'pinned'">
<ds-admin-sidebar [expandedSidebarWidth$]="expandedSidebarWidth$" [collapsedSidebarWidth$]="collapsedSidebarWidth$"></ds-admin-sidebar>
<div class="inner-wrapper">
<ds-system-wide-alert-banner></ds-system-wide-alert-banner>
Expand Down
24 changes: 24 additions & 0 deletions src/app/root/root.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,27 @@
top: 0;
}
}

// Admin-sidebar left gutter, driven by the ds-admin-sidebar-* class from sidebarPaddingState$ rather
// than the @slideSidebarPadding animation. The animation read the width from a browser-only store, so
// the server emitted `padding-left: *` and the page moved sideways once the browser resolved it.
// Resolving from the custom properties in CSS renders the same on both sides, with no hardcoded px.
.outer-wrapper {
&.ds-admin-sidebar-hidden {
padding-left: 0;
}

&.ds-admin-sidebar-unpinned {
padding-left: var(--ds-admin-sidebar-fixed-element-width);
}

&.ds-admin-sidebar-pinned {
padding-left: var(--ds-admin-sidebar-total-width);
}

// Only genuine pin/unpin toggles slide: the class is added after the first paint, so the initial
// gutter never animates behind the anti-flicker overlay.
&.ds-admin-sidebar-animate {
transition: padding-left 300ms ease-in-out;
}
}
34 changes: 31 additions & 3 deletions src/app/root/root.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
NgClass,
} from '@angular/common';
import {
AfterViewInit,
Component,
Inject,
Input,
Expand Down Expand Up @@ -38,7 +39,6 @@ import {
} from '../core/services/window.service';
import { ThemedFooterComponent } from '../footer/themed-footer.component';
import { ThemedHeaderNavbarWrapperComponent } from '../header-nav-wrapper/themed-header-navbar-wrapper.component';
import { slideSidebarPadding } from '../shared/animations/slide';
import { HostWindowService } from '../shared/host-window.service';
import { LiveRegionComponent } from '../shared/live-region/live-region.component';
import { ThemedLoadingComponent } from '../shared/loading/themed-loading.component';
Expand All @@ -52,7 +52,6 @@ import { SystemWideAlertBannerComponent } from '../system-wide-alert/alert-banne
selector: 'ds-base-root',
templateUrl: './root.component.html',
styleUrls: ['./root.component.scss'],
animations: [slideSidebarPadding],
imports: [
AsyncPipe,
LiveRegionComponent,
Expand All @@ -68,12 +67,25 @@ import { SystemWideAlertBannerComponent } from '../system-wide-alert/alert-banne
TranslateModule,
],
})
export class RootComponent implements OnInit {
export class RootComponent implements OnInit, AfterViewInit {
theme: Observable<ThemeConfig> = of({} as any);
isSidebarVisible$: Observable<boolean>;
slideSidebarOver$: Observable<boolean>;
collapsedSidebarWidth$: Observable<string>;
expandedSidebarWidth$: Observable<string>;

/**
* Which admin-sidebar gutter the outer wrapper should carry: 'hidden', 'unpinned' or 'pinned'.
* The width itself comes from CSS (see root.component.scss), so the server and the browser
* resolve it the same way.
*/
sidebarPaddingState$: Observable<string>;

/**
* Lets the gutter transition run only after the first paint, so the initial resolution does not
* animate. Off on the server and on the first render; only pin/unpin toggles slide.
*/
gutterTransitionEnabled = false;
notificationOptions: INotificationBoardOptions;
models: any;

Expand Down Expand Up @@ -129,11 +141,27 @@ export class RootComponent implements OnInit {
startWith(true),
);

// A CSS class instead of the @slideSidebarPadding animation: that animation needed a concrete
// width from the browser-only CSS-variable store, so the server rendered `padding-left: *` and
// the page moved sideways once the browser resolved the real width.
this.sidebarPaddingState$ = combineLatestObservable([this.isSidebarVisible$, this.slideSidebarOver$]).pipe(
map(([visible, over]: [boolean, boolean]) => !visible ? 'hidden' : over ? 'unpinned' : 'pinned'),
);

if (this.router.url === getPageInternalServerErrorRoute()) {
this.shouldShowRouteLoader = false;
}
}

ngAfterViewInit(): void {
// Browser only; requestAnimationFrame does not exist under SSR.
if (typeof requestAnimationFrame === 'function') {
requestAnimationFrame(() => {
this.gutterTransitionEnabled = true;
});
}
}

skipToMainContent() {
const mainContent = document.getElementById('main-content');
if (mainContent) {
Expand Down
2 changes: 0 additions & 2 deletions src/themes/custom/app/root/root.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { ThemedBreadcrumbsComponent } from '../../../../app/breadcrumbs/themed-b
import { ThemedFooterComponent } from '../../../../app/footer/themed-footer.component';
import { ThemedHeaderNavbarWrapperComponent } from '../../../../app/header-nav-wrapper/themed-header-navbar-wrapper.component';
import { RootComponent as BaseComponent } from '../../../../app/root/root.component';
import { slideSidebarPadding } from '../../../../app/shared/animations/slide';
import { LiveRegionComponent } from '../../../../app/shared/live-region/live-region.component';
import { ThemedLoadingComponent } from '../../../../app/shared/loading/themed-loading.component';
import { NotificationsBoardComponent } from '../../../../app/shared/notifications/notifications-board/notifications-board.component';
Expand All @@ -23,7 +22,6 @@ import { SystemWideAlertBannerComponent } from '../../../../app/system-wide-aler
styleUrls: ['../../../../app/root/root.component.scss'],
// templateUrl: './root.component.html',
templateUrl: '../../../../app/root/root.component.html',
animations: [slideSidebarPadding],
imports: [
AsyncPipe,
LiveRegionComponent,
Expand Down
Loading