feat: add animation for opening and closing OverlayComponent and optimize code
This commit is contained in:
parent
a013402e23
commit
19f1a2de5a
3 changed files with 74 additions and 35 deletions
|
|
@ -1,5 +1,8 @@
|
||||||
@if (overlayData) {
|
<div
|
||||||
<div class="overlay">
|
class="overlay"
|
||||||
|
[class.show]="shouldShowOverlay"
|
||||||
|
[class.closing]="isClosingAnimation"
|
||||||
|
>
|
||||||
<div class="overlay-content">
|
<div class="overlay-content">
|
||||||
@if (overlayType === "taskOverlay") {
|
@if (overlayType === "taskOverlay") {
|
||||||
<app-task-overlay
|
<app-task-overlay
|
||||||
|
|
@ -18,7 +21,7 @@
|
||||||
[overlayType]="overlayType"
|
[overlayType]="overlayType"
|
||||||
(closeDialogEmitter)="onCloseOverlay($event)"
|
(closeDialogEmitter)="onCloseOverlay($event)"
|
||||||
></app-task-edit-overlay>
|
></app-task-edit-overlay>
|
||||||
} @if (overlayType === "dialog") {
|
} @if (overlayType === "dialogOverlay") {
|
||||||
<app-dialog-overlay
|
<app-dialog-overlay
|
||||||
[overlayData]="overlayData"
|
[overlayData]="overlayData"
|
||||||
[overlayType]="overlayType"
|
[overlayType]="overlayType"
|
||||||
|
|
@ -33,4 +36,3 @@
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
.overlay {
|
.overlay {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
@ -7,20 +10,38 @@
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
background-color: rgba($color: #000000, $alpha: 0.2);
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
display: flex;
|
pointer-events: none;
|
||||||
justify-content: center;
|
transition: opacity 0.3s ease, backdrop-filter 0.3s ease;
|
||||||
align-items: center;
|
|
||||||
z-index: 999;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlay-mobile {
|
&.closing {
|
||||||
position: fixed;
|
opacity: 0;
|
||||||
top: 0;
|
pointer-events: none;
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
& > .overlay-content {
|
||||||
right: 0;
|
transform: scale(0.95) translateY(20px);
|
||||||
width: 100vw;
|
opacity: 0;
|
||||||
height: 100vh;
|
transition: transform 0.4s ease-in, opacity 0.4s ease-out;
|
||||||
z-index: 999;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-content {
|
||||||
|
transform: scale(0.95) translateY(20px);
|
||||||
|
opacity: 0;
|
||||||
|
transition: transform 0.4s ease-out, opacity 0.4s ease-out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,21 +22,31 @@ import { Subject, takeUntil } from 'rxjs';
|
||||||
styleUrl: './overlay.component.scss',
|
styleUrl: './overlay.component.scss',
|
||||||
})
|
})
|
||||||
export class OverlayComponent implements OnInit, OnDestroy {
|
export class OverlayComponent implements OnInit, OnDestroy {
|
||||||
overlayType: any;
|
overlayType:
|
||||||
overlayData: any;
|
| 'taskOverlay'
|
||||||
|
| 'taskOverlayEdit'
|
||||||
|
| 'newTaskOverlay'
|
||||||
|
| 'dialogOverlay'
|
||||||
|
| 'contactOverlay'
|
||||||
|
| null = null;
|
||||||
|
overlayData: any = null;
|
||||||
|
shouldShowOverlay = false;
|
||||||
|
isClosingAnimation = false;
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(private overlayService: OverlayService, private router: Router) {}
|
constructor(private overlayService: OverlayService, private router: Router) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Angular lifecycle hook that is called after the component's view has been fully initialized.
|
* Checks the overlay data observable from the OverlayService and subscribes to it.
|
||||||
* Invokes `checkOverlayData` to subscribe to overlay data changes and update the component's state accordingly.
|
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.checkOverlayData();
|
this.listenToOverlayChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an event to stop listening to the overlay data observable and unsubscribes from it.
|
||||||
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.destroy$.next();
|
this.destroy$.next();
|
||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
|
|
@ -44,40 +54,46 @@ export class OverlayComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to the overlay data observable from the OverlayService.
|
* Subscribes to the overlay data observable from the OverlayService.
|
||||||
* Updates the component's `overlayType` and `overlayData` properties
|
* Updates the overlay type and data when new data is received.
|
||||||
* whenever new overlay data is emitted.
|
* 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$
|
this.overlayService.overlayData$
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe((data) => {
|
.subscribe((data) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
this.overlayType = data.overlay;
|
this.overlayType = data.overlay;
|
||||||
this.overlayData = data.data;
|
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.
|
* Closes the overlay by clearing the overlay data from the service.
|
||||||
* If the overlay type is 'dialog', navigates to the login route.
|
* @param {boolean} close Indicates the close event.
|
||||||
* @param emitter The string to be emitted, which will also be set as the overlay data.
|
|
||||||
*/
|
*/
|
||||||
onCloseOverlay(emitter: boolean) {
|
onCloseOverlay(close: boolean) {
|
||||||
this.overlayData = emitter;
|
this.overlayData = close;
|
||||||
this.overlayService.clearOverlayData();
|
this.overlayService.clearOverlayData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('document:click', ['$event'])
|
@HostListener('document:click', ['$event'])
|
||||||
/**
|
/**
|
||||||
* Closes the contact edit overlay if the user clicks on the overlay background.
|
* If the event target is the overlay itself, the overlay is closed.
|
||||||
*
|
* @param {MouseEvent} event The event object passed from the document click event.
|
||||||
* @param event The MouseEvent triggered by a click action.
|
|
||||||
*/
|
*/
|
||||||
checkOpenContactEdit(event: MouseEvent) {
|
onDocumentClick(event: MouseEvent) {
|
||||||
const targetElement = event.target as HTMLElement;
|
const targetElement = event.target as HTMLElement;
|
||||||
|
|
||||||
if (targetElement === document.querySelector('.overlay')) {
|
if (targetElement && targetElement.classList.contains('overlay')) {
|
||||||
this.onCloseOverlay(false);
|
this.onCloseOverlay(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue