Picsur/frontend/src/app/app.component.ts

117 lines
3.2 KiB
TypeScript

import { Portal } from '@angular/cdk/portal';
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import {
ActivatedRoute,
NavigationEnd,
NavigationError,
Router,
} from '@angular/router';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { RouteTransitionAnimations } from './app.animation';
import { PRouteData } from './models/dto/picsur-routes.dto';
import { BootstrapService } from './util/bootstrap.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
animations: [RouteTransitionAnimations],
})
export class AppComponent implements OnInit {
private readonly logger = console;
@ViewChild(MatSidenav) sidebar: MatSidenav;
wrapContentWithContainer: boolean = true;
sidebarPortal: Portal<any> | undefined = undefined;
isDesktop: boolean = false;
hasSidebar: boolean = false;
public constructor(
private readonly router: Router,
private readonly activatedRoute: ActivatedRoute,
private readonly bootstrapService: BootstrapService,
) {}
public getRouteAnimData() {
// Everyone is doing shit with the activated route
// This seems so much cleaner tho
// Am I just missing something, or is everyone else missing something?
return this.router.url;
}
public ngOnInit() {
this.subscribeRouter();
this.subscribeMobile();
}
@AutoUnsubscribe()
private subscribeRouter() {
return this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) this.onNavigationEnd(event);
if (event instanceof NavigationError) this.onNavigationError(event);
});
}
@AutoUnsubscribe()
private subscribeMobile() {
return this.bootstrapService.isNotMobile().subscribe((state) => {
this.isDesktop = state;
this.updateSidebar();
});
}
private async onNavigationError(event: NavigationError) {
// 404 handler
const error: Error = event.error;
if (error.message.startsWith('Cannot match any routes'))
this.router.navigate(['/error/404'], { replaceUrl: true });
}
private async onNavigationEnd(event: NavigationEnd) {
const data = this.routeData;
this.wrapContentWithContainer = !data.noContainer;
if (data._sidebar_portal !== undefined) {
this.sidebarPortal = data._sidebar_portal;
this.hasSidebar = true;
} else {
this.hasSidebar = false;
}
this.updateSidebar();
}
private updateSidebar() {
if (!this.sidebar) return;
if (
this.sidebarPortal === undefined ||
!this.hasSidebar ||
!this.isDesktop
) {
this.sidebar.opened = false;
} else {
this.sidebar.opened = true;
}
}
// Recusively collect and merge all route data
private get routeData(): PRouteData {
let currentRoute: ActivatedRoute | null = this.activatedRoute;
let accumulate: PRouteData = {};
while (currentRoute !== null) {
const data = currentRoute.snapshot.data;
if (data !== undefined) {
accumulate = {
...accumulate,
...data,
};
}
currentRoute = currentRoute.firstChild;
}
return accumulate;
}
}