Add map view toggle for fullWidthMap mode
All checks were successful
Build Docker Image / build (push) Successful in 3m25s
All checks were successful
Build Docker Image / build (push) Successful in 3m25s
- Add MapViewMode type (offers/hubs/suppliers) with cookie storage - Add view toggle button group on full-width map - Update clusterNodeType and mapPointColor based on selected view - Add translations for view options
This commit is contained in:
@@ -36,6 +36,32 @@
|
||||
<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">
|
||||
<!-- View mode toggle -->
|
||||
<div class="absolute top-4 left-4 z-10">
|
||||
<div class="btn-group shadow-lg bg-white/90 backdrop-blur rounded-lg">
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
:class="{ 'btn-active': mapViewMode === 'offers' }"
|
||||
@click="setMapViewMode('offers')"
|
||||
>
|
||||
{{ $t('catalog.views.offers') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
:class="{ 'btn-active': mapViewMode === 'hubs' }"
|
||||
@click="setMapViewMode('hubs')"
|
||||
>
|
||||
{{ $t('catalog.views.hubs') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
:class="{ 'btn-active': mapViewMode === 'suppliers' }"
|
||||
@click="setMapViewMode('suppliers')"
|
||||
>
|
||||
{{ $t('catalog.views.suppliers') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<CatalogMap
|
||||
ref="mapRef"
|
||||
@@ -217,6 +243,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
|
||||
|
||||
// Map view mode for full width map
|
||||
const { mapViewMode, setMapViewMode } = useCatalogSearch()
|
||||
|
||||
interface MapItem {
|
||||
uuid: string
|
||||
latitude?: number | null
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { LocationQuery } from 'vue-router'
|
||||
|
||||
export type SelectMode = 'product' | 'supplier' | 'hub' | null
|
||||
export type MapViewMode = 'offers' | 'hubs' | 'suppliers'
|
||||
export type DisplayMode =
|
||||
| 'map-default'
|
||||
| 'grid-products'
|
||||
@@ -214,6 +215,19 @@ export function useCatalogSearch() {
|
||||
// Text search (for filtering within current grid) - shared via useState
|
||||
const searchQuery = useState<string>('catalog-search-query', () => '')
|
||||
|
||||
// Map view mode preference (stored in cookie)
|
||||
const mapViewCookie = useCookie<MapViewMode>('catalog-map-view', {
|
||||
default: () => 'offers',
|
||||
maxAge: 60 * 60 * 24 * 365 // 1 year
|
||||
})
|
||||
const mapViewMode = computed({
|
||||
get: () => mapViewCookie.value,
|
||||
set: (val: MapViewMode) => { mapViewCookie.value = val }
|
||||
})
|
||||
const setMapViewMode = (mode: MapViewMode) => {
|
||||
mapViewCookie.value = mode
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
selectMode,
|
||||
@@ -223,6 +237,7 @@ export function useCatalogSearch() {
|
||||
hubId,
|
||||
quantity,
|
||||
searchQuery,
|
||||
mapViewMode,
|
||||
|
||||
// Colors
|
||||
entityColors,
|
||||
@@ -239,6 +254,7 @@ export function useCatalogSearch() {
|
||||
editFilter,
|
||||
clearAll,
|
||||
setLabel,
|
||||
setMapViewMode,
|
||||
|
||||
// Labels cache
|
||||
filterLabels
|
||||
|
||||
@@ -87,7 +87,9 @@ const {
|
||||
selectItem,
|
||||
removeFilter,
|
||||
editFilter,
|
||||
setLabel
|
||||
setLabel,
|
||||
mapViewMode,
|
||||
entityColors
|
||||
} = useCatalogSearch()
|
||||
|
||||
// Composables for data
|
||||
@@ -140,6 +142,12 @@ const useServerClustering = computed(() => {
|
||||
})
|
||||
|
||||
const clusterNodeType = computed(() => {
|
||||
// When in full width map mode, use mapViewMode preference
|
||||
if (!selectMode.value) {
|
||||
if (mapViewMode.value === 'offers') return 'offer'
|
||||
if (mapViewMode.value === 'hubs') return 'logistics'
|
||||
if (mapViewMode.value === 'suppliers') return 'supplier'
|
||||
}
|
||||
// For products/offers/default map show offer locations
|
||||
if (['map-default', 'grid-products', 'grid-offers', 'grid-products-from-supplier', 'grid-products-in-hub'].includes(displayMode.value)) {
|
||||
return 'offer'
|
||||
@@ -148,10 +156,13 @@ const clusterNodeType = computed(() => {
|
||||
return 'logistics'
|
||||
})
|
||||
|
||||
// Import entity colors
|
||||
const { entityColors } = useCatalogSearch()
|
||||
|
||||
const mapPointColor = computed(() => {
|
||||
// When in full width map mode, use mapViewMode preference
|
||||
if (!selectMode.value) {
|
||||
if (mapViewMode.value === 'offers') return entityColors.offer // orange
|
||||
if (mapViewMode.value === 'hubs') return entityColors.hub // green
|
||||
if (mapViewMode.value === 'suppliers') return entityColors.supplier // blue
|
||||
}
|
||||
if (cardType.value === 'supplier') return entityColors.supplier // blue
|
||||
if (cardType.value === 'hub') return entityColors.hub // green
|
||||
if (cardType.value === 'offer') return entityColors.offer // orange
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
"noOffers": "No offers found",
|
||||
"noResults": "No results found"
|
||||
},
|
||||
"views": {
|
||||
"hubs": "Hubs",
|
||||
"products": "Products",
|
||||
"suppliers": "Suppliers",
|
||||
"offers": "Offers",
|
||||
"map": "Map"
|
||||
},
|
||||
"offers": "offer | offers"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
"noOffers": "Предложения не найдены",
|
||||
"noResults": "Ничего не найдено"
|
||||
},
|
||||
"views": {
|
||||
"hubs": "Хабы",
|
||||
"products": "Товары",
|
||||
"suppliers": "Поставщики",
|
||||
"offers": "Офферы",
|
||||
"map": "Карта"
|
||||
},
|
||||
"offers": "предложение | предложения | предложений"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user