Make pins explicit and selection open info
All checks were successful
Build Docker Image / build (push) Successful in 5m24s
All checks were successful
Build Docker Image / build (push) Successful in 5m24s
This commit is contained in:
@@ -12,9 +12,20 @@
|
||||
</div>
|
||||
<h3 class="font-semibold text-base text-white">{{ entityName }}</h3>
|
||||
</div>
|
||||
<button class="btn btn-ghost btn-xs btn-circle text-white/60 hover:text-white" @click="emit('close')">
|
||||
<Icon name="lucide:x" size="16" />
|
||||
</button>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
v-if="(entityType === 'hub' || entityType === 'supplier') && entity?.uuid"
|
||||
class="rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click="emit('pin', entityType, { uuid: entity?.uuid, name: entity?.name })"
|
||||
aria-label="Pin"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
<button class="btn btn-ghost btn-xs btn-circle text-white/60 hover:text-white" @click="emit('close')">
|
||||
<Icon name="lucide:x" size="16" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -123,11 +134,12 @@
|
||||
@select="onProductSelect(product)"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity rounded-full bg-white/10 hover:bg-white/20 p-1"
|
||||
class="absolute -top-2 -right-2 rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click.stop="emit('pin', 'product', product)"
|
||||
aria-label="Pin product"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="14" class="text-white/80" />
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,11 +209,12 @@
|
||||
@select="onSupplierSelect(supplier)"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity rounded-full bg-white/10 hover:bg-white/20 p-1"
|
||||
class="absolute -top-2 -right-2 rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click.stop="emit('pin', 'supplier', supplier)"
|
||||
aria-label="Pin supplier"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="14" class="text-white/80" />
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -242,11 +255,12 @@
|
||||
@select="onHubSelect(hub)"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity rounded-full bg-white/10 hover:bg-white/20 p-1"
|
||||
class="absolute -top-2 -right-2 rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click.stop="emit('pin', 'hub', hub)"
|
||||
aria-label="Pin hub"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="14" class="text-white/80" />
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -274,11 +288,12 @@
|
||||
@select="onHubSelect(hub)"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity rounded-full bg-white/10 hover:bg-white/20 p-1"
|
||||
class="absolute -top-2 -right-2 rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click.stop="emit('pin', 'hub', hub)"
|
||||
aria-label="Pin hub"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="14" class="text-white/80" />
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,11 +38,12 @@
|
||||
@select="onSelect(item)"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity rounded-full bg-white/10 hover:bg-white/20 p-1"
|
||||
class="absolute -top-2 -right-2 rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click.stop="emit('pin', 'product', item)"
|
||||
aria-label="Pin product"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="14" class="text-white/80" />
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -62,11 +63,12 @@
|
||||
@select="onSelect(item)"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity rounded-full bg-white/10 hover:bg-white/20 p-1"
|
||||
class="absolute -top-2 -right-2 rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click.stop="emit('pin', 'hub', item)"
|
||||
aria-label="Pin hub"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="14" class="text-white/80" />
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -86,11 +88,12 @@
|
||||
@select="onSelect(item)"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity rounded-full bg-white/10 hover:bg-white/20 p-1"
|
||||
class="absolute -top-2 -right-2 rounded-full glass-bright border border-white/30 shadow-lg p-1.5 transition-transform hover:scale-105"
|
||||
@click.stop="emit('pin', 'supplier', item)"
|
||||
aria-label="Pin supplier"
|
||||
title="Pin"
|
||||
>
|
||||
<Icon name="lucide:pin" size="14" class="text-white/80" />
|
||||
<Icon name="lucide:pin" size="16" class="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -94,7 +94,8 @@ export function useCatalogSearch() {
|
||||
})
|
||||
|
||||
// Filter by bounds checkbox state from URL
|
||||
const filterByBounds = computed(() => route.query.bounds !== undefined)
|
||||
// Use explicit flag so bounds don't auto-enable filtering.
|
||||
const filterByBounds = computed(() => route.query.boundsFilter === '1')
|
||||
|
||||
// Get label for a filter (from cache or fallback to ID)
|
||||
const getLabel = (type: string, id: string | undefined): string | null => {
|
||||
@@ -261,7 +262,7 @@ export function useCatalogSearch() {
|
||||
const setBoundsInUrl = (bounds: { west: number; south: number; east: number; north: number } | null) => {
|
||||
if (bounds) {
|
||||
const boundsStr = `${bounds.west.toFixed(4)},${bounds.south.toFixed(4)},${bounds.east.toFixed(4)},${bounds.north.toFixed(4)}`
|
||||
updateQuery({ bounds: boundsStr })
|
||||
updateQuery({ bounds: boundsStr, boundsFilter: '1' })
|
||||
} else {
|
||||
updateQuery({ bounds: null })
|
||||
}
|
||||
@@ -269,7 +270,12 @@ export function useCatalogSearch() {
|
||||
|
||||
// Clear bounds from URL
|
||||
const clearBoundsFromUrl = () => {
|
||||
updateQuery({ bounds: null })
|
||||
updateQuery({ bounds: null, boundsFilter: null })
|
||||
}
|
||||
|
||||
// Explicitly enable/disable bounds filter flag in URL
|
||||
const setBoundsFilterEnabled = (enabled: boolean) => {
|
||||
updateQuery({ boundsFilter: enabled ? '1' : null })
|
||||
}
|
||||
|
||||
const openInfo = (type: InfoEntityType, uuid: string) => {
|
||||
@@ -427,6 +433,7 @@ export function useCatalogSearch() {
|
||||
setQuantity,
|
||||
setBoundsInUrl,
|
||||
clearBoundsFromUrl,
|
||||
setBoundsFilterEnabled,
|
||||
openInfo,
|
||||
closeInfo,
|
||||
setInfoTab,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
:cluster-supplier-uuid="clusterSupplierUuid"
|
||||
@select="onMapSelect"
|
||||
@bounds-change="onBoundsChange"
|
||||
@update:filter-by-bounds="$event ? setBoundsInUrl(currentMapBounds) : clearBoundsFromUrl()"
|
||||
@update:filter-by-bounds="onToggleBoundsFilter"
|
||||
>
|
||||
<!-- Panel slot - shows selection list OR info OR quote results -->
|
||||
<template #panel>
|
||||
@@ -175,7 +175,8 @@ const {
|
||||
urlBounds,
|
||||
filterByBounds,
|
||||
setBoundsInUrl,
|
||||
clearBoundsFromUrl
|
||||
clearBoundsFromUrl,
|
||||
setBoundsFilterEnabled
|
||||
} = useCatalogSearch()
|
||||
|
||||
// Info panel composable
|
||||
@@ -255,7 +256,20 @@ const getSelectionBounds = () => {
|
||||
return { west: bounds.west, south: bounds.south, east: bounds.east, north: bounds.north }
|
||||
}
|
||||
|
||||
const onToggleBoundsFilter = (enabled: boolean) => {
|
||||
if (enabled) {
|
||||
setBoundsFilterEnabled(true)
|
||||
const bounds = getSelectionBounds()
|
||||
if (bounds) {
|
||||
setBoundsInUrl(bounds)
|
||||
}
|
||||
} else {
|
||||
clearBoundsFromUrl()
|
||||
}
|
||||
}
|
||||
|
||||
const applySelectionBounds = () => {
|
||||
if (!filterByBounds.value) return
|
||||
if (!selectionBoundsBackup.value) {
|
||||
selectionBoundsBackup.value = {
|
||||
hadBounds: !!urlBounds.value,
|
||||
@@ -651,10 +665,18 @@ const onMapSelect = async (item: MapSelectItem) => {
|
||||
setLabel(infoType, itemId, itemName)
|
||||
}
|
||||
|
||||
// Handle selection from SelectionPanel - add to filter (show badge in search)
|
||||
// Handle selection from SelectionPanel - open info card (pin only via pin button)
|
||||
const onSelectItem = (type: string, item: { uuid?: string | null; name?: string | null }) => {
|
||||
if (item.uuid && item.name) {
|
||||
selectItem(type, item.uuid, item.name)
|
||||
if (!item.uuid) return
|
||||
if (type === 'hub' || type === 'supplier') {
|
||||
if (item.name) {
|
||||
setLabel(type, item.uuid, item.name)
|
||||
}
|
||||
openInfo(type, item.uuid)
|
||||
return
|
||||
}
|
||||
if (type === 'product') {
|
||||
router.push(localePath(`/catalog/products/${item.uuid}`))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user