fix(catalog): filter UX and tablet layout
Some checks failed
Architecture Governance / architecture (push) Has been cancelled

This commit is contained in:
sdarbinyan
2026-07-09 02:57:48 +04:00
parent 6409a91cb0
commit 86de2cc45b
9 changed files with 108 additions and 18 deletions

View File

@@ -4,7 +4,7 @@
</div>
@for (filter of definitions; track filter.id) {
@if (filter.enabled) {
@if (shouldRenderFilter(filter)) {
<section class="filter-group">
<button
type="button"

View File

@@ -30,6 +30,24 @@ export class CatalogFiltersPanelComponent {
return this.collapsed()[filterId] ?? false;
}
shouldRenderFilter(filter: FilterGroup): boolean {
if (!filter.enabled) {
return false;
}
if (filter.type === 'range' || filter.type === 'slider') {
const min = Number(filter.min ?? 0);
const max = Number(filter.max ?? 0);
return Number.isFinite(min) && Number.isFinite(max) && min < max;
}
if (filter.type === 'toggle') {
return true;
}
return (filter.options?.length ?? 0) > 1;
}
isSelected(filterId: string, optionValue: string): boolean {
return (this.state.values[filterId] ?? []).includes(optionValue);
}

View File

@@ -84,6 +84,13 @@
gap: 24px;
}
@media (max-width: 1024px) {
.catalog-products-section {
grid-template-columns: minmax(0, 1fr);
gap: 16px;
}
}
.catalog-left-panel {
position: sticky;
top: 16px;

View File

@@ -120,6 +120,7 @@ export class CatalogContainerComponent {
private dataSubscription?: Subscription;
private readonly backendFetchSize = 200;
private pendingScrollY: number | null = null;
private restoringScrollFromUrlSync = false;
private syncingUrl = false;
constructor() {
@@ -522,14 +523,14 @@ export class CatalogContainerComponent {
layoutLabelKey(layout: CatalogLayoutMode): string {
switch (layout) {
case 'grid':
return 'catalog.layout.grid';
return 'catalog.layoutGrid';
case 'large-grid':
return 'catalog.layout.largeGrid';
return 'catalog.layoutLargeGrid';
case 'compact-grid':
return 'catalog.layout.compactGrid';
return 'catalog.layoutCompactGrid';
case 'list':
default:
return 'catalog.layout.list';
return 'catalog.layoutList';
}
}
@@ -691,12 +692,23 @@ export class CatalogContainerComponent {
private syncUrlFromState(): void {
const queryParams = this.searchFacade.toQueryParams(this.toSearchState());
const scrollY = typeof window !== 'undefined' ? window.scrollY : null;
this.syncingUrl = true;
void this.router.navigate([], {
relativeTo: this.route,
queryParams,
replaceUrl: true,
}).finally(() => {
if (scrollY != null && typeof window !== 'undefined') {
this.restoringScrollFromUrlSync = true;
const target = Math.max(0, scrollY);
requestAnimationFrame(() => {
window.scrollTo({ top: target, behavior: 'auto' });
this.restoringScrollFromUrlSync = false;
});
}
this.syncingUrl = false;
});
}