diff --git a/app/components/catalog/CatalogMap.vue b/app/components/catalog/CatalogMap.vue
index 714001c..8699df4 100644
--- a/app/components/catalog/CatalogMap.vue
+++ b/app/components/catalog/CatalogMap.vue
@@ -208,12 +208,7 @@ const initClientClusteringLayers = (map: MapboxMapType) => {
filter: ['!', ['has', 'point_count']],
paint: {
'circle-radius': 12,
- 'circle-color': [
- 'case',
- ['==', ['get', 'uuid'], props.hoveredItemId || ''],
- '#facc15', // yellow when hovered
- props.pointColor
- ],
+ 'circle-color': props.pointColor,
'circle-stroke-width': 3,
'circle-stroke-color': '#ffffff'
}
@@ -260,6 +255,36 @@ const initClientClusteringLayers = (map: MapboxMapType) => {
map.on('mouseenter', 'unclustered-point', () => { map.getCanvas().style.cursor = 'pointer' })
map.on('mouseleave', 'unclustered-point', () => { map.getCanvas().style.cursor = '' })
+ // Hovered point layer (on top of everything) - "target" effect with border
+ map.addSource(hoveredSourceId.value, {
+ type: 'geojson',
+ data: hoveredPointGeoJson.value
+ })
+ // Outer ring (white)
+ map.addLayer({
+ id: 'hovered-point-ring',
+ type: 'circle',
+ source: hoveredSourceId.value,
+ paint: {
+ 'circle-radius': 20,
+ 'circle-color': 'transparent',
+ 'circle-stroke-width': 3,
+ 'circle-stroke-color': '#ffffff'
+ }
+ })
+ // Inner point (same as entity color)
+ map.addLayer({
+ id: 'hovered-point-layer',
+ type: 'circle',
+ source: hoveredSourceId.value,
+ paint: {
+ 'circle-radius': 14,
+ 'circle-color': props.pointColor,
+ 'circle-stroke-width': 3,
+ 'circle-stroke-color': '#ffffff'
+ }
+ })
+
// Auto-fit bounds to all items
if (!didFitBounds.value && props.items.length > 0) {
const bounds = new LngLatBounds()
@@ -312,12 +337,7 @@ const initServerClusteringLayers = (map: MapboxMapType) => {
filter: ['==', ['get', 'count'], 1],
paint: {
'circle-radius': 12,
- 'circle-color': [
- 'case',
- ['==', ['get', 'id'], props.hoveredItemId || ''],
- '#facc15', // yellow when hovered
- props.pointColor
- ],
+ 'circle-color': props.pointColor,
'circle-stroke-width': 3,
'circle-stroke-color': '#ffffff'
}
@@ -365,18 +385,31 @@ const initServerClusteringLayers = (map: MapboxMapType) => {
map.on('mouseenter', 'server-points', () => { map.getCanvas().style.cursor = 'pointer' })
map.on('mouseleave', 'server-points', () => { map.getCanvas().style.cursor = '' })
- // Hovered point layer (on top of everything)
+ // Hovered point layer (on top of everything) - "target" effect with border
map.addSource(hoveredSourceId.value, {
type: 'geojson',
data: hoveredPointGeoJson.value
})
+ // Outer ring (white)
+ map.addLayer({
+ id: 'hovered-point-ring',
+ type: 'circle',
+ source: hoveredSourceId.value,
+ paint: {
+ 'circle-radius': 20,
+ 'circle-color': 'transparent',
+ 'circle-stroke-width': 3,
+ 'circle-stroke-color': '#ffffff'
+ }
+ })
+ // Inner point (same as entity color)
map.addLayer({
id: 'hovered-point-layer',
type: 'circle',
source: hoveredSourceId.value,
paint: {
'circle-radius': 14,
- 'circle-color': '#3b82f6',
+ 'circle-color': props.pointColor,
'circle-stroke-width': 3,
'circle-stroke-color': '#ffffff'
}
diff --git a/app/components/navigation/MainNavigation.vue b/app/components/navigation/MainNavigation.vue
index 369ea67..987aa01 100644
--- a/app/components/navigation/MainNavigation.vue
+++ b/app/components/navigation/MainNavigation.vue
@@ -27,7 +27,8 @@
@@ -204,6 +205,7 @@
diff --git a/app/composables/useCatalogSearch.ts b/app/composables/useCatalogSearch.ts
index ff9f361..eedc62c 100644
--- a/app/composables/useCatalogSearch.ts
+++ b/app/composables/useCatalogSearch.ts
@@ -12,7 +12,7 @@ export type DisplayMode =
| 'grid-offers'
export interface SearchFilter {
- type: 'product' | 'supplier' | 'hub' | 'location' | 'quantity'
+ type: 'product' | 'supplier' | 'hub' | 'quantity'
id: string
label: string
}
@@ -22,16 +22,22 @@ export interface SearchState {
product: { id: string; name: string } | null
supplier: { id: string; name: string } | null
hub: { id: string; name: string } | null
- location: { id: string; name: string } | null
quantity: string | null
}
+// Color scheme for entity types
+export const entityColors = {
+ product: '#f97316', // orange
+ supplier: '#3b82f6', // blue
+ hub: '#22c55e', // green
+ offer: '#f97316' // orange (same as product context)
+} as const
+
// Filter labels cache (to show names instead of UUIDs)
const filterLabels = ref>>({
product: {},
supplier: {},
- hub: {},
- location: {}
+ hub: {}
})
export function useCatalogSearch() {
@@ -51,7 +57,6 @@ export function useCatalogSearch() {
const productId = computed(() => route.query.product as string | undefined)
const supplierId = computed(() => route.query.supplier as string | undefined)
const hubId = computed(() => route.query.hub as string | undefined)
- const locationId = computed(() => route.query.location as string | undefined)
const quantity = computed(() => route.query.qty as string | undefined)
// Get label for a filter (from cache or fallback to ID)
@@ -96,14 +101,6 @@ export function useCatalogSearch() {
icon: 'lucide:map-pin'
})
}
- if (locationId.value) {
- tokens.push({
- type: 'location',
- id: locationId.value,
- label: getLabel('location', locationId.value) || t('catalog.filters.location'),
- icon: 'lucide:navigation'
- })
- }
if (quantity.value) {
tokens.push({
type: 'quantity',
@@ -129,10 +126,8 @@ export function useCatalogSearch() {
if (!hubId.value && selectMode.value !== 'hub') {
chips.push({ type: 'hub', label: t('catalog.filters.hub') })
}
- if (!locationId.value) {
- chips.push({ type: 'location', label: t('catalog.filters.location') })
- }
- if (!quantity.value) {
+ // Quantity only available after product is selected
+ if (productId.value && !quantity.value) {
chips.push({ type: 'quantity', label: t('catalog.filters.quantity') })
}
@@ -226,10 +221,12 @@ export function useCatalogSearch() {
productId,
supplierId,
hubId,
- locationId,
quantity,
searchQuery,
+ // Colors
+ entityColors,
+
// Computed
activeTokens,
availableChips,
diff --git a/app/pages/catalog/index.vue b/app/pages/catalog/index.vue
index 2e75691..83f8b43 100644
--- a/app/pages/catalog/index.vue
+++ b/app/pages/catalog/index.vue
@@ -143,11 +143,14 @@ const clusterNodeType = computed(() => {
return 'logistics'
})
+// Import entity colors
+const { entityColors } = useCatalogSearch()
+
const mapPointColor = computed(() => {
- if (cardType.value === 'supplier') return '#3b82f6'
- if (cardType.value === 'hub') return '#10b981'
- if (cardType.value === 'offer') return '#22c55e'
- return '#f59e0b'
+ if (cardType.value === 'supplier') return entityColors.supplier // blue
+ if (cardType.value === 'hub') return entityColors.hub // green
+ if (cardType.value === 'offer') return entityColors.offer // orange
+ return entityColors.product // orange
})
const headerText = computed(() => {
diff --git a/i18n/locales/en/catalog.json b/i18n/locales/en/catalog.json
index 1645b19..c4e1eee 100644
--- a/i18n/locales/en/catalog.json
+++ b/i18n/locales/en/catalog.json
@@ -4,7 +4,6 @@
"product": "Product",
"supplier": "Supplier",
"hub": "Hub",
- "location": "Location",
"quantity": "Quantity"
},
"search": {
diff --git a/i18n/locales/ru/catalog.json b/i18n/locales/ru/catalog.json
index 7280e7f..70f60e1 100644
--- a/i18n/locales/ru/catalog.json
+++ b/i18n/locales/ru/catalog.json
@@ -4,7 +4,6 @@
"product": "Товар",
"supplier": "Поставщик",
"hub": "Хаб",
- "location": "Локация",
"quantity": "Количество"
},
"search": {