From c851272ebeefa7e4bd18f460e5b905f042760708 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Wed, 30 Sep 2026 09:00:53 -0300 Subject: [PATCH] feat(main-carousel): enhance image handling for responsive design --- src/app/core/services/tenant.interface.ts | 2 +- .../main-carousel.component.html | 27 ++++++++++--------- .../main-carousel.component.scss | 4 +-- .../main-carousel.component.spec.ts | 23 +++++++++++++++- .../main-carousel/main-carousel.component.ts | 17 +++++++++--- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/app/core/services/tenant.interface.ts b/src/app/core/services/tenant.interface.ts index fcc075c..e7f00e6 100644 --- a/src/app/core/services/tenant.interface.ts +++ b/src/app/core/services/tenant.interface.ts @@ -75,7 +75,7 @@ export interface TenantEvent { } export interface WebsiteExtras { - carousel?: string[]; + carousel?: (string | { desktop: string; mobile: string })[]; immersiveHeroCarousel?: string[]; immersiveHero?: { eyebrow: string; diff --git a/src/app/shared/components/main-carousel/main-carousel.component.html b/src/app/shared/components/main-carousel/main-carousel.component.html index 98b315c..563b5d9 100644 --- a/src/app/shared/components/main-carousel/main-carousel.component.html +++ b/src/app/shared/components/main-carousel/main-carousel.component.html @@ -12,18 +12,21 @@ > diff --git a/src/app/shared/components/main-carousel/main-carousel.component.scss b/src/app/shared/components/main-carousel/main-carousel.component.scss index bd9a335..103e94b 100644 --- a/src/app/shared/components/main-carousel/main-carousel.component.scss +++ b/src/app/shared/components/main-carousel/main-carousel.component.scss @@ -17,9 +17,7 @@ &__viewport { position: relative; width: 100%; - aspect-ratio: 4 / 1; - min-height: 9rem; - max-height: 25rem; + aspect-ratio: 355 / 90; } &__image { diff --git a/src/app/shared/components/main-carousel/main-carousel.component.spec.ts b/src/app/shared/components/main-carousel/main-carousel.component.spec.ts index af77618..3c218e5 100644 --- a/src/app/shared/components/main-carousel/main-carousel.component.spec.ts +++ b/src/app/shared/components/main-carousel/main-carousel.component.spec.ts @@ -18,12 +18,20 @@ class TestHostComponent { readonly images = ['/images/one.webp', '/images/two.webp', '/images/three.webp']; } +@Component({ + imports: [MainCarouselComponent], + template: ``, +}) +class ResponsiveTestHostComponent { + readonly images = [{ desktop: '/images/desktop.webp', mobile: '/images/mobile.webp' }]; +} + describe('MainCarouselComponent', () => { let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [TestHostComponent], + imports: [TestHostComponent, ResponsiveTestHostComponent], }).compileComponents(); fixture = TestBed.createComponent(TestHostComponent); @@ -41,6 +49,19 @@ describe('MainCarouselComponent', () => { expect(images[0].classList).toContain('main-carousel__image--active'); }); + it('usa la variante móvil del crop cuando está disponible', () => { + const responsiveFixture = TestBed.createComponent(ResponsiveTestHostComponent); + responsiveFixture.detectChanges(); + + const picture = responsiveFixture.nativeElement.querySelector('picture') as HTMLPictureElement; + const source = picture.querySelector('source') as HTMLSourceElement; + const image = picture.querySelector('img') as HTMLImageElement; + + expect(source.getAttribute('media')).toBe('(max-width: 576px)'); + expect(source.getAttribute('srcset')).toBe('/images/mobile.webp'); + expect(image.getAttribute('src')).toBe('/images/desktop.webp'); + }); + it('carga las imágenes secuencialmente y prioriza la imagen visible', () => { const images = fixture.nativeElement.querySelectorAll( '.main-carousel__image', diff --git a/src/app/shared/components/main-carousel/main-carousel.component.ts b/src/app/shared/components/main-carousel/main-carousel.component.ts index 581b827..6537719 100644 --- a/src/app/shared/components/main-carousel/main-carousel.component.ts +++ b/src/app/shared/components/main-carousel/main-carousel.component.ts @@ -11,6 +11,9 @@ import { signal, } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; +import type { WebsiteExtras } from '../../../core/services/tenant.interface'; + +type CarouselImage = NonNullable[number]; @Component({ selector: 'app-main-carousel', @@ -26,7 +29,7 @@ export class MainCarouselComponent { private readonly settledIndexes = signal>(new Set()); private firstImageReadyEmitted = false; - readonly images = input.required(); + readonly images = input.required(); readonly imageAlts = input([]); readonly autoSlideInterval = input(5000); readonly ariaLabel = input('Imágenes destacadas'); @@ -91,13 +94,21 @@ export class MainCarouselComponent { this.paused.set(paused); } - protected imageSource(image: string, index: number): string | null { + protected imageSource(image: CarouselImage, index: number): string | null { const shouldLoad = this.loadedIndexes().has(index) || index === this.sequentialLoadIndex() || index === this.activeIndex(); - return shouldLoad ? image : null; + return shouldLoad ? (typeof image === 'string' ? image : image.desktop) : null; + } + + protected mobileImageSource(image: CarouselImage, index: number): string | null { + if (typeof image === 'string' || this.imageSource(image, index) === null) { + return null; + } + + return image.mobile; } protected handleImageLoad(index: number): void {