feat(nav): client area tabs in main navigation
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:
Ruslan Bakiev
2026-01-28 05:28:16 +07:00
parent 45acef9b20
commit 8b0e1900d1
4 changed files with 80 additions and 8 deletions

View File

@@ -12,8 +12,8 @@
<span class="font-bold text-xl" :class="useWhiteText ? 'text-white' : 'text-base-content'">Optovia</span>
</NuxtLink>
<!-- Service nav links -->
<nav v-if="showModeToggle" class="flex items-center gap-1">
<!-- Service nav links (hide in client area) -->
<nav v-if="showModeToggle && !isClientArea" class="flex items-center gap-1">
<button
class="px-3 py-1 text-sm font-medium rounded-lg transition-colors"
:class="showActiveMode && catalogMode === 'explore'
@@ -35,13 +35,55 @@
</nav>
</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">
<!-- Hero slot for home page title -->
<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) -->
<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">
<!-- Product segment -->
<button
@@ -135,8 +177,19 @@
</template>
</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">
<!-- 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 -->
<NuxtLink
:to="localePath('/clientarea/ai')"
@@ -310,6 +363,8 @@ const props = withDefaults(defineProps<{
isCollapsed?: boolean
// Home page flag for transparent background
isHomePage?: boolean
// Client area flag - shows cabinet tabs instead of search
isClientArea?: boolean
// Dynamic height for hero effect
height?: number
}>(), {
@@ -334,10 +389,18 @@ defineEmits([
])
const localePath = useLocalePath()
const route = useRoute()
const { locale, locales } = useI18n()
const switchLocalePath = useSwitchLocalePath()
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 localSearchQuery = ref(props.searchQuery || '')
const localQuantity = ref(props.quantity || '')

View File

@@ -30,6 +30,7 @@
:show-active-mode="isCatalogSection"
:is-collapsed="isHomePage ? heroIsCollapsed : isCatalogSection"
:is-home-page="isHomePage"
:is-client-area="isClientArea"
@toggle-theme="toggleTheme"
@set-catalog-mode="setCatalogMode"
@sign-out="onClickSignOut"
@@ -54,9 +55,9 @@
</template>
</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
v-if="!isHomePage && !isCatalogSection"
v-if="!isHomePage && !isCatalogSection && !isClientArea"
:section="currentSection"
/>
</div>
@@ -174,8 +175,13 @@ const isCatalogSection = computed(() => {
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
const hasSubNav = computed(() => !isHomePage.value && !isCatalogSection.value)
const hasSubNav = computed(() => !isHomePage.value && !isCatalogSection.value && !isClientArea.value)
const canCollapse = computed(() => hasSubNav.value)
const isHeaderCollapsed = computed(() => canCollapse.value && isCollapsed.value)
@@ -193,6 +199,7 @@ const headerContainerStyle = computed(() => {
const mainStyle = computed(() => {
if (isCatalogSection.value) return { paddingTop: '0' }
if (isHomePage.value) return { paddingTop: `${heroBaseHeight.value}px` }
if (isClientArea.value) return { paddingTop: '116px' } // Header only, no SubNav
return { paddingTop: '154px' }
})

View File

@@ -1,5 +1,6 @@
{
"cabinetNav": {
"cabinet": "My Cabinet",
"search": "Search",
"catalog": "Catalog",
"orders": "My orders",

View File

@@ -1,5 +1,6 @@
{
"cabinetNav": {
"cabinet": "Мой кабинет",
"search": "Поиск",
"catalog": "Каталог",
"orders": "Мои заказы",