Improve catalog UX: remove category, add offers count, dynamic layout
All checks were successful
Build Docker Image / build (push) Successful in 3m37s

- ProductCard: remove category field, add offersCount display
- CatalogPage: add fullWidthMap prop for map-only view
- catalog/index: pass fullWidthMap based on selectMode
- i18n: add offers pluralization
This commit is contained in:
Ruslan Bakiev
2026-01-22 16:59:33 +07:00
parent 6da5bf10c9
commit 39f8364edb
5 changed files with 41 additions and 10 deletions

View File

@@ -14,10 +14,10 @@
]"
>
<Stack gap="2">
<Stack gap="1">
<Text size="base" weight="semibold">{{ product.name }}</Text>
<Text tone="muted">{{ product.categoryName || t('catalogProduct.labels.category_unknown') }}</Text>
</Stack>
<Text size="base" weight="semibold">{{ product.name }}</Text>
<Text v-if="product.offersCount" tone="muted" size="sm">
{{ product.offersCount }} {{ t('catalog.offers', product.offersCount) }}
</Text>
<Text v-if="product.description && !compact" tone="muted" size="sm">{{ product.description }}</Text>
</Stack>
</Card>
@@ -30,8 +30,8 @@ import { NuxtLink } from '#components'
interface Product {
uuid?: string | null
name?: string | null
categoryName?: string | null
description?: string | null
offersCount?: number | null
}
const props = defineProps<{

View File

@@ -30,10 +30,32 @@
</div>
</div>
<!-- With Map: Split Layout -->
<!-- With Map: Split Layout or Full Width Map -->
<template v-if="withMap">
<!-- Desktop: side-by-side -->
<div class="hidden lg:flex flex-1 gap-4 min-h-0 py-4">
<!-- Full Width Map Mode (after selection) -->
<div v-if="fullWidthMap" class="hidden lg:flex flex-1 min-h-0 py-4">
<div class="w-full">
<div class="sticky rounded-xl overflow-hidden shadow-lg" :style="mapStyle">
<ClientOnly>
<CatalogMap
ref="mapRef"
:map-id="mapId"
:items="useServerClustering ? [] : itemsWithCoords"
:clustered-points="useServerClustering ? clusteredNodes : []"
:use-server-clustering="useServerClustering"
:point-color="pointColor"
:hovered-item-id="hoveredId"
:hovered-item="hoveredItem"
@select-item="onMapSelect"
@bounds-change="onBoundsChange"
/>
</ClientOnly>
</div>
</div>
</div>
<!-- Desktop: side-by-side (during selection) -->
<div v-else class="hidden lg:flex flex-1 gap-4 min-h-0 py-4">
<!-- Left: List (scrollable) -->
<div class="w-2/5 overflow-y-auto pr-2">
<Stack gap="4">
@@ -209,6 +231,7 @@ const props = withDefaults(defineProps<{
mapItems?: MapItem[] // Optional separate items for map (if different from list items)
loading?: boolean
withMap?: boolean
fullWidthMap?: boolean // Map takes full width (no grid), used after filter selection
useServerClustering?: boolean // Use server-side h3 clustering for ALL points
clusterNodeType?: string // Node type for clustering: 'logistics' | 'offer' | 'supplier'
mapId?: string
@@ -221,6 +244,7 @@ const props = withDefaults(defineProps<{
}>(), {
loading: false,
withMap: true,
fullWidthMap: false,
useServerClustering: false,
clusterNodeType: 'logistics',
mapId: 'catalog-map',

View File

@@ -5,6 +5,7 @@
:total-count="currentItems.length"
:grid-columns="3"
:with-map="showMap"
:full-width-map="fullWidthMap"
:use-server-clustering="useServerClustering"
:cluster-node-type="clusterNodeType"
map-id="unified-catalog-map"
@@ -126,6 +127,10 @@ const cardType = computed(() => {
const showMap = computed(() => displayMode.value !== 'hero')
// Full width map when not in select mode (after filter is selected)
// selectMode is active = grid + map, after selection = only map
const fullWidthMap = computed(() => !selectMode.value && displayMode.value !== 'hero')
// Use server clustering for grids that need it
const useServerClustering = computed(() => {
// Products grid - show offers clusters

View File

@@ -32,6 +32,7 @@
"noHubs": "No hubs found",
"noOffers": "No offers found",
"noResults": "No results found"
}
},
"offers": "offer | offers"
}
}

View File

@@ -32,6 +32,7 @@
"noHubs": "Хабы не найдены",
"noOffers": "Предложения не найдены",
"noResults": "Ничего не найдено"
}
},
"offers": "предложение | предложения | предложений"
}
}