Add map view toggle for fullWidthMap mode
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:
Ruslan Bakiev
2026-01-22 18:41:38 +07:00
parent 2d86c79b06
commit 749f15131b
5 changed files with 74 additions and 4 deletions

View File

@@ -36,6 +36,32 @@
<div v-if="fullWidthMap" class="hidden lg:flex flex-1 min-h-0 py-4"> <div v-if="fullWidthMap" class="hidden lg:flex flex-1 min-h-0 py-4">
<div class="w-full"> <div class="w-full">
<div class="sticky rounded-xl overflow-hidden shadow-lg" :style="mapStyle"> <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> <ClientOnly>
<CatalogMap <CatalogMap
ref="mapRef" ref="mapRef"
@@ -217,6 +243,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { MapBounds } from '~/components/catalog/CatalogMap.vue' import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
// Map view mode for full width map
const { mapViewMode, setMapViewMode } = useCatalogSearch()
interface MapItem { interface MapItem {
uuid: string uuid: string
latitude?: number | null latitude?: number | null

View File

@@ -1,6 +1,7 @@
import type { LocationQuery } from 'vue-router' import type { LocationQuery } from 'vue-router'
export type SelectMode = 'product' | 'supplier' | 'hub' | null export type SelectMode = 'product' | 'supplier' | 'hub' | null
export type MapViewMode = 'offers' | 'hubs' | 'suppliers'
export type DisplayMode = export type DisplayMode =
| 'map-default' | 'map-default'
| 'grid-products' | 'grid-products'
@@ -214,6 +215,19 @@ export function useCatalogSearch() {
// Text search (for filtering within current grid) - shared via useState // Text search (for filtering within current grid) - shared via useState
const searchQuery = useState<string>('catalog-search-query', () => '') 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 { return {
// State // State
selectMode, selectMode,
@@ -223,6 +237,7 @@ export function useCatalogSearch() {
hubId, hubId,
quantity, quantity,
searchQuery, searchQuery,
mapViewMode,
// Colors // Colors
entityColors, entityColors,
@@ -239,6 +254,7 @@ export function useCatalogSearch() {
editFilter, editFilter,
clearAll, clearAll,
setLabel, setLabel,
setMapViewMode,
// Labels cache // Labels cache
filterLabels filterLabels

View File

@@ -87,7 +87,9 @@ const {
selectItem, selectItem,
removeFilter, removeFilter,
editFilter, editFilter,
setLabel setLabel,
mapViewMode,
entityColors
} = useCatalogSearch() } = useCatalogSearch()
// Composables for data // Composables for data
@@ -140,6 +142,12 @@ const useServerClustering = computed(() => {
}) })
const clusterNodeType = 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 // 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)) { if (['map-default', 'grid-products', 'grid-offers', 'grid-products-from-supplier', 'grid-products-in-hub'].includes(displayMode.value)) {
return 'offer' return 'offer'
@@ -148,10 +156,13 @@ const clusterNodeType = computed(() => {
return 'logistics' return 'logistics'
}) })
// Import entity colors
const { entityColors } = useCatalogSearch()
const mapPointColor = computed(() => { 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 === 'supplier') return entityColors.supplier // blue
if (cardType.value === 'hub') return entityColors.hub // green if (cardType.value === 'hub') return entityColors.hub // green
if (cardType.value === 'offer') return entityColors.offer // orange if (cardType.value === 'offer') return entityColors.offer // orange

View File

@@ -33,6 +33,13 @@
"noOffers": "No offers found", "noOffers": "No offers found",
"noResults": "No results found" "noResults": "No results found"
}, },
"views": {
"hubs": "Hubs",
"products": "Products",
"suppliers": "Suppliers",
"offers": "Offers",
"map": "Map"
},
"offers": "offer | offers" "offers": "offer | offers"
} }
} }

View File

@@ -33,6 +33,13 @@
"noOffers": "Предложения не найдены", "noOffers": "Предложения не найдены",
"noResults": "Ничего не найдено" "noResults": "Ничего не найдено"
}, },
"views": {
"hubs": "Хабы",
"products": "Товары",
"suppliers": "Поставщики",
"offers": "Офферы",
"map": "Карта"
},
"offers": "предложение | предложения | предложений" "offers": "предложение | предложения | предложений"
} }
} }