NotificationsOverlay WIP

This commit is contained in:
Patrick Haßel 2024-11-08 10:41:48 +01:00
parent f47d30a4c8
commit bc68777229
5 changed files with 173 additions and 6 deletions

View File

@ -0,0 +1,26 @@
import {FromJson} from "../common/types";
import {validateDate, validateString} from "../common/validators";
export class Notification<T> {
constructor(
readonly uuid: string,
readonly title: string,
readonly date: Date,
readonly type: string,
readonly payload: T,
) {
// -
}
static fromJson<T>(fromJson: FromJson<T>): FromJson<Notification<T>> {
return (json: any) => new Notification<T>(
validateString(json.uuid),
validateString(json.title),
validateDate(json.date),
validateString(json.type),
fromJson(json.payload),
);
}
}

View File

@ -0,0 +1,20 @@
import {Injectable} from '@angular/core';
import {ApiService} from "../common/api.service";
import {Notification} from "./Notification";
@Injectable({
providedIn: 'root'
})
export class NotificationService {
public notifications: Notification<any>[] = [
new Notification('', 'Test', new Date(), 'test', null),
];
constructor(
protected readonly api: ApiService,
) {
// -
}
}

View File

@ -13,6 +13,9 @@
>
{{ userService.user.name }}
</div>
<div #notificationsButton class="mainMenuItem mainMenuItemRight mainMenuNotifications" [class.mainMenuNotifications_blink]="blink" *ngIf="notificationService.notifications.length" (click)="toggleMenu()">
{{ notificationService.notifications.length }}
</div>
</ng-container>
<ng-container *ngIf="userService.user === null">
@ -23,3 +26,15 @@
</div>
<router-outlet (activate)="onActivate($event)"/>
<div #notificationsOverlayMobile class="notificationsOverlay notificationsOverlayMobile" *ngIf="notificationsOverlayVisible" (window:resize)="onResize()">
<div class="notificationOverlayEntry" *ngFor="let notification of notificationService.notifications">
{{ notification.title }}
</div>
</div>
<div #notificationsOverlayDesktop class="notificationsOverlay notificationsOverlayDesktop" *ngIf="notificationsOverlayVisible" (window:resize)="onResize()">
<div class="notificationOverlayEntry" *ngFor="let notification of notificationService.notifications">
{{ notification.title }}
</div>
</div>

View File

@ -23,4 +23,56 @@
background-color: lightskyblue;
}
.mainMenuNotifications {
background-color: lightskyblue;
min-width: 2.5em;
text-align: center;
}
.mainMenuNotifications_blink {
color: white;
background-color: dodgerblue;
}
}
.notificationsOverlay {
position: fixed;
background-color: lightgray;
border: 1px solid gray;
border-radius: 0 0 @space @space;
box-shadow: -0.5em 0.5em 1em rgba(0, 0, 0, 0.5);
.notificationOverlayEntry {
border-bottom: 1px solid gray;
padding: @halfSpace;
}
.notificationOverlayEntry:hover {
background-color: lightskyblue;
}
}
.notificationsOverlayMobile {
width: calc(100% - 2 * @space);
margin: 0 @space;
}
.notificationsOverlayDesktop {
display: none;
}
@media (min-width: 1000px) {
.notificationsOverlayMobile {
display: none;
}
.notificationsOverlayDesktop {
display: unset;
width: 500px;
margin: 0;
}
}

View File

@ -1,25 +1,52 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {Router, RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router';
import {NgIf} from "@angular/common";
import {JsonPipe, NgForOf, NgIf} from "@angular/common";
import {UserService} from "./api/User/user.service";
import {Subscription} from "rxjs";
import {Subscription, timer} from "rxjs";
import {NotificationService} from "./api/Notification/notification.service";
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, RouterLink, RouterLinkActive, NgIf],
imports: [RouterOutlet, RouterLink, RouterLinkActive, NgIf, NgForOf, JsonPipe],
templateUrl: './app.component.html',
styleUrl: './app.component.less'
})
export class AppComponent implements OnInit, OnDestroy {
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
private readonly subs: Subscription[] = [];
protected menuVisible = true;
protected blink: boolean = true;
private _notificationsButton!: ElementRef;
@ViewChild("notificationsButton")
set notificationsButton(e: ElementRef) {
this._notificationsButton = e;
this.onResize();
}
private _notificationsOverlayMobile!: ElementRef;
@ViewChild("notificationsOverlayMobile")
set notificationsOverlayMobile(e: ElementRef) {
this._notificationsOverlayMobile = e;
this.onResize();
}
private _notificationsOverlayDesktop!: ElementRef;
@ViewChild("notificationsOverlayDesktop")
set notificationsOverlayDesktop(e: ElementRef) {
this._notificationsOverlayDesktop = e;
this.onResize();
}
protected notificationsOverlayVisible: boolean = true;
constructor(
protected readonly router: Router,
protected readonly userService: UserService,
protected readonly notificationService: NotificationService,
) {
// -
}
@ -29,7 +56,11 @@ export class AppComponent implements OnInit, OnDestroy {
}
ngOnInit(): void {
// -
this.subs.push(timer(500, 500).subscribe(() => this.blink = !this.blink))
}
ngAfterViewInit(): void {
this.onResize();
}
ngOnDestroy(): void {
@ -37,4 +68,27 @@ export class AppComponent implements OnInit, OnDestroy {
this.subs.length = 0;
}
toggleMenu() {
this.notificationsOverlayVisible = !this.notificationsOverlayVisible;
this.onResize();
}
onResize() {
if (this._notificationsButton) {
const button = this._notificationsButton.nativeElement.getBoundingClientRect();
if (this._notificationsOverlayMobile) {
const overlayMobile = this._notificationsOverlayMobile.nativeElement.style;
overlayMobile.top = button.bottom + 'px';
}
if (this._notificationsOverlayDesktop) {
const overlayDesktopRect = this._notificationsOverlayDesktop.nativeElement.getBoundingClientRect();
const overlayDesktopStyle = this._notificationsOverlayDesktop.nativeElement.style;
overlayDesktopStyle.top = button.bottom + 'px';
overlayDesktopStyle.left = button.right - overlayDesktopRect.width + 'px';
}
}
}
}