feat(ux): implement sprint 11 user experience module

This commit is contained in:
sdarbinyan
2026-07-09 01:13:54 +04:00
parent 1a8f916942
commit 92e1bdaff8
59 changed files with 2062 additions and 25 deletions

View File

@@ -38,6 +38,24 @@
<!-- Right Actions -->
<div class="dexar-actions">
@if (userExperienceConfig.wishlist.enabled) {
<button type="button" class="dexar-ux-btn" (click)="navigateToWishlist()" [attr.aria-label]="'header.wishlist' | translate">
<span class="dexar-ux-icon"></span>
@if (userExperienceConfig.wishlist.headerBadgeEnabled && wishlistCount() > 0) {
<span class="dexar-ux-badge">{{ wishlistCount() }}</span>
}
</button>
}
@if (userExperienceConfig.compare.enabled) {
<button type="button" class="dexar-ux-btn" (click)="navigateToCompare()" [attr.aria-label]="'header.compare' | translate">
<span class="dexar-ux-icon"></span>
@if (compareCount() > 0) {
<span class="dexar-ux-badge">{{ compareCount() }}</span>
}
</button>
}
<!-- Cart Button -->
<a [routerLink]="'/cart' | langRoute" routerLinkActive="dexar-cart-active" class="dexar-cart-btn" (click)="closeMenu()">
<span class="dexar-cart-icon">

View File

@@ -632,6 +632,50 @@
flex-shrink: 0;
}
.dexar-ux-btn {
position: relative;
width: 34px;
height: 34px;
border: 1px solid #d3dad9;
border-radius: 50%;
background: rgba(255, 255, 255, 0.84);
color: #1e3c38;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: transform 0.18s ease, border-color 0.2s ease, background 0.2s ease;
}
.dexar-ux-btn:hover {
transform: translateY(-1px);
border-color: #497671;
background: #ffffff;
}
.dexar-ux-icon {
font-size: 15px;
line-height: 1;
font-weight: 700;
}
.dexar-ux-badge {
position: absolute;
right: -6px;
top: -6px;
min-width: 16px;
height: 16px;
border-radius: 999px;
background: #497671;
color: #ffffff;
font-size: 10px;
font-weight: 700;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 4px;
}
.dexar-cart-btn {
display: flex;
flex-direction: column;

View File

@@ -8,6 +8,9 @@ import { RegionSelectorComponent } from '../region-selector/region-selector.comp
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
import { TranslatePipe } from '../../i18n/translate.pipe';
import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
import { UserExperienceFacade } from '../../facades/platform/user-experience.facade';
import { ConfigService } from '../../core/config/config.service';
import { DEFAULT_USER_EXPERIENCE_CONFIG } from '../../shared/models/config';
@Component({
selector: 'app-header',
@@ -25,6 +28,12 @@ export class HeaderComponent {
private document = inject(DOCUMENT);
private langService = inject(LanguageService);
private uiRuntime = inject(UiRuntimeFacade);
private uxFacade = inject(UserExperienceFacade);
private configService = inject(ConfigService);
readonly wishlistCount = this.uxFacade.wishlistCount;
readonly compareCount = this.uxFacade.compareCount;
readonly userExperienceConfig = this.resolveUserExperienceConfig();
constructor(private cartService: CartService, private router: Router) {
this.cartItemCount = this.cartService.itemCount;
@@ -89,6 +98,18 @@ export class HeaderComponent {
});
}
navigateToWishlist(): void {
this.closeMenu();
const lang = this.langService.currentLanguage();
this.router.navigate([`/${lang}/wishlist`]);
}
navigateToCompare(): void {
this.closeMenu();
const lang = this.langService.currentLanguage();
this.router.navigate([`/${lang}/compare`]);
}
formatCartTotal(total: number): string {
const locale = this.langService.currentLanguage() === 'en'
? 'en-US'
@@ -104,4 +125,21 @@ export class HeaderComponent {
return `${amount} ${currencySymbol}`;
}
private resolveUserExperienceConfig() {
const raw = (this.configService.getBootstrapSnapshot() as any)?.userExperience ?? {};
return {
...DEFAULT_USER_EXPERIENCE_CONFIG,
...raw,
wishlist: {
...DEFAULT_USER_EXPERIENCE_CONFIG.wishlist,
...(raw.wishlist ?? {})
},
compare: {
...DEFAULT_USER_EXPERIENCE_CONFIG.compare,
...(raw.compare ?? {})
}
};
}
}