feat(carousel): add main carousel component with image support and integrate into store home page
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
PLATFORM_ID,
|
||||
computed,
|
||||
effect,
|
||||
inject,
|
||||
input,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { isPlatformBrowser } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-main-carousel',
|
||||
templateUrl: './main-carousel.component.html',
|
||||
styleUrl: './main-carousel.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MainCarouselComponent {
|
||||
private readonly platformId = inject(PLATFORM_ID);
|
||||
private readonly requestedIndex = signal(0);
|
||||
private readonly paused = signal(false);
|
||||
|
||||
readonly images = input.required<readonly string[]>();
|
||||
readonly imageAlts = input<readonly string[]>([]);
|
||||
readonly autoSlideInterval = input(5000);
|
||||
readonly ariaLabel = input('Imágenes destacadas');
|
||||
|
||||
protected readonly activeIndex = computed(() => {
|
||||
const imageCount = this.images().length;
|
||||
|
||||
return imageCount ? this.requestedIndex() % imageCount : 0;
|
||||
});
|
||||
protected readonly hasMultipleImages = computed(() => this.images().length > 1);
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
const imageCount = this.images().length;
|
||||
const interval = Math.max(this.autoSlideInterval(), 1000);
|
||||
|
||||
if (!isPlatformBrowser(this.platformId) || imageCount < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = window.setInterval(() => {
|
||||
if (!this.paused()) {
|
||||
this.requestedIndex.update((index) => (index + 1) % imageCount);
|
||||
}
|
||||
}, interval);
|
||||
|
||||
return () => window.clearInterval(timer);
|
||||
});
|
||||
}
|
||||
|
||||
protected selectImage(index: number): void {
|
||||
if (index >= 0 && index < this.images().length) {
|
||||
this.requestedIndex.set(index);
|
||||
}
|
||||
}
|
||||
|
||||
protected setPaused(paused: boolean): void {
|
||||
this.paused.set(paused);
|
||||
}
|
||||
|
||||
protected handleKeydown(event: KeyboardEvent): void {
|
||||
if (!this.hasMultipleImages()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === 'ArrowLeft') {
|
||||
event.preventDefault();
|
||||
this.requestedIndex.update(
|
||||
(index) => (index - 1 + this.images().length) % this.images().length,
|
||||
);
|
||||
}
|
||||
|
||||
if (event.key === 'ArrowRight') {
|
||||
event.preventDefault();
|
||||
this.requestedIndex.update((index) => (index + 1) % this.images().length);
|
||||
}
|
||||
}
|
||||
|
||||
protected imageAlt(index: number): string {
|
||||
return this.imageAlts()[index] || `Imagen destacada ${index + 1}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user