feat(header): refactor immersive store header for improved search functionality and styling
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
<header
|
<header class="immersive-header" [class.immersive-header--compact]="!showHero()">
|
||||||
class="immersive-header"
|
|
||||||
[class.immersive-header--compact]="!showHero()"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="immersive-header__backdrop"
|
class="immersive-header__backdrop"
|
||||||
[style.background-image]="backgroundImageUrl() ? 'url(' + backgroundImageUrl() + ')' : null"
|
[style.background-image]="backgroundImageUrl() ? 'url(' + backgroundImageUrl() + ')' : null"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div class="immersive-header__content">
|
<div class="immersive-header__content">
|
||||||
<nav class="immersive-header__nav container-xl px-3 px-md-4" aria-label="Navegación de la tienda">
|
<nav
|
||||||
|
class="immersive-header__nav container-xl px-3 px-md-4"
|
||||||
|
aria-label="Navegación de la tienda"
|
||||||
|
>
|
||||||
<a routerLink="/" class="immersive-header__brand" aria-label="Ir al inicio">
|
<a routerLink="/" class="immersive-header__brand" aria-label="Ir al inicio">
|
||||||
@if (logoUrl()) {
|
@if (logoUrl()) {
|
||||||
<img [src]="logoUrl()" alt="Logo del comercio" />
|
<img [src]="logoUrl()" alt="Logo del comercio" />
|
||||||
@@ -19,19 +19,14 @@
|
|||||||
@if (displaySearchBar()) {
|
@if (displaySearchBar()) {
|
||||||
<form class="immersive-header__search" role="search" (submit)="submitSearch($event)">
|
<form class="immersive-header__search" role="search" (submit)="submitSearch($event)">
|
||||||
<label class="visually-hidden" for="immersive-search-input">Buscar productos</label>
|
<label class="visually-hidden" for="immersive-search-input">Buscar productos</label>
|
||||||
<input
|
<app-input
|
||||||
id="immersive-search-input"
|
id="immersive-search-input"
|
||||||
type="search"
|
|
||||||
placeholder="Buscar"
|
placeholder="Buscar"
|
||||||
autocomplete="off"
|
type="search"
|
||||||
[formControl]="searchControl"
|
[(value)]="searchTerm"
|
||||||
[attr.aria-invalid]="showSearchError()"
|
[invalid]="showSearchError()"
|
||||||
[attr.aria-describedby]="showSearchError() ? 'immersive-search-error' : null"
|
(valueChange)="showSearchError.set(false)"
|
||||||
(input)="showSearchError.set(false)"
|
|
||||||
/>
|
/>
|
||||||
<button type="submit" aria-label="Buscar">
|
|
||||||
<i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
@if (showSearchError()) {
|
@if (showSearchError()) {
|
||||||
<span id="immersive-search-error" class="immersive-header__search-error" role="alert"
|
<span id="immersive-search-error" class="immersive-header__search-error" role="alert"
|
||||||
>Ingresá al menos 3 caracteres.</span
|
>Ingresá al menos 3 caracteres.</span
|
||||||
@@ -41,9 +36,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@if (ticketsMenu(); as menu) {
|
@if (ticketsMenu(); as menu) {
|
||||||
<button class="immersive-header__tickets" type="button" (click)="ticketsClick.emit()">
|
<app-button
|
||||||
|
variant="secondary"
|
||||||
|
hostClass="immersive-header__tickets"
|
||||||
|
(click)="ticketsClick.emit()"
|
||||||
|
>
|
||||||
{{ menu.label }}
|
{{ menu.label }}
|
||||||
</button>
|
</app-button>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (displayCart()) {
|
@if (displayCart()) {
|
||||||
@@ -78,7 +77,11 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@if (checkoutRemainingTime(); as remainingTime) {
|
@if (checkoutRemainingTime(); as remainingTime) {
|
||||||
<div class="immersive-header__timer container-xl px-3 px-md-4" role="timer" aria-label="Tiempo restante de compra">
|
<div
|
||||||
|
class="immersive-header__timer container-xl px-3 px-md-4"
|
||||||
|
role="timer"
|
||||||
|
aria-label="Tiempo restante de compra"
|
||||||
|
>
|
||||||
Tiempo restante de compra: <strong>{{ remainingTime }}</strong>
|
Tiempo restante de compra: <strong>{{ remainingTime }}</strong>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,57 +74,19 @@
|
|||||||
|
|
||||||
.immersive-header__search {
|
.immersive-header__search {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
width: clamp(115px, 17vw, 205px);
|
width: clamp(115px, 17vw, 205px);
|
||||||
height: 2rem;
|
|
||||||
border: 1px solid var(--tenant-primary, #ff7006);
|
|
||||||
border-radius: 3px;
|
|
||||||
background: rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.immersive-header__search input {
|
|
||||||
width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
color: #fff;
|
|
||||||
background: transparent;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
.immersive-header__search input::placeholder {
|
|
||||||
color: rgba(255, 255, 255, 0.78);
|
|
||||||
}
|
|
||||||
.immersive-header__search input::-webkit-search-cancel-button {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
.immersive-header__search button {
|
|
||||||
border: 0;
|
|
||||||
padding-inline: 0.55rem;
|
|
||||||
color: var(--tenant-primary, #ff7006);
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
.immersive-header__search:focus-within {
|
|
||||||
outline: 2px solid var(--tenant-primary, #ff7006);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
}
|
||||||
.immersive-header__search-error {
|
.immersive-header__search-error {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% + 0.25rem);
|
top: calc(100% + 0.25rem);
|
||||||
right: 0;
|
right: 0;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
color: #fff;
|
color: var(--tenant-danger, #dc3545);
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
}
|
}
|
||||||
.immersive-header__tickets {
|
|
||||||
border: 1px solid var(--tenant-primary, #ff7006);
|
:host ::ng-deep .immersive-header__tickets {
|
||||||
border-radius: 3px;
|
width: auto;
|
||||||
padding: 0.25rem 0.6rem;
|
|
||||||
color: #fff;
|
|
||||||
background: rgba(0, 0, 0, 0.2);
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
.immersive-header__tickets:hover {
|
|
||||||
background: var(--tenant-primary, #ff7006);
|
|
||||||
}
|
}
|
||||||
.immersive-header__account {
|
.immersive-header__account {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -219,9 +181,3 @@
|
|||||||
font-size: clamp(3rem, 12vw, 5rem);
|
font-size: clamp(3rem, 12vw, 5rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.immersive-header__tickets {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ import {
|
|||||||
output,
|
output,
|
||||||
signal,
|
signal,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
import { AuthUser } from '../../../services/auth/auth.interfaces';
|
import { AuthUser } from '../../../services/auth/auth.interfaces';
|
||||||
import { Menu, WebsiteExtras } from '../../../services/tenant.interface';
|
import { Menu, WebsiteExtras } from '../../../services/tenant.interface';
|
||||||
|
import { ButtonComponent } from '../../../../shared/components/button/button.component';
|
||||||
import { CartIconComponent } from '../../../../shared/components/cart-icon/cart-icon.component';
|
import { CartIconComponent } from '../../../../shared/components/cart-icon/cart-icon.component';
|
||||||
import { IconButtonComponent } from '../../../../shared/components/icon-button/icon-button.component';
|
import { IconButtonComponent } from '../../../../shared/components/icon-button/icon-button.component';
|
||||||
|
import { InputComponent } from '../../../../shared/components/input/input.component';
|
||||||
import { ContinuousImageCarouselComponent } from '../../../../shared/components/continuous-image-carousel/continuous-image-carousel.component';
|
import { ContinuousImageCarouselComponent } from '../../../../shared/components/continuous-image-carousel/continuous-image-carousel.component';
|
||||||
import { UserDropdownComponent } from './user-dropdown/user-dropdown.component';
|
import { UserDropdownComponent } from './user-dropdown/user-dropdown.component';
|
||||||
|
|
||||||
@@ -21,9 +22,10 @@ import { UserDropdownComponent } from './user-dropdown/user-dropdown.component';
|
|||||||
selector: 'app-immersive-store-header',
|
selector: 'app-immersive-store-header',
|
||||||
imports: [
|
imports: [
|
||||||
RouterLink,
|
RouterLink,
|
||||||
ReactiveFormsModule,
|
ButtonComponent,
|
||||||
CartIconComponent,
|
CartIconComponent,
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
|
InputComponent,
|
||||||
ContinuousImageCarouselComponent,
|
ContinuousImageCarouselComponent,
|
||||||
UserDropdownComponent,
|
UserDropdownComponent,
|
||||||
],
|
],
|
||||||
@@ -54,7 +56,7 @@ export class ImmersiveStoreHeaderComponent {
|
|||||||
readonly logoutClick = output<void>();
|
readonly logoutClick = output<void>();
|
||||||
readonly searchSubmit = output<string>();
|
readonly searchSubmit = output<string>();
|
||||||
|
|
||||||
protected readonly searchControl = new FormControl('', { nonNullable: true });
|
protected searchTerm = '';
|
||||||
protected readonly showSearchError = signal(false);
|
protected readonly showSearchError = signal(false);
|
||||||
protected readonly isUserDropdownOpen = signal(false);
|
protected readonly isUserDropdownOpen = signal(false);
|
||||||
protected readonly checkoutRemainingTime = computed(() => {
|
protected readonly checkoutRemainingTime = computed(() => {
|
||||||
@@ -68,7 +70,7 @@ export class ImmersiveStoreHeaderComponent {
|
|||||||
|
|
||||||
protected submitSearch(event?: Event): void {
|
protected submitSearch(event?: Event): void {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
const term = this.searchControl.value.trim();
|
const term = this.searchTerm.trim();
|
||||||
if (term.length < 3) {
|
if (term.length < 3) {
|
||||||
this.showSearchError.set(true);
|
this.showSearchError.set(true);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user