feat(nav): client area tabs in main navigation
Some checks failed
Build Docker Image / build (push) Has been cancelled
Some checks failed
Build Docker Image / build (push) Has been cancelled
- Add Cabinet button to header (dashboard icon) - When in /clientarea/* show tabs instead of search input - Tabs: Заказы | Предложения (SELLER only) | Адреса | Профиль | Команда - Hide Explore/Quote toggle in client area - Remove SubNavigation for clientarea (tabs moved to MainNavigation)
This commit is contained in:
@@ -12,8 +12,8 @@
|
|||||||
<span class="font-bold text-xl" :class="useWhiteText ? 'text-white' : 'text-base-content'">Optovia</span>
|
<span class="font-bold text-xl" :class="useWhiteText ? 'text-white' : 'text-base-content'">Optovia</span>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|
||||||
<!-- Service nav links -->
|
<!-- Service nav links (hide in client area) -->
|
||||||
<nav v-if="showModeToggle" class="flex items-center gap-1">
|
<nav v-if="showModeToggle && !isClientArea" class="flex items-center gap-1">
|
||||||
<button
|
<button
|
||||||
class="px-3 py-1 text-sm font-medium rounded-lg transition-colors"
|
class="px-3 py-1 text-sm font-medium rounded-lg transition-colors"
|
||||||
:class="showActiveMode && catalogMode === 'explore'
|
:class="showActiveMode && catalogMode === 'explore'
|
||||||
@@ -35,13 +35,55 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Center: Search input (vertically centered) -->
|
<!-- Center: Search input OR Client Area tabs (vertically centered) -->
|
||||||
<div class="flex-1 flex flex-col items-center max-w-2xl mx-auto gap-2 justify-center">
|
<div class="flex-1 flex flex-col items-center max-w-2xl mx-auto gap-2 justify-center">
|
||||||
<!-- Hero slot for home page title -->
|
<!-- Hero slot for home page title -->
|
||||||
<slot name="hero" />
|
<slot name="hero" />
|
||||||
|
|
||||||
|
<!-- Client Area tabs -->
|
||||||
|
<template v-if="isClientArea">
|
||||||
|
<div class="flex items-center gap-1 rounded-full border border-white/20 bg-white/80 backdrop-blur-md shadow-lg p-1">
|
||||||
|
<NuxtLink
|
||||||
|
:to="localePath('/clientarea/orders')"
|
||||||
|
class="px-4 py-2 rounded-full text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="isClientAreaTabActive('/clientarea/orders') ? 'bg-primary text-primary-content' : 'text-base-content/70 hover:text-base-content hover:bg-base-200/50'"
|
||||||
|
>
|
||||||
|
{{ $t('cabinetNav.orders') }}
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink
|
||||||
|
v-if="isSeller"
|
||||||
|
:to="localePath('/clientarea/offers')"
|
||||||
|
class="px-4 py-2 rounded-full text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="isClientAreaTabActive('/clientarea/offers') ? 'bg-primary text-primary-content' : 'text-base-content/70 hover:text-base-content hover:bg-base-200/50'"
|
||||||
|
>
|
||||||
|
{{ $t('cabinetNav.myOffers') }}
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink
|
||||||
|
:to="localePath('/clientarea/addresses')"
|
||||||
|
class="px-4 py-2 rounded-full text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="isClientAreaTabActive('/clientarea/addresses') ? 'bg-primary text-primary-content' : 'text-base-content/70 hover:text-base-content hover:bg-base-200/50'"
|
||||||
|
>
|
||||||
|
{{ $t('cabinetNav.addresses') }}
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink
|
||||||
|
:to="localePath('/clientarea/profile')"
|
||||||
|
class="px-4 py-2 rounded-full text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="isClientAreaTabActive('/clientarea/profile') ? 'bg-primary text-primary-content' : 'text-base-content/70 hover:text-base-content hover:bg-base-200/50'"
|
||||||
|
>
|
||||||
|
{{ $t('cabinetNav.profile') }}
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink
|
||||||
|
:to="localePath('/clientarea/team')"
|
||||||
|
class="px-4 py-2 rounded-full text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="isClientAreaTabActive('/clientarea/team') ? 'bg-primary text-primary-content' : 'text-base-content/70 hover:text-base-content hover:bg-base-200/50'"
|
||||||
|
>
|
||||||
|
{{ $t('cabinetNav.team') }}
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- Quote mode: Simple segmented input with search inside (white glass) -->
|
<!-- Quote mode: Simple segmented input with search inside (white glass) -->
|
||||||
<template v-if="catalogMode === 'quote'">
|
<template v-else-if="catalogMode === 'quote'">
|
||||||
<div class="flex items-center w-full rounded-full border border-white/40 bg-white/80 backdrop-blur-md shadow-lg divide-x divide-base-300/30">
|
<div class="flex items-center w-full rounded-full border border-white/40 bg-white/80 backdrop-blur-md shadow-lg divide-x divide-base-300/30">
|
||||||
<!-- Product segment -->
|
<!-- Product segment -->
|
||||||
<button
|
<button
|
||||||
@@ -135,8 +177,19 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right: AI + Globe + Team + User (top aligned like logo) -->
|
<!-- Right: Cabinet + AI + Globe + Team + User (top aligned like logo) -->
|
||||||
<div class="flex items-start gap-1 flex-shrink-0 pt-4">
|
<div class="flex items-start gap-1 flex-shrink-0 pt-4">
|
||||||
|
<!-- Cabinet button (when logged in and not in client area) -->
|
||||||
|
<NuxtLink
|
||||||
|
v-if="loggedIn && !isClientArea"
|
||||||
|
:to="localePath('/clientarea/orders')"
|
||||||
|
class="w-8 h-8 rounded-full flex items-center justify-center transition-colors"
|
||||||
|
:class="useWhiteText ? 'text-white/70 hover:text-white hover:bg-white/10' : 'text-base-content/70 hover:text-base-content hover:bg-base-200'"
|
||||||
|
:title="$t('cabinetNav.cabinet')"
|
||||||
|
>
|
||||||
|
<Icon name="lucide:layout-dashboard" size="18" />
|
||||||
|
</NuxtLink>
|
||||||
|
|
||||||
<!-- AI Assistant button -->
|
<!-- AI Assistant button -->
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
:to="localePath('/clientarea/ai')"
|
:to="localePath('/clientarea/ai')"
|
||||||
@@ -310,6 +363,8 @@ const props = withDefaults(defineProps<{
|
|||||||
isCollapsed?: boolean
|
isCollapsed?: boolean
|
||||||
// Home page flag for transparent background
|
// Home page flag for transparent background
|
||||||
isHomePage?: boolean
|
isHomePage?: boolean
|
||||||
|
// Client area flag - shows cabinet tabs instead of search
|
||||||
|
isClientArea?: boolean
|
||||||
// Dynamic height for hero effect
|
// Dynamic height for hero effect
|
||||||
height?: number
|
height?: number
|
||||||
}>(), {
|
}>(), {
|
||||||
@@ -334,10 +389,18 @@ defineEmits([
|
|||||||
])
|
])
|
||||||
|
|
||||||
const localePath = useLocalePath()
|
const localePath = useLocalePath()
|
||||||
|
const route = useRoute()
|
||||||
const { locale, locales } = useI18n()
|
const { locale, locales } = useI18n()
|
||||||
const switchLocalePath = useSwitchLocalePath()
|
const switchLocalePath = useSwitchLocalePath()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// Check if client area tab is active
|
||||||
|
const isClientAreaTabActive = (path: string) => {
|
||||||
|
const currentPath = route.path
|
||||||
|
const localizedPath = localePath(path)
|
||||||
|
return currentPath === localizedPath || currentPath.startsWith(localizedPath + '/')
|
||||||
|
}
|
||||||
|
|
||||||
const inputRef = ref<HTMLInputElement>()
|
const inputRef = ref<HTMLInputElement>()
|
||||||
const localSearchQuery = ref(props.searchQuery || '')
|
const localSearchQuery = ref(props.searchQuery || '')
|
||||||
const localQuantity = ref(props.quantity || '')
|
const localQuantity = ref(props.quantity || '')
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
:show-active-mode="isCatalogSection"
|
:show-active-mode="isCatalogSection"
|
||||||
:is-collapsed="isHomePage ? heroIsCollapsed : isCatalogSection"
|
:is-collapsed="isHomePage ? heroIsCollapsed : isCatalogSection"
|
||||||
:is-home-page="isHomePage"
|
:is-home-page="isHomePage"
|
||||||
|
:is-client-area="isClientArea"
|
||||||
@toggle-theme="toggleTheme"
|
@toggle-theme="toggleTheme"
|
||||||
@set-catalog-mode="setCatalogMode"
|
@set-catalog-mode="setCatalogMode"
|
||||||
@sign-out="onClickSignOut"
|
@sign-out="onClickSignOut"
|
||||||
@@ -54,9 +55,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</MainNavigation>
|
</MainNavigation>
|
||||||
|
|
||||||
<!-- Sub Navigation (section-specific tabs) - only for non-catalog/non-home sections -->
|
<!-- Sub Navigation (section-specific tabs) - only for non-catalog/non-home/non-clientarea sections -->
|
||||||
<SubNavigation
|
<SubNavigation
|
||||||
v-if="!isHomePage && !isCatalogSection"
|
v-if="!isHomePage && !isCatalogSection && !isClientArea"
|
||||||
:section="currentSection"
|
:section="currentSection"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,8 +175,13 @@ const isCatalogSection = computed(() => {
|
|||||||
route.path.startsWith('/ru/catalog')
|
route.path.startsWith('/ru/catalog')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Client area detection (cabinet tabs in MainNavigation, no SubNav needed)
|
||||||
|
const isClientArea = computed(() => {
|
||||||
|
return route.path.includes('/clientarea')
|
||||||
|
})
|
||||||
|
|
||||||
// Collapsible header logic - only for pages with SubNav
|
// Collapsible header logic - only for pages with SubNav
|
||||||
const hasSubNav = computed(() => !isHomePage.value && !isCatalogSection.value)
|
const hasSubNav = computed(() => !isHomePage.value && !isCatalogSection.value && !isClientArea.value)
|
||||||
const canCollapse = computed(() => hasSubNav.value)
|
const canCollapse = computed(() => hasSubNav.value)
|
||||||
const isHeaderCollapsed = computed(() => canCollapse.value && isCollapsed.value)
|
const isHeaderCollapsed = computed(() => canCollapse.value && isCollapsed.value)
|
||||||
|
|
||||||
@@ -193,6 +199,7 @@ const headerContainerStyle = computed(() => {
|
|||||||
const mainStyle = computed(() => {
|
const mainStyle = computed(() => {
|
||||||
if (isCatalogSection.value) return { paddingTop: '0' }
|
if (isCatalogSection.value) return { paddingTop: '0' }
|
||||||
if (isHomePage.value) return { paddingTop: `${heroBaseHeight.value}px` }
|
if (isHomePage.value) return { paddingTop: `${heroBaseHeight.value}px` }
|
||||||
|
if (isClientArea.value) return { paddingTop: '116px' } // Header only, no SubNav
|
||||||
return { paddingTop: '154px' }
|
return { paddingTop: '154px' }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"cabinetNav": {
|
"cabinetNav": {
|
||||||
|
"cabinet": "My Cabinet",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"catalog": "Catalog",
|
"catalog": "Catalog",
|
||||||
"orders": "My orders",
|
"orders": "My orders",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"cabinetNav": {
|
"cabinetNav": {
|
||||||
|
"cabinet": "Мой кабинет",
|
||||||
"search": "Поиск",
|
"search": "Поиск",
|
||||||
"catalog": "Каталог",
|
"catalog": "Каталог",
|
||||||
"orders": "Мои заказы",
|
"orders": "Мои заказы",
|
||||||
|
|||||||
Reference in New Issue
Block a user