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="2">
|
||||||
<Stack gap="1">
|
|
||||||
<Text size="base" weight="semibold">{{ product.name }}</Text>
|
<Text size="base" weight="semibold">{{ product.name }}</Text>
|
||||||
<Text tone="muted">{{ product.categoryName || t('catalogProduct.labels.category_unknown') }}</Text>
|
<Text v-if="product.offersCount" tone="muted" size="sm">
|
||||||
</Stack>
|
{{ product.offersCount }} {{ t('catalog.offers', product.offersCount) }}
|
||||||
|
</Text>
|
||||||
<Text v-if="product.description && !compact" tone="muted" size="sm">{{ product.description }}</Text>
|
<Text v-if="product.description && !compact" tone="muted" size="sm">{{ product.description }}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -30,8 +30,8 @@ import { NuxtLink } from '#components'
|
|||||||
interface Product {
|
interface Product {
|
||||||
uuid?: string | null
|
uuid?: string | null
|
||||||
name?: string | null
|
name?: string | null
|
||||||
categoryName?: string | null
|
|
||||||
description?: string | null
|
description?: string | null
|
||||||
|
offersCount?: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|||||||
@@ -30,10 +30,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- With Map: Split Layout -->
|
<!-- With Map: Split Layout or Full Width Map -->
|
||||||
<template v-if="withMap">
|
<template v-if="withMap">
|
||||||
<!-- Desktop: side-by-side -->
|
<!-- Full Width Map Mode (after selection) -->
|
||||||
<div class="hidden lg:flex flex-1 gap-4 min-h-0 py-4">
|
<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) -->
|
<!-- Left: List (scrollable) -->
|
||||||
<div class="w-2/5 overflow-y-auto pr-2">
|
<div class="w-2/5 overflow-y-auto pr-2">
|
||||||
<Stack gap="4">
|
<Stack gap="4">
|
||||||
@@ -209,6 +231,7 @@ const props = withDefaults(defineProps<{
|
|||||||
mapItems?: MapItem[] // Optional separate items for map (if different from list items)
|
mapItems?: MapItem[] // Optional separate items for map (if different from list items)
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
withMap?: 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
|
useServerClustering?: boolean // Use server-side h3 clustering for ALL points
|
||||||
clusterNodeType?: string // Node type for clustering: 'logistics' | 'offer' | 'supplier'
|
clusterNodeType?: string // Node type for clustering: 'logistics' | 'offer' | 'supplier'
|
||||||
mapId?: string
|
mapId?: string
|
||||||
@@ -221,6 +244,7 @@ const props = withDefaults(defineProps<{
|
|||||||
}>(), {
|
}>(), {
|
||||||
loading: false,
|
loading: false,
|
||||||
withMap: true,
|
withMap: true,
|
||||||
|
fullWidthMap: false,
|
||||||
useServerClustering: false,
|
useServerClustering: false,
|
||||||
clusterNodeType: 'logistics',
|
clusterNodeType: 'logistics',
|
||||||
mapId: 'catalog-map',
|
mapId: 'catalog-map',
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
:total-count="currentItems.length"
|
:total-count="currentItems.length"
|
||||||
:grid-columns="3"
|
:grid-columns="3"
|
||||||
:with-map="showMap"
|
:with-map="showMap"
|
||||||
|
:full-width-map="fullWidthMap"
|
||||||
:use-server-clustering="useServerClustering"
|
:use-server-clustering="useServerClustering"
|
||||||
:cluster-node-type="clusterNodeType"
|
:cluster-node-type="clusterNodeType"
|
||||||
map-id="unified-catalog-map"
|
map-id="unified-catalog-map"
|
||||||
@@ -126,6 +127,10 @@ const cardType = computed(() => {
|
|||||||
|
|
||||||
const showMap = computed(() => displayMode.value !== 'hero')
|
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
|
// Use server clustering for grids that need it
|
||||||
const useServerClustering = computed(() => {
|
const useServerClustering = computed(() => {
|
||||||
// Products grid - show offers clusters
|
// Products grid - show offers clusters
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"noHubs": "No hubs found",
|
"noHubs": "No hubs found",
|
||||||
"noOffers": "No offers found",
|
"noOffers": "No offers found",
|
||||||
"noResults": "No results found"
|
"noResults": "No results found"
|
||||||
}
|
},
|
||||||
|
"offers": "offer | offers"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"noHubs": "Хабы не найдены",
|
"noHubs": "Хабы не найдены",
|
||||||
"noOffers": "Предложения не найдены",
|
"noOffers": "Предложения не найдены",
|
||||||
"noResults": "Ничего не найдено"
|
"noResults": "Ничего не найдено"
|
||||||
}
|
},
|
||||||
|
"offers": "предложение | предложения | предложений"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user