feat: add animation for opening and closing OverlayComponent and optimize code

This commit is contained in:
Chneemann 2025-04-11 09:29:06 +02:00
parent a013402e23
commit 19f1a2de5a
3 changed files with 74 additions and 35 deletions

View file

@ -1,5 +1,8 @@
@if (overlayData) {
<div class="overlay">
<div
class="overlay"
[class.show]="shouldShowOverlay"
[class.closing]="isClosingAnimation"
>
<div class="overlay-content">
@if (overlayType === "taskOverlay") {
<app-task-overlay
@ -18,7 +21,7 @@
[overlayType]="overlayType"
(closeDialogEmitter)="onCloseOverlay($event)"
></app-task-edit-overlay>
} @if (overlayType === "dialog") {
} @if (overlayType === "dialogOverlay") {
<app-dialog-overlay
[overlayData]="overlayData"
[overlayType]="overlayType"
@ -33,4 +36,3 @@
}
</div>
</div>
}

View file

@ -1,4 +1,7 @@
.overlay {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
bottom: 0;
@ -7,20 +10,38 @@
width: 100vw;
height: 100vh;
backdrop-filter: blur(5px);
background-color: rgba($color: #000000, $alpha: 0.2);
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.2);
pointer-events: none;
transition: opacity 0.3s ease, backdrop-filter 0.3s ease;
z-index: 999;
opacity: 0;
&.show {
opacity: 1;
pointer-events: auto;
& > .overlay-content {
transform: scale(1) translateY(0);
opacity: 1;
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55),
opacity 0.4s ease-out;
}
}
&.closing {
opacity: 0;
pointer-events: none;
& > .overlay-content {
transform: scale(0.95) translateY(20px);
opacity: 0;
transition: transform 0.4s ease-in, opacity 0.4s ease-out;
}
}
}
.overlay-mobile {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100vw;
height: 100vh;
z-index: 999;
.overlay-content {
transform: scale(0.95) translateY(20px);
opacity: 0;
transition: transform 0.4s ease-out, opacity 0.4s ease-out;
}

View file

@ -22,21 +22,31 @@ import { Subject, takeUntil } from 'rxjs';
styleUrl: './overlay.component.scss',
})
export class OverlayComponent implements OnInit, OnDestroy {
overlayType: any;
overlayData: any;
overlayType:
| 'taskOverlay'
| 'taskOverlayEdit'
| 'newTaskOverlay'
| 'dialogOverlay'
| 'contactOverlay'
| null = null;
overlayData: any = null;
shouldShowOverlay = false;
isClosingAnimation = false;
private destroy$ = new Subject<void>();
constructor(private overlayService: OverlayService, private router: Router) {}
/**
* Angular lifecycle hook that is called after the component's view has been fully initialized.
* Invokes `checkOverlayData` to subscribe to overlay data changes and update the component's state accordingly.
* Checks the overlay data observable from the OverlayService and subscribes to it.
*/
ngOnInit(): void {
this.checkOverlayData();
this.listenToOverlayChanges();
}
/**
* Emits an event to stop listening to the overlay data observable and unsubscribes from it.
*/
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
@ -44,40 +54,46 @@ export class OverlayComponent implements OnInit, OnDestroy {
/**
* Subscribes to the overlay data observable from the OverlayService.
* Updates the component's `overlayType` and `overlayData` properties
* whenever new overlay data is emitted.
* Updates the overlay type and data when new data is received.
* Sets the overlay as visible with a slight delay if data is present.
* Marks the overlay as closing and invisible if no data is present.
*/
checkOverlayData() {
listenToOverlayChanges() {
this.overlayService.overlayData$
.pipe(takeUntil(this.destroy$))
.subscribe((data) => {
if (data) {
this.overlayType = data.overlay;
this.overlayData = data.data;
this.isClosingAnimation = false;
requestAnimationFrame(() => {
this.shouldShowOverlay = true;
});
} else {
this.isClosingAnimation = true;
this.shouldShowOverlay = false;
}
});
}
/**
* Emits an event to close the overlay and set the overlay type/data to the provided string.
* If the overlay type is 'dialog', navigates to the login route.
* @param emitter The string to be emitted, which will also be set as the overlay data.
* Closes the overlay by clearing the overlay data from the service.
* @param {boolean} close Indicates the close event.
*/
onCloseOverlay(emitter: boolean) {
this.overlayData = emitter;
onCloseOverlay(close: boolean) {
this.overlayData = close;
this.overlayService.clearOverlayData();
}
@HostListener('document:click', ['$event'])
/**
* Closes the contact edit overlay if the user clicks on the overlay background.
*
* @param event The MouseEvent triggered by a click action.
* If the event target is the overlay itself, the overlay is closed.
* @param {MouseEvent} event The event object passed from the document click event.
*/
checkOpenContactEdit(event: MouseEvent) {
onDocumentClick(event: MouseEvent) {
const targetElement = event.target as HTMLElement;
if (targetElement === document.querySelector('.overlay')) {
if (targetElement && targetElement.classList.contains('overlay')) {
this.onCloseOverlay(false);
}
}