feat: add server-side clustering to CatalogPage for hubs
All checks were successful
Build Docker Image / build (push) Successful in 5m8s

This commit is contained in:
Ruslan Bakiev
2026-01-14 11:16:26 +07:00
parent b75459c8be
commit 46f8e97ee9
2 changed files with 23 additions and 3 deletions

View File

@@ -52,10 +52,13 @@
<CatalogMap
ref="mapRef"
:map-id="mapId"
:items="itemsWithCoords"
:items="useServerClustering ? [] : itemsWithCoords"
:clustered-points="useServerClustering ? clusteredNodes : []"
:use-server-clustering="useServerClustering"
:point-color="pointColor"
:hovered-item-id="hoveredId"
@select-item="onMapSelect"
@bounds-change="onBoundsChange"
/>
</ClientOnly>
</div>
@@ -97,10 +100,13 @@
<CatalogMap
ref="mobileMapRef"
:map-id="`${mapId}-mobile`"
:items="itemsWithCoords"
:items="useServerClustering ? [] : itemsWithCoords"
:clustered-points="useServerClustering ? clusteredNodes : []"
:use-server-clustering="useServerClustering"
:point-color="pointColor"
:hovered-item-id="hoveredId"
@select-item="onMapSelect"
@bounds-change="onBoundsChange"
/>
</ClientOnly>
</div>
@@ -157,6 +163,8 @@
</template>
<script setup lang="ts">
import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
interface MapItem {
uuid: string
latitude?: number | null
@@ -171,6 +179,7 @@ const props = withDefaults(defineProps<{
mapItems?: MapItem[] // Optional separate items for map (if different from list items)
loading?: boolean
withMap?: boolean
useServerClustering?: boolean // Use server-side h3 clustering for ALL points
mapId?: string
pointColor?: string
selectedId?: string
@@ -179,6 +188,7 @@ const props = withDefaults(defineProps<{
}>(), {
loading: false,
withMap: true,
useServerClustering: false,
mapId: 'catalog-map',
pointColor: '#3b82f6',
hasSubNav: true
@@ -194,10 +204,19 @@ const emit = defineEmits<{
'update:hoveredId': [uuid: string | undefined]
}>()
// Server-side clustering
const { clusteredNodes, fetchClusters } = useClusteredNodes()
const onBoundsChange = (bounds: MapBounds) => {
if (props.useServerClustering) {
fetchClusters(bounds)
}
}
// Use mapItems if provided, otherwise fall back to items
const itemsForMap = computed(() => props.mapItems || props.items)
// Filter items with valid coordinates for map
// Filter items with valid coordinates for map (client-side mode only)
const itemsWithCoords = computed(() =>
itemsForMap.value.filter(item =>
item.latitude != null &&