Improve catalog UX: remove category, add offers count, dynamic layout
All checks were successful
Build Docker Image / build (push) Successful in 3m37s
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:
@@ -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<{
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"noHubs": "No hubs found",
|
||||
"noOffers": "No offers found",
|
||||
"noResults": "No results found"
|
||||
}
|
||||
},
|
||||
"offers": "offer | offers"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"noHubs": "Хабы не найдены",
|
||||
"noOffers": "Предложения не найдены",
|
||||
"noResults": "Ничего не найдено"
|
||||
}
|
||||
},
|
||||
"offers": "предложение | предложения | предложений"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user