Center MainNav vertically on home hero, add fading title
All checks were successful
Build Docker Image / build (push) Successful in 3m47s
All checks were successful
Build Docker Image / build (push) Successful in 3m47s
This commit is contained in:
@@ -23,6 +23,12 @@ export function useCatalogInfo() {
|
|||||||
const activeTab = ref<string>('products')
|
const activeTab = ref<string>('products')
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
|
|
||||||
|
// Separate loading states for each tab
|
||||||
|
const isLoadingProducts = ref(false)
|
||||||
|
const isLoadingHubs = ref(false)
|
||||||
|
const isLoadingSuppliers = ref(false)
|
||||||
|
const isLoadingOffers = ref(false)
|
||||||
|
|
||||||
// Load hub info: hub details + products + suppliers
|
// Load hub info: hub details + products + suppliers
|
||||||
const loadHubInfo = async (uuid: string) => {
|
const loadHubInfo = async (uuid: string) => {
|
||||||
try {
|
try {
|
||||||
@@ -35,7 +41,12 @@ export function useCatalogInfo() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load offers near hub and group by product
|
// Set default active tab to offers (first step shows products)
|
||||||
|
activeTab.value = 'offers'
|
||||||
|
|
||||||
|
// Load products (offers grouped by product)
|
||||||
|
isLoadingProducts.value = true
|
||||||
|
try {
|
||||||
const offersData = await execute(
|
const offersData = await execute(
|
||||||
NearestOffersDocument,
|
NearestOffersDocument,
|
||||||
{
|
{
|
||||||
@@ -62,11 +73,11 @@ export function useCatalogInfo() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
relatedProducts.value = Array.from(productsMap.values())
|
relatedProducts.value = Array.from(productsMap.values())
|
||||||
|
} finally {
|
||||||
|
isLoadingProducts.value = false
|
||||||
|
}
|
||||||
|
|
||||||
// Set default active tab to offers (first step shows products)
|
// Note: Suppliers and Offers loaded after product selection via loadOffersForHub
|
||||||
activeTab.value = 'offers'
|
|
||||||
|
|
||||||
// Note: Suppliers loaded after product selection via loadOffersForHub
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading hub info:', error)
|
console.error('Error loading hub info:', error)
|
||||||
}
|
}
|
||||||
@@ -99,7 +110,12 @@ export function useCatalogInfo() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load offers near supplier and group by product
|
// Set default active tab to offers (first step shows products)
|
||||||
|
activeTab.value = 'offers'
|
||||||
|
|
||||||
|
// Load products (offers grouped by product)
|
||||||
|
isLoadingProducts.value = true
|
||||||
|
try {
|
||||||
const offersData = await execute(
|
const offersData = await execute(
|
||||||
NearestOffersDocument,
|
NearestOffersDocument,
|
||||||
{
|
{
|
||||||
@@ -126,9 +142,9 @@ export function useCatalogInfo() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
relatedProducts.value = Array.from(productsMap.values())
|
relatedProducts.value = Array.from(productsMap.values())
|
||||||
|
} finally {
|
||||||
// Set default active tab to offers (first step shows products)
|
isLoadingProducts.value = false
|
||||||
activeTab.value = 'offers'
|
}
|
||||||
|
|
||||||
// Note: Hubs will be loaded after product selection
|
// Note: Hubs will be loaded after product selection
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -148,37 +164,6 @@ export function useCatalogInfo() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load hubs near offer coordinates
|
|
||||||
const hubsData = await execute(
|
|
||||||
NearestHubsDocument,
|
|
||||||
{
|
|
||||||
lat: entity.value.latitude,
|
|
||||||
lon: entity.value.longitude,
|
|
||||||
radius: 1000,
|
|
||||||
limit: 12
|
|
||||||
},
|
|
||||||
'public',
|
|
||||||
'geo'
|
|
||||||
)
|
|
||||||
relatedHubs.value = hubsData?.nearestHubs || []
|
|
||||||
|
|
||||||
// If offer has supplier UUID, load supplier profile
|
|
||||||
if (entity.value?.teamUuid) {
|
|
||||||
try {
|
|
||||||
const supplierData = await execute(
|
|
||||||
GetSupplierProfileDocument,
|
|
||||||
{ uuid: entity.value.teamUuid },
|
|
||||||
'public',
|
|
||||||
'exchange'
|
|
||||||
)
|
|
||||||
relatedSuppliers.value = supplierData?.getSupplierProfile
|
|
||||||
? [supplierData.getSupplierProfile]
|
|
||||||
: []
|
|
||||||
} catch (e) {
|
|
||||||
// Supplier might not exist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default active tab to hubs
|
// Set default active tab to hubs
|
||||||
activeTab.value = 'hubs'
|
activeTab.value = 'hubs'
|
||||||
|
|
||||||
@@ -191,6 +176,43 @@ export function useCatalogInfo() {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load hubs near offer coordinates
|
||||||
|
isLoadingHubs.value = true
|
||||||
|
execute(
|
||||||
|
NearestHubsDocument,
|
||||||
|
{
|
||||||
|
lat: entity.value.latitude,
|
||||||
|
lon: entity.value.longitude,
|
||||||
|
radius: 1000,
|
||||||
|
limit: 12
|
||||||
|
},
|
||||||
|
'public',
|
||||||
|
'geo'
|
||||||
|
).then(hubsData => {
|
||||||
|
relatedHubs.value = hubsData?.nearestHubs || []
|
||||||
|
}).finally(() => {
|
||||||
|
isLoadingHubs.value = false
|
||||||
|
})
|
||||||
|
|
||||||
|
// If offer has supplier UUID, load supplier profile
|
||||||
|
if (entity.value?.teamUuid) {
|
||||||
|
isLoadingSuppliers.value = true
|
||||||
|
execute(
|
||||||
|
GetSupplierProfileDocument,
|
||||||
|
{ uuid: entity.value.teamUuid },
|
||||||
|
'public',
|
||||||
|
'exchange'
|
||||||
|
).then(supplierData => {
|
||||||
|
relatedSuppliers.value = supplierData?.getSupplierProfile
|
||||||
|
? [supplierData.getSupplierProfile]
|
||||||
|
: []
|
||||||
|
}).catch(() => {
|
||||||
|
// Supplier might not exist
|
||||||
|
}).finally(() => {
|
||||||
|
isLoadingSuppliers.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading offer info:', error)
|
console.error('Error loading offer info:', error)
|
||||||
}
|
}
|
||||||
@@ -205,6 +227,11 @@ export function useCatalogInfo() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load offers
|
||||||
|
isLoadingOffers.value = true
|
||||||
|
isLoadingSuppliers.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
// Find offers near hub for this product WITH routes calculated on backend
|
// Find offers near hub for this product WITH routes calculated on backend
|
||||||
const offersData = await execute(
|
const offersData = await execute(
|
||||||
NearestOffersDocument,
|
NearestOffersDocument,
|
||||||
@@ -222,6 +249,7 @@ export function useCatalogInfo() {
|
|||||||
|
|
||||||
// Offers already include routes from backend
|
// Offers already include routes from backend
|
||||||
relatedOffers.value = offersData?.nearestOffers || []
|
relatedOffers.value = offersData?.nearestOffers || []
|
||||||
|
isLoadingOffers.value = false
|
||||||
|
|
||||||
// Extract unique suppliers from offers (use supplierUuid from offers)
|
// Extract unique suppliers from offers (use supplierUuid from offers)
|
||||||
const supplierUuids = new Set<string>()
|
const supplierUuids = new Set<string>()
|
||||||
@@ -249,6 +277,10 @@ export function useCatalogInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
relatedSuppliers.value = suppliers
|
relatedSuppliers.value = suppliers
|
||||||
|
} finally {
|
||||||
|
isLoadingOffers.value = false
|
||||||
|
isLoadingSuppliers.value = false
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading offers for hub:', error)
|
console.error('Error loading offers for hub:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,24 @@
|
|||||||
<div class="absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-primary/20 via-transparent to-transparent" />
|
<div class="absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-primary/20 via-transparent to-transparent" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- MainNavigation - same everywhere, just glass-style on home/catalog -->
|
<!-- Hero title (home page only, fades on scroll) -->
|
||||||
|
<div
|
||||||
|
v-if="isHomePage"
|
||||||
|
class="absolute left-0 right-0 text-center pointer-events-none z-20"
|
||||||
|
:style="heroTitleStyle"
|
||||||
|
>
|
||||||
|
<h1 class="text-4xl lg:text-5xl font-bold text-white mb-2">
|
||||||
|
{{ $t('hero.title', 'Оптовая торговля') }}
|
||||||
|
</h1>
|
||||||
|
<p class="text-lg text-white/70">
|
||||||
|
{{ $t('hero.subtitle', 'Найдите лучших поставщиков и товары') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MainNavigation - same everywhere, centered vertically on home page -->
|
||||||
<MainNavigation
|
<MainNavigation
|
||||||
class="relative z-10"
|
class="relative z-10"
|
||||||
|
:style="mainNavStyle"
|
||||||
:session-checked="sessionChecked"
|
:session-checked="sessionChecked"
|
||||||
:logged-in="isLoggedIn"
|
:logged-in="isLoggedIn"
|
||||||
:user-avatar-svg="userAvatarSvg"
|
:user-avatar-svg="userAvatarSvg"
|
||||||
@@ -175,6 +190,26 @@ const headerContainerStyle = computed(() => {
|
|||||||
return {}
|
return {}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// MainNavigation style - centered vertically on home page, normal on other pages
|
||||||
|
const mainNavStyle = computed(() => {
|
||||||
|
if (!isHomePage.value) return {}
|
||||||
|
// Center MainNav (100px) in container: margin-top = (height - 100) / 2
|
||||||
|
const marginTop = Math.max(0, (heroHeight.value - 100) / 2)
|
||||||
|
return { marginTop: `${marginTop}px` }
|
||||||
|
})
|
||||||
|
|
||||||
|
// Hero title style - positioned above MainNav, fades on scroll
|
||||||
|
const heroTitleStyle = computed(() => {
|
||||||
|
// Position title above the centered MainNav
|
||||||
|
const navMarginTop = Math.max(0, (heroHeight.value - 100) / 2)
|
||||||
|
const titleBottom = heroHeight.value - navMarginTop + 20 // 20px gap above nav
|
||||||
|
return {
|
||||||
|
bottom: `${titleBottom}px`,
|
||||||
|
opacity: 1 - collapseProgress.value,
|
||||||
|
transform: `translateY(${collapseProgress.value * -20}px)`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Main content padding-top to compensate for fixed header
|
// Main content padding-top to compensate for fixed header
|
||||||
const mainStyle = computed(() => {
|
const mainStyle = computed(() => {
|
||||||
if (isCatalogSection.value) return { paddingTop: '0' }
|
if (isCatalogSection.value) return { paddingTop: '0' }
|
||||||
|
|||||||
Reference in New Issue
Block a user