feat(store-header): implement immersive categories and update header properties
This commit is contained in:
@@ -1,16 +1,11 @@
|
||||
<header
|
||||
class="immersive-header"
|
||||
[class.immersive-header--compact]="!showHero()"
|
||||
[class.immersive-header--has-image]="showHero() && !!backgroundImageUrl()"
|
||||
>
|
||||
<div
|
||||
class="immersive-header__backdrop"
|
||||
[style.background-image]="backgroundImageUrl() ? 'url(' + backgroundImageUrl() + ')' : null"
|
||||
>
|
||||
@if (showHero() && backgroundImageUrl(); as imageUrl) {
|
||||
<img class="immersive-header__backdrop-size" [src]="imageUrl" alt="" aria-hidden="true" />
|
||||
}
|
||||
</div>
|
||||
></div>
|
||||
|
||||
<div class="immersive-header__content">
|
||||
<nav class="immersive-header__nav" aria-label="Navegación de la tienda">
|
||||
|
||||
@@ -5,20 +5,18 @@
|
||||
.immersive-header {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
isolation: isolate;
|
||||
min-height: 26rem;
|
||||
min-height: 640px;
|
||||
color: #fff;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.immersive-header--has-image {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.immersive-header__content {
|
||||
grid-area: 1 / 1;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-width: 0;
|
||||
padding-top: clamp(1.75rem, 4vw, 2.5rem);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
@@ -32,13 +30,6 @@
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.immersive-header__backdrop-size {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.immersive-header__backdrop::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -47,7 +38,7 @@
|
||||
180deg,
|
||||
rgba(0, 0, 0, 0.48) 0%,
|
||||
rgba(0, 0, 0, 0.4) 47%,
|
||||
rgba(245, 245, 245, 0.88) 100%
|
||||
#f5f5f5 100%
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,3 +50,19 @@
|
||||
(categorySelect)="categorySelect.emit($event)"
|
||||
/>
|
||||
</ng-template>
|
||||
|
||||
@if (headerType() === 'immersive' && displayCategories() && categories().length) {
|
||||
<nav class="immersive-categories" aria-label="Categorías">
|
||||
<div class="immersive-categories__list">
|
||||
@for (category of categories(); track category.id) {
|
||||
<button
|
||||
type="button"
|
||||
class="immersive-categories__item"
|
||||
(click)="categorySelect.emit(category)"
|
||||
>
|
||||
{{ category.nombre | uppercase }}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.immersive-categories {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.immersive-categories__list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: clamp(1rem, 3vw, 2.5rem);
|
||||
width: max-content;
|
||||
min-width: 100%;
|
||||
min-height: 3.5rem;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.immersive-categories__item {
|
||||
flex: none;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: #666666;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.immersive-categories__item:hover,
|
||||
.immersive-categories__item:focus-visible {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NgTemplateOutlet } from '@angular/common';
|
||||
import { NgTemplateOutlet, UpperCasePipe } from '@angular/common';
|
||||
import { Component, input, output } from '@angular/core';
|
||||
import { AuthUser } from '../../../services/auth/auth.interfaces';
|
||||
import { Category, Menu, WebsiteExtras } from '../../../services/tenant.interface';
|
||||
@@ -9,8 +9,9 @@ export type StoreHeaderType = 'standard' | 'immersive';
|
||||
|
||||
@Component({
|
||||
selector: 'app-store-header',
|
||||
imports: [NgTemplateOutlet, StandardStoreHeaderComponent, ImmersiveStoreHeaderComponent],
|
||||
imports: [NgTemplateOutlet, UpperCasePipe, StandardStoreHeaderComponent, ImmersiveStoreHeaderComponent],
|
||||
templateUrl: './store-header.component.html',
|
||||
styleUrl: './store-header.component.scss',
|
||||
})
|
||||
export class StoreHeaderComponent {
|
||||
readonly headerType = input<StoreHeaderType>('standard');
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
ngSkipHydration
|
||||
[headerType]="tenant()?.header_type ?? 'standard'"
|
||||
[heroContent]="tenant()?.extras?.immersiveHero"
|
||||
[carouselImages]="tenant()?.extras?.heroCarousel ?? []"
|
||||
[carouselImages]="tenant()?.extras?.immersiveHeroCarousel ?? []"
|
||||
[showHero]="isHomeRoute()"
|
||||
[cartQuantity]="cartQuantity()"
|
||||
[logoUrl]="tenant()?.header_logo ?? null"
|
||||
|
||||
@@ -266,7 +266,7 @@ describe('StoreLayoutComponent', () => {
|
||||
title: 'experiencia',
|
||||
description: 'Reservá tu entrada',
|
||||
},
|
||||
heroCarousel: ['/first.jpg', '/second.jpg'],
|
||||
immersiveHeroCarousel: ['/first.jpg', '/second.jpg'],
|
||||
},
|
||||
});
|
||||
fixture.detectChanges();
|
||||
@@ -288,6 +288,41 @@ describe('StoreLayoutComponent', () => {
|
||||
expect(element.querySelector('app-cart-icon')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('shows immersive categories below the header and navigates on selection', () => {
|
||||
tenantState.set({
|
||||
...tenant,
|
||||
header_type: 'immersive',
|
||||
display_categories: true,
|
||||
categories: [{ id: 11, nombre: 'Música', subcategories: [] }],
|
||||
});
|
||||
|
||||
const fixture = TestBed.createComponent(StoreLayoutComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
const element = fixture.nativeElement as HTMLElement;
|
||||
const header = element.querySelector('app-immersive-store-header header');
|
||||
const categories = element.querySelector('app-store-header .immersive-categories');
|
||||
const categoryButton = categories?.querySelector<HTMLButtonElement>('button');
|
||||
|
||||
expect(header).not.toBeNull();
|
||||
expect(categories).not.toBeNull();
|
||||
expect(header?.contains(categories)).toBe(false);
|
||||
expect(categoryButton?.textContent?.trim()).toBe('MÚSICA');
|
||||
|
||||
const navigate = vi.spyOn(TestBed.inject(Router), 'navigate');
|
||||
categoryButton?.click();
|
||||
expect(navigate).toHaveBeenCalledWith(['/categoria', 11], { queryParams: { page: 1 } });
|
||||
|
||||
tenantState.set({
|
||||
...tenant,
|
||||
header_type: 'immersive',
|
||||
display_categories: false,
|
||||
categories: [{ id: 11, nombre: 'Música', subcategories: [] }],
|
||||
});
|
||||
fixture.detectChanges();
|
||||
expect(element.querySelector('.immersive-categories')).toBeNull();
|
||||
});
|
||||
|
||||
it('opens the cart when requested through the openCart query parameter', () => {
|
||||
const fixture = TestBed.createComponent(StoreLayoutComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -71,7 +71,7 @@ export interface TenantEvent {
|
||||
|
||||
export interface WebsiteExtras {
|
||||
carousel?: string[];
|
||||
heroCarousel?: string[];
|
||||
immersiveHeroCarousel?: string[];
|
||||
immersiveHero?: {
|
||||
eyebrow: string;
|
||||
title: string;
|
||||
|
||||
Reference in New Issue
Block a user