Fix catalog UI issues
All checks were successful
Build Docker Image / build (push) Successful in 3m31s
All checks were successful
Build Docker Image / build (push) Successful in 3m31s
1. Fix navbar height - prevent tag wrapping with overflow-hidden 2. Fix translation keys for mode labels and search form labels 3. Fix SelectionPanel - white glass header/search, no top gap 4. Map click fills active selector - emit full properties from map
This commit is contained in:
@@ -62,7 +62,7 @@ const props = withDefaults(defineProps<{
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'select-item': [uuid: string]
|
||||
'select-item': [uuid: string, properties?: Record<string, any>]
|
||||
'bounds-change': [bounds: MapBounds]
|
||||
}>()
|
||||
|
||||
@@ -428,11 +428,12 @@ const initServerClusteringLayers = async (map: MapboxMapType) => {
|
||||
})
|
||||
})
|
||||
|
||||
// Click on individual point
|
||||
// Click on individual point - emit full properties
|
||||
map.on('click', 'server-points', (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: ['server-points'] })
|
||||
if (!features.length) return
|
||||
emit('select-item', features[0].properties?.id)
|
||||
const props = features[0].properties || {}
|
||||
emit('select-item', props.id, props)
|
||||
})
|
||||
|
||||
map.on('mouseenter', 'server-clusters', () => { map.getCanvas().style.cursor = 'pointer' })
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-3">
|
||||
<!-- Header (sticky at top) -->
|
||||
<div class="flex items-center justify-between sticky top-0 bg-base-100/80 backdrop-blur-sm -mx-4 px-4 py-2 -mt-4 z-10">
|
||||
<h3 class="font-semibold text-lg">{{ title }}</h3>
|
||||
<button class="btn btn-ghost btn-sm btn-circle" @click="emit('close')">
|
||||
<Icon name="lucide:x" size="18" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Search input (sticky below header) -->
|
||||
<div class="sticky top-10 bg-base-100/80 backdrop-blur-sm -mx-4 px-4 pb-2 z-10">
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Header + Search (white glass, sticky) -->
|
||||
<div class="sticky top-0 z-10 -m-4 mb-0 p-3 rounded-t-xl bg-white/90 backdrop-blur-md border-b border-white/20">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="font-semibold text-base text-base-content">{{ title }}</h3>
|
||||
<button class="btn btn-ghost btn-xs btn-circle text-base-content/60 hover:text-base-content" @click="emit('close')">
|
||||
<Icon name="lucide:x" size="16" />
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
:placeholder="searchPlaceholder"
|
||||
class="input input-bordered input-sm w-full"
|
||||
class="input input-sm w-full bg-white/50 border-base-300/50 text-base-content placeholder:text-base-content/50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- List -->
|
||||
<div class="-mx-1 px-1">
|
||||
<div class="flex-1 pt-3">
|
||||
<div v-if="loading" class="flex items-center justify-center py-8">
|
||||
<span class="loading loading-spinner loading-md" />
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
: (glassStyle ? 'text-white/70 hover:text-white hover:bg-white/10' : 'text-base-content/70 hover:text-base-content hover:bg-base-200')"
|
||||
@click="$emit('set-catalog-mode', 'explore')"
|
||||
>
|
||||
TradeScanner
|
||||
{{ $t('catalog.modes.explore') }}
|
||||
</button>
|
||||
<button
|
||||
class="px-3 py-1 text-sm font-medium rounded-lg transition-colors"
|
||||
@@ -29,7 +29,7 @@
|
||||
: (glassStyle ? 'text-white/70 hover:text-white hover:bg-white/10' : 'text-base-content/70 hover:text-base-content hover:bg-base-200')"
|
||||
@click="$emit('set-catalog-mode', 'quote')"
|
||||
>
|
||||
Search
|
||||
{{ $t('catalog.modes.quote') }}
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
@@ -44,7 +44,7 @@
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-base-200/50 rounded-l-full transition-colors min-w-0"
|
||||
@click="$emit('edit-token', 'product')"
|
||||
>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.quote.product') }}</div>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.filters.product') }}</div>
|
||||
<div class="font-medium truncate text-base-content">{{ productLabel || $t('catalog.quote.selectProduct') }}</div>
|
||||
</button>
|
||||
<!-- Hub segment -->
|
||||
@@ -52,7 +52,7 @@
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-base-200/50 transition-colors min-w-0"
|
||||
@click="$emit('edit-token', 'hub')"
|
||||
>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.quote.hub') }}</div>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.filters.hub') }}</div>
|
||||
<div class="font-medium truncate text-base-content">{{ hubLabel || $t('catalog.quote.selectHub') }}</div>
|
||||
</button>
|
||||
<!-- Quantity segment -->
|
||||
@@ -60,7 +60,7 @@
|
||||
class="flex-1 px-4 py-2 text-left hover:bg-base-200/50 transition-colors min-w-0"
|
||||
@click="$emit('edit-token', 'quantity')"
|
||||
>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.quote.quantity') }}</div>
|
||||
<div class="text-xs text-base-content/60">{{ $t('catalog.filters.quantity') }}</div>
|
||||
<div class="font-medium text-base-content">{{ quantity ? `${quantity} ${$t('units.t')}` : '—' }}</div>
|
||||
</button>
|
||||
<!-- Search button inside -->
|
||||
@@ -83,8 +83,8 @@
|
||||
>
|
||||
<Icon name="lucide:search" size="22" class="text-primary flex-shrink-0" />
|
||||
|
||||
<!-- Tokens + input inline -->
|
||||
<div class="flex items-center gap-2 flex-wrap flex-1 min-w-0">
|
||||
<!-- Tokens + input inline (no wrap to prevent height change) -->
|
||||
<div class="flex items-center gap-2 flex-1 min-w-0 overflow-hidden">
|
||||
<!-- Active filter tokens (outline style with icon in circle) -->
|
||||
<div
|
||||
v-for="token in activeTokens"
|
||||
|
||||
@@ -265,16 +265,20 @@ const onBoundsChange = (bounds: MapBounds) => {
|
||||
}
|
||||
|
||||
// Handle selection from map
|
||||
const onMapSelect = (uuid: string) => {
|
||||
const onMapSelect = (uuid: string, properties?: Record<string, any>) => {
|
||||
const item = props.items.find(i => i.uuid === uuid)
|
||||
if (item) {
|
||||
selectedMapItem.value = item
|
||||
emit('select', item)
|
||||
} else if (props.useServerClustering) {
|
||||
// For server clustering, item might not be in props.items
|
||||
// Create minimal item with just uuid
|
||||
selectedMapItem.value = { uuid }
|
||||
emit('select', { uuid })
|
||||
// For server clustering, include properties from cluster data
|
||||
const mapItem: MapItem = {
|
||||
uuid,
|
||||
name: properties?.name,
|
||||
...properties
|
||||
}
|
||||
selectedMapItem.value = mapItem
|
||||
emit('select', mapItem)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,43 @@ const mapPointColor = computed(() => {
|
||||
|
||||
// Handle map item selection
|
||||
const onMapSelect = (item: any) => {
|
||||
// Navigate to offer detail page if in quote mode with results
|
||||
// If in selection mode, use map click to fill the selector
|
||||
if (selectMode.value && item.uuid) {
|
||||
const itemName = item.name || item.uuid.slice(0, 8) + '...'
|
||||
|
||||
// For hubs selection - click on hub fills hub selector
|
||||
if (selectMode.value === 'hub' && mapViewMode.value === 'hubs') {
|
||||
selectItem('hub', item.uuid, itemName)
|
||||
showQuoteResults.value = false
|
||||
offers.value = []
|
||||
return
|
||||
}
|
||||
|
||||
// For supplier selection - click on supplier fills supplier selector
|
||||
if (selectMode.value === 'supplier' && mapViewMode.value === 'suppliers') {
|
||||
selectItem('supplier', item.uuid, itemName)
|
||||
showQuoteResults.value = false
|
||||
offers.value = []
|
||||
return
|
||||
}
|
||||
|
||||
// For product selection viewing offers - try to find product in loaded list
|
||||
if (selectMode.value === 'product' && mapViewMode.value === 'offers') {
|
||||
// The offer has product info - we'll look it up from the products list if loaded
|
||||
// or just use the offer's product_uuid if available
|
||||
const product = products.value.find((p: any) => p.uuid === item.productUuid)
|
||||
if (product) {
|
||||
selectItem('product', product.uuid, product.name || itemName)
|
||||
} else if (item.productUuid) {
|
||||
selectItem('product', item.productUuid, item.productName || itemName)
|
||||
}
|
||||
showQuoteResults.value = false
|
||||
offers.value = []
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Default behavior for quote mode etc
|
||||
if (catalogMode.value === 'quote' && item.uuid) {
|
||||
console.log('Selected from map:', item)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user