animaciones
This commit is contained in:
@@ -1,9 +1,17 @@
|
||||
@if(thereIsFullscreenImage) {
|
||||
<mid-res-image [src]="midResImage!.src" [alt]="midResImage!.alt" (closed)="onClose()"></mid-res-image>
|
||||
<mid-res-image
|
||||
[src]="midResImage!.src"
|
||||
[alt]="midResImage!.alt"
|
||||
(closed)="onClose()"
|
||||
></mid-res-image>
|
||||
}
|
||||
|
||||
<ul class="low-res-image-list">
|
||||
@for (image of images; track image.id) {
|
||||
<low-res-image [src]="image.src" [alt]="image.alt" (clicked)="onClickedImage($event)"></low-res-image>
|
||||
<low-res-image
|
||||
[src]="image.src"
|
||||
[alt]="image.alt"
|
||||
(clicked)="onClickedImageWithEvent($event)"
|
||||
></low-res-image>
|
||||
}
|
||||
</ul>
|
||||
|
@@ -13,14 +13,47 @@ export class Gallery {
|
||||
protected images : LowResImage[] = [];
|
||||
thereIsFullscreenImage: boolean = false;
|
||||
midResImage: MidResImage | null = null;
|
||||
isAnimatingToFullscreen: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this.loadImages();
|
||||
}
|
||||
|
||||
onClickedImage(midResImage: MidResImage): void {
|
||||
onClickedImage(midResImage: MidResImage, event?: MouseEvent): void {
|
||||
// Capturar información de la animación si hay evento disponible
|
||||
if (event && event.target) {
|
||||
this.prepareImageTransition(event.target as HTMLElement);
|
||||
}
|
||||
|
||||
this.isAnimatingToFullscreen = true;
|
||||
this.midResImage = midResImage;
|
||||
this.thereIsFullscreenImage = this.midResImage !== null;
|
||||
|
||||
// Resetear el estado de animación después de un breve delay
|
||||
setTimeout(() => {
|
||||
this.isAnimatingToFullscreen = false;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
onClickedImageWithEvent(data: {midResImage: MidResImage, event: MouseEvent}): void {
|
||||
this.onClickedImage(data.midResImage, data.event);
|
||||
}
|
||||
|
||||
private prepareImageTransition(imageElement: HTMLElement): void {
|
||||
// Capturar la posición inicial de la imagen para animación coordinada
|
||||
const rect = imageElement.getBoundingClientRect();
|
||||
const initialPosition = {
|
||||
x: rect.left + rect.width / 2,
|
||||
y: rect.top + rect.height / 2,
|
||||
width: rect.width,
|
||||
height: rect.height
|
||||
};
|
||||
|
||||
// Guardar información de transición en el document para uso del mid-res-image
|
||||
(document as any).__imageTransition = {
|
||||
...initialPosition,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
|
@@ -11,6 +11,7 @@ $gap-size: 20px;
|
||||
transition: box-shadow 0.3s ease, transform 0.3s ease;
|
||||
margin-top: calc($gap-size / 2);
|
||||
margin-bottom: calc($gap-size / 2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.low-res-image-container:hover {
|
||||
@@ -18,11 +19,22 @@ $gap-size: 20px;
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
.low-res-image-container:active {
|
||||
transform: scale(1.05);
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
|
||||
.low-res-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
transition: transform 0.3s ease, filter 0.3s ease;
|
||||
}
|
||||
|
||||
.low-res-image-container:hover .low-res-image {
|
||||
transform: scale(1.02);
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
/* Tablets in landscape - 1 column */
|
||||
|
@@ -12,13 +12,13 @@ export class LowResImage {
|
||||
@Input({ required: true }) alt: string = '';
|
||||
public id : string = 'low-res-image-' + Math.random().toString(36).substring(2, 15);
|
||||
|
||||
@Output() clicked = new EventEmitter<MidResImage>();
|
||||
@Output() clicked = new EventEmitter<{midResImage: MidResImage, event: MouseEvent}>();
|
||||
|
||||
openFullscreen(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
const midResImage = new MidResImage();
|
||||
midResImage.src = this.src.replace('low', 'mid');
|
||||
midResImage.alt = this.alt;
|
||||
this.clicked.emit(midResImage);
|
||||
this.clicked.emit({midResImage, event});
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,17 @@
|
||||
<div class="mid-res-image-container">
|
||||
<img [src]="src" [alt]="alt" class="img" loading="lazy" />
|
||||
<div class="panel" (click)="openFullscreen($event)">
|
||||
<div class="infoPanelMenu">
|
||||
<div
|
||||
class="mid-res-image-container"
|
||||
[class.panel-shown]="!isInfoPanelHidden"
|
||||
[class.panel-hidden]="isInfoPanelHidden"
|
||||
(click)="closeFullscreen($event)"
|
||||
>
|
||||
<div class="image-container">
|
||||
<img
|
||||
[src]="src"
|
||||
[alt]="alt"
|
||||
loading="lazy"
|
||||
(click)="$event.stopPropagation()"
|
||||
/>
|
||||
</div>
|
||||
@if(isInfoPanelHidden) {
|
||||
<app-button
|
||||
label="ShowInfoPanel"
|
||||
@@ -11,6 +21,8 @@
|
||||
icon="assets/icons/push-left-svgrepo-com.svg"
|
||||
></app-button>
|
||||
} @else {
|
||||
<div class="panel" (click)="$event.stopPropagation()">
|
||||
<div class="infoPanelMenu">
|
||||
<app-button
|
||||
label="HideInfoPanel"
|
||||
(click)="hideInfoPanel($event)"
|
||||
@@ -18,7 +30,6 @@
|
||||
tooltip="Hide Image Info"
|
||||
icon="assets/icons/push-right-svgrepo-com.svg"
|
||||
></app-button>
|
||||
}
|
||||
<app-button
|
||||
label="CloseFullscreen"
|
||||
(click)="closeFullscreen($event)"
|
||||
@@ -72,14 +83,15 @@
|
||||
></app-button>
|
||||
</div>
|
||||
<div class="comment-section">
|
||||
<div class="header">
|
||||
<!-- <div class="header">
|
||||
<h4>Comment</h4>
|
||||
<button (click)="toggleCommentForm($event)">Add Comment</button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h4>Comments</h4>
|
||||
<div class="list"></div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
@@ -4,27 +4,329 @@
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
background-color: rgba(42, 41, 38, 0.95);
|
||||
display: flex;
|
||||
z-index: 1000;
|
||||
flex-grow: 1;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
|
||||
// Entrada animada del contenedor
|
||||
animation: fadeInContainer 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
|
||||
// Animación coordinada desde la posición de la imagen clickeada
|
||||
&.coordinated-animation {
|
||||
animation: fadeInContainerCoordinated 0.5s cubic-bezier(0.4, 0, 0.2, 1)
|
||||
forwards;
|
||||
|
||||
.image-container {
|
||||
animation: coordinatedImageTransition 0.7s
|
||||
cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
||||
}
|
||||
|
||||
.panel {
|
||||
animation: slideInPanelDelayed 0.5s cubic-bezier(0.4, 0, 0.2, 1)
|
||||
0.4s both;
|
||||
}
|
||||
|
||||
.show-button {
|
||||
animation: fadeInButtonDelayed 0.4s cubic-bezier(0.4, 0, 0.2, 1)
|
||||
0.5s both;
|
||||
}
|
||||
}
|
||||
|
||||
// Animaciones de salida coordinada
|
||||
&.coordinated-exit {
|
||||
animation: fadeOutContainerCoordinated 0.6s cubic-bezier(0.4, 0, 0.2, 1)
|
||||
forwards;
|
||||
|
||||
.image-container {
|
||||
animation: coordinatedImageExitTransition 0.6s
|
||||
cubic-bezier(0.7, 0, 0.84, 0) forwards;
|
||||
}
|
||||
|
||||
.panel {
|
||||
animation: slideOutPanel 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
|
||||
.show-button {
|
||||
animation: fadeOutButton 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
}
|
||||
|
||||
// Animación de salida simple (sin coordinación)
|
||||
&.simple-exit {
|
||||
animation: fadeOutContainerSimple 0.4s cubic-bezier(0.4, 0, 0.2, 1)
|
||||
forwards;
|
||||
|
||||
.image-container {
|
||||
animation: zoomOutImage 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
|
||||
.panel {
|
||||
animation: slideOutPanel 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
|
||||
.show-button {
|
||||
animation: fadeOutButton 0.2s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInContainer {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-backdrop-filter: blur(0px);
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
}
|
||||
|
||||
// Image section
|
||||
.img {
|
||||
.image-container {
|
||||
width: 70%;
|
||||
height: 100vh;
|
||||
object-fit: contain;
|
||||
cursor: zoom-in;
|
||||
transition: transform 0.3s ease;
|
||||
height: 100dvh;
|
||||
transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
// Animación de entrada de la imagen
|
||||
animation: slideInImage 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
|
||||
img {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: scale-down;
|
||||
|
||||
// Animación de zoom elegante
|
||||
animation: zoomInImage 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)
|
||||
forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInImage {
|
||||
from {
|
||||
transform: translateX(-30px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoomInImage {
|
||||
from {
|
||||
transform: scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// When panel is hidden, image takes full width
|
||||
&.panel-hidden {
|
||||
.image-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.panel {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.panel-shown {
|
||||
.image-container {
|
||||
width: 75%;
|
||||
}
|
||||
.panel {
|
||||
width: 25%;
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Show panel button - positioned to always be visible
|
||||
.show-button {
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
right: 4rem;
|
||||
z-index: 1001;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
// Animación de entrada del botón con retraso
|
||||
animation: fadeInButton 0.4s cubic-bezier(0.4, 0, 0.2, 1) 0.3s both;
|
||||
}
|
||||
|
||||
@keyframes fadeInButton {
|
||||
from {
|
||||
transform: translateY(-20px) scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Animaciones coordinadas para transición suave desde galería
|
||||
@keyframes fadeInContainerCoordinated {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-backdrop-filter: blur(0px);
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes coordinatedImageTransition {
|
||||
from {
|
||||
transform: translate(
|
||||
calc(var(--start-x, 50vw) - 50vw),
|
||||
calc(var(--start-y, 50vh) - 50vh)
|
||||
)
|
||||
scale(calc(var(--start-width, 200px) / 400));
|
||||
opacity: 0.8;
|
||||
}
|
||||
50% {
|
||||
transform: translate(
|
||||
calc((var(--start-x, 50vw) - 50vw) * 0.3),
|
||||
calc((var(--start-y, 50vh) - 50vh) * 0.3)
|
||||
)
|
||||
scale(0.9);
|
||||
opacity: 0.9;
|
||||
}
|
||||
to {
|
||||
transform: translate(0, 0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInPanelDelayed {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInButtonDelayed {
|
||||
from {
|
||||
transform: translateY(-20px) scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Animaciones de salida coordinada
|
||||
@keyframes fadeOutContainerCoordinated {
|
||||
from {
|
||||
opacity: 1;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
-webkit-backdrop-filter: blur(0px);
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes coordinatedImageExitTransition {
|
||||
from {
|
||||
transform: translate(0, 0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: translate(
|
||||
calc((var(--end-x, 50vw) - 50vw) * 0.3),
|
||||
calc((var(--end-y, 50vh) - 50vh) * 0.3)
|
||||
)
|
||||
scale(0.7);
|
||||
opacity: 0.8;
|
||||
}
|
||||
to {
|
||||
transform: translate(
|
||||
calc(var(--end-x, 50vw) - 50vw),
|
||||
calc(var(--end-y, 50vh) - 50vh)
|
||||
)
|
||||
scale(calc(var(--end-width, 200px) / 400));
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOutPanel {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOutButton {
|
||||
from {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateY(-20px) scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Animaciones de salida simple
|
||||
@keyframes fadeOutContainerSimple {
|
||||
from {
|
||||
opacity: 1;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
-webkit-backdrop-filter: blur(0px);
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoomOutImage {
|
||||
from {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Panel section
|
||||
.panel {
|
||||
width: 30%;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
background: variables.$primary-white;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
@@ -32,6 +334,12 @@
|
||||
box-shadow: -4px 0 20px rgba(42, 41, 38, 0.2);
|
||||
border-left: 1px solid variables.$border-grey;
|
||||
padding: 2%;
|
||||
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
width 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
// Animación de entrada del panel
|
||||
animation: slideInPanel 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.2s both;
|
||||
|
||||
.infoPanelMenu {
|
||||
display: flex;
|
||||
@@ -178,11 +486,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInPanel {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive design
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
|
||||
.img {
|
||||
.image-container {
|
||||
width: 100%;
|
||||
height: 60vh;
|
||||
}
|
||||
@@ -195,10 +514,17 @@
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust show button position for mobile
|
||||
.show-button {
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.img {
|
||||
.image-container {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
|
@@ -1,14 +1,23 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { SvgLoader } from '../svg/svg';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
HostListener,
|
||||
} from '@angular/core';
|
||||
import { Button } from '../button/button';
|
||||
|
||||
// view: src/app/mid-res-image/mid-res-image.html
|
||||
|
||||
@Component({
|
||||
selector: 'mid-res-image',
|
||||
imports: [Button],
|
||||
templateUrl: './mid-res-image.html',
|
||||
styleUrl: './mid-res-image.scss',
|
||||
})
|
||||
export class MidResImage {
|
||||
export class MidResImage implements OnInit, OnDestroy {
|
||||
@Input({ required: true }) src: string = '';
|
||||
@Input({ required: true }) alt: string = '';
|
||||
@Input() title: string = 'Title';
|
||||
@@ -17,25 +26,126 @@ export class MidResImage {
|
||||
@Output() closed = new EventEmitter<void>();
|
||||
|
||||
isInfoPanelHidden: boolean = false;
|
||||
hasCoordinatedAnimation: boolean = false;
|
||||
private originalPosition: any = null;
|
||||
|
||||
comments: string[] = [];
|
||||
|
||||
@HostListener('document:keydown', ['$event'])
|
||||
handleKeyDown(event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') {
|
||||
this.closeFullscreenAnimated();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Bloquear el scroll del body cuando se abre la imagen en pantalla completa
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
// Verificar si hay información de transición disponible
|
||||
const transitionData = (document as any).__imageTransition;
|
||||
if (transitionData && Date.now() - transitionData.timestamp < 200) {
|
||||
this.hasCoordinatedAnimation = true;
|
||||
this.setupCoordinatedAnimation(transitionData);
|
||||
// Limpiar la información de transición
|
||||
delete (document as any).__imageTransition;
|
||||
}
|
||||
}
|
||||
|
||||
private setupCoordinatedAnimation(transitionData: any): void {
|
||||
// Guardar la posición original para la animación de salida
|
||||
this.originalPosition = { ...transitionData };
|
||||
|
||||
// Aplicar CSS variables para la animación coordinada
|
||||
const container = document.querySelector(
|
||||
'.mid-res-image-container'
|
||||
) as HTMLElement;
|
||||
if (container) {
|
||||
container.style.setProperty('--start-x', `${transitionData.x}px`);
|
||||
container.style.setProperty('--start-y', `${transitionData.y}px`);
|
||||
container.style.setProperty(
|
||||
'--start-width',
|
||||
`${transitionData.width}px`
|
||||
);
|
||||
container.style.setProperty(
|
||||
'--start-height',
|
||||
`${transitionData.height}px`
|
||||
);
|
||||
container.classList.add('coordinated-animation');
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// Restaurar el scroll del body cuando se destruye el componente
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
hideInfoPanel(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.isInfoPanelHidden = !this.isInfoPanelHidden;
|
||||
this.isInfoPanelHidden = true;
|
||||
// tienes que coger el div 'panel' y cambiar su display a none
|
||||
// Esto es para que no se vea el panel de información cuando se cierra
|
||||
// Ademas, tienes que mostrar un botón para mostrar de nuevo el panel
|
||||
document
|
||||
.querySelector('.panel')
|
||||
?.setAttribute('style', 'display: none;');
|
||||
}
|
||||
|
||||
showInfoPanel(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.isInfoPanelHidden = !this.isInfoPanelHidden;
|
||||
this.isInfoPanelHidden = false;
|
||||
}
|
||||
|
||||
closeFullscreen(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.closeFullscreenAnimated();
|
||||
}
|
||||
|
||||
openFullscreen(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
private closeFullscreenAnimated(): void {
|
||||
// Iniciar animación de salida
|
||||
this.startExitAnimation();
|
||||
|
||||
// Emitir el evento de cerrado después de la animación
|
||||
setTimeout(() => {
|
||||
// Restaurar el scroll del body
|
||||
document.body.style.overflow = 'auto';
|
||||
this.closed.emit();
|
||||
}, 600); // Duración de la animación de salida
|
||||
}
|
||||
|
||||
private startExitAnimation(): void {
|
||||
const container = document.querySelector(
|
||||
'.mid-res-image-container'
|
||||
) as HTMLElement;
|
||||
if (container) {
|
||||
// Remover animaciones de entrada
|
||||
container.classList.remove('coordinated-animation');
|
||||
|
||||
// Si tenemos información de la posición original, configurar para retorno coordinado
|
||||
if (this.hasCoordinatedAnimation && this.originalPosition) {
|
||||
// Volver a establecer las variables CSS para la animación de retorno
|
||||
container.style.setProperty(
|
||||
'--end-x',
|
||||
`${this.originalPosition.x}px`
|
||||
);
|
||||
container.style.setProperty(
|
||||
'--end-y',
|
||||
`${this.originalPosition.y}px`
|
||||
);
|
||||
container.style.setProperty(
|
||||
'--end-width',
|
||||
`${this.originalPosition.width}px`
|
||||
);
|
||||
container.style.setProperty(
|
||||
'--end-height',
|
||||
`${this.originalPosition.height}px`
|
||||
);
|
||||
container.classList.add('coordinated-exit');
|
||||
} else {
|
||||
// Animación de salida simple si no hay coordinación
|
||||
container.classList.add('simple-exit');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
editImage(event: MouseEvent): void {
|
||||
@@ -48,21 +158,16 @@ export class MidResImage {
|
||||
|
||||
downloadImage(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
// debe descargar la imagen en resolución media (720p)
|
||||
}
|
||||
|
||||
shareImage(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
// tiene que abrir un modal para compartir la imagen en redes sociales
|
||||
}
|
||||
|
||||
buyImage(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
toggleCommentForm(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
close() {
|
||||
this.closed.emit();
|
||||
// tiene que abrir un modal para comprar la imagen
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user