Fix UI issues: 3 columns, SubNav label, back button, sticky map, hover flyTo
All checks were successful
Build Docker Image / build (push) Successful in 4m14s

- Homepage roles section now shows 3 columns on medium screens
- SubNavigation catalog offers label changed to "Предложения"
- Removed back button from catalog/offers page
- ListMapLayout: sticky map with full height
- ListMapLayout: hover on card flies to location on map
This commit is contained in:
Ruslan Bakiev
2026-01-08 10:00:59 +07:00
parent 1a0305011f
commit e629025899
6 changed files with 21 additions and 13 deletions

View File

@@ -1,14 +1,14 @@
<template> <template>
<div class="flex flex-col flex-1 min-h-0"> <div class="flex flex-col flex-1 min-h-0">
<!-- Desktop: side-by-side layout --> <!-- Desktop: side-by-side layout -->
<div class="hidden lg:flex flex-1 gap-4 min-h-0"> <div class="hidden lg:flex flex-1 gap-4 min-h-0 overflow-hidden">
<!-- Left side: List (scrollable) --> <!-- Left side: List (scrollable) -->
<div class="w-2/5 overflow-y-auto pr-2"> <div class="w-2/5 overflow-y-auto pr-2">
<slot name="list" /> <slot name="list" />
</div> </div>
<!-- Right side: Map (sticky) --> <!-- Right side: Map (sticky, full height from SubNav to bottom) -->
<div class="w-3/5 rounded-lg overflow-hidden"> <div class="w-3/5 h-full rounded-lg overflow-hidden sticky top-0 self-start">
<ClientOnly> <ClientOnly>
<CatalogMap <CatalogMap
ref="mapRef" ref="mapRef"
@@ -75,6 +75,7 @@ interface MapItem {
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
items: MapItem[] items: MapItem[]
selectedItemId?: string selectedItemId?: string
hoveredItemId?: string
mapId: string mapId: string
pointColor?: string pointColor?: string
}>(), { }>(), {
@@ -136,6 +137,13 @@ watch(() => props.selectedItemId, (uuid) => {
} }
}) })
// Watch hoveredItemId and fly to it on hover
watch(() => props.hoveredItemId, (uuid) => {
if (uuid) {
flyToItem(uuid)
}
})
// Expose methods for parent components // Expose methods for parent components
defineExpose({ flyTo, flyToItem }) defineExpose({ flyTo, flyToItem })
</script> </script>

View File

@@ -25,7 +25,7 @@ const { t } = useI18n()
const sectionItems = computed(() => ({ const sectionItems = computed(() => ({
catalog: [ catalog: [
{ label: t('cabinetNav.offers'), path: '/catalog/offers' }, { label: 'Предложения', path: '/catalog/offers' },
{ label: t('cabinetNav.suppliers'), path: '/catalog/suppliers' }, { label: t('cabinetNav.suppliers'), path: '/catalog/suppliers' },
{ label: t('cabinetNav.hubs'), path: '/catalog/hubs' }, { label: t('cabinetNav.hubs'), path: '/catalog/hubs' },
], ],

View File

@@ -36,14 +36,6 @@
<!-- Offers for selected product --> <!-- Offers for selected product -->
<template v-else> <template v-else>
<!-- Back button -->
<div class="py-2 px-4 lg:px-0">
<NuxtLink :to="localePath('/catalog/offers')" class="btn btn-ghost btn-sm gap-2">
<Icon name="lucide:arrow-left" size="16" />
{{ t('common.back') }}
</NuxtLink>
</div>
<CatalogPage <CatalogPage
:items="items" :items="items"
:loading="isLoading" :loading="isLoading"

View File

@@ -15,6 +15,7 @@
v-else-if="items.length" v-else-if="items.length"
:items="itemsForMap" :items="itemsForMap"
:selected-item-id="selectedAddressId" :selected-item-id="selectedAddressId"
:hovered-item-id="hoveredAddressId"
map-id="addresses-map" map-id="addresses-map"
point-color="#10b981" point-color="#10b981"
@select-item="onSelectAddress" @select-item="onSelectAddress"
@@ -42,6 +43,8 @@
interactive interactive
:class="{ 'ring-2 ring-primary': addr.uuid === selectedAddressId }" :class="{ 'ring-2 ring-primary': addr.uuid === selectedAddressId }"
@click.prevent="onSelectAddress(addr.uuid)" @click.prevent="onSelectAddress(addr.uuid)"
@mouseenter="hoveredAddressId = addr.uuid"
@mouseleave="hoveredAddressId = undefined"
> >
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<Text size="base" weight="semibold" class="truncate">{{ addr.name }}</Text> <Text size="base" weight="semibold" class="truncate">{{ addr.name }}</Text>
@@ -92,6 +95,7 @@ const {
} = useTeamAddresses() } = useTeamAddresses()
const selectedAddressId = ref<string>() const selectedAddressId = ref<string>()
const hoveredAddressId = ref<string>()
// Map items for ListMapLayout // Map items for ListMapLayout
const itemsForMap = computed(() => { const itemsForMap = computed(() => {

View File

@@ -26,6 +26,7 @@
v-else-if="items.length" v-else-if="items.length"
:items="itemsForMap" :items="itemsForMap"
:selected-item-id="selectedOrderId" :selected-item-id="selectedOrderId"
:hovered-item-id="hoveredOrderId"
map-id="orders-map" map-id="orders-map"
point-color="#6366f1" point-color="#6366f1"
@select-item="onSelectOrder" @select-item="onSelectOrder"
@@ -42,6 +43,8 @@
class="cursor-pointer" class="cursor-pointer"
:class="{ 'ring-2 ring-primary': order.uuid === selectedOrderId }" :class="{ 'ring-2 ring-primary': order.uuid === selectedOrderId }"
@click="onSelectOrder(order.uuid)" @click="onSelectOrder(order.uuid)"
@mouseenter="hoveredOrderId = order.uuid"
@mouseleave="hoveredOrderId = undefined"
> >
<Stack gap="4"> <Stack gap="4">
<Stack direction="row" justify="between" align="center"> <Stack direction="row" justify="between" align="center">
@@ -132,6 +135,7 @@ const {
const hasError = ref(false) const hasError = ref(false)
const error = ref('') const error = ref('')
const selectedOrderId = ref<string>() const selectedOrderId = ref<string>()
const hoveredOrderId = ref<string>()
// Map items for ListMapLayout (use source location coordinates) // Map items for ListMapLayout (use source location coordinates)
const itemsForMap = computed(() => { const itemsForMap = computed(() => {

View File

@@ -5,7 +5,7 @@
<Heading :level="2">{{ $t('roles.title') }}</Heading> <Heading :level="2">{{ $t('roles.title') }}</Heading>
<Text align="center" tone="muted">{{ $t('about.description') }}</Text> <Text align="center" tone="muted">{{ $t('about.description') }}</Text>
<Grid :cols="1" :lg="3" :gap="6"> <Grid :cols="1" :md="3" :gap="6">
<Card padding="lg"> <Card padding="lg">
<Stack gap="4" align="center"> <Stack gap="4" align="center">
<IconCircle tone="primary">🏭</IconCircle> <IconCircle tone="primary">🏭</IconCircle>