Files
nademitex_user/src/components/layout/BottomNav.vue
T

171 lines
3.8 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useCartStore } from '@/stores/cart'
import { MAIN_NAV_ITEMS, isNavItemActive } from '@/utils/navigation'
const route = useRoute()
const router = useRouter()
const cartStore = useCartStore()
const cartCount = computed(() => cartStore.itemCount)
function navigate(path: string, event: Event) {
const target = event.currentTarget
if (target instanceof HTMLElement) target.blur()
// «ثبت سفارش»: سبد خالی → انتخاب شرکت؛ در غیر این صورت سبد خرید
if (path === '/cart' && cartStore.itemCount === 0) {
router.push('/companies')
return
}
router.push(path)
}
</script>
<template>
<nav class="bottom-nav" aria-label="ناوبری اصلی">
<button
v-for="item in MAIN_NAV_ITEMS"
:key="item.name"
type="button"
class="nav-item"
:class="{
active: isNavItemActive(item.name, item.path, route.path),
'nav-item--fab': item.name === 'order-fab',
}"
:aria-current="isNavItemActive(item.name, item.path, route.path) ? 'page' : undefined"
:aria-label="item.label"
@click="navigate(item.path, $event)"
>
<span class="nav-icon" :class="{ 'nav-icon--fab': item.name === 'order-fab' }">
<component
:is="item.icon"
:size="item.name === 'order-fab' ? 26 : 22"
:stroke-width="item.name === 'order-fab' ? 1.8 : 1.5"
:color="item.name === 'order-fab' ? '#ffffff' : undefined"
/>
<span
v-if="item.name === 'order-fab' && cartCount > 0"
class="nav-badge"
>{{ cartCount }}</span>
</span>
<span v-if="item.name !== 'order-fab'" class="nav-label">{{ item.label }}</span>
<span v-else class="nav-label nav-label--fab">{{ item.label }}</span>
</button>
</nav>
</template>
<style scoped>
.bottom-nav {
flex-shrink: 0;
min-height: var(--nav-height);
background: var(--color-surface);
border-top: 1px solid var(--color-border);
display: flex;
justify-content: space-around;
align-items: flex-end;
z-index: 100;
padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0));
}
@media (min-width: 768px) {
.bottom-nav {
display: none;
}
}
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
gap: 4px;
margin: 0;
padding: 4px 2px 2px;
border: none;
border-radius: 10px;
background: transparent;
cursor: pointer;
color: var(--color-text-muted);
position: relative;
min-width: 0;
transition: color 0.15s;
}
.nav-item:focus,
.nav-item:focus-visible {
outline: none;
}
.nav-item.active {
color: var(--color-primary);
background: transparent;
}
.nav-item.active .nav-label {
font-weight: 700;
}
.nav-item--fab {
justify-content: flex-end;
color: var(--color-text-muted);
}
.nav-item--fab.active {
color: var(--color-primary);
}
.nav-icon {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
flex-shrink: 0;
overflow: visible;
}
.nav-icon--fab {
width: 52px;
height: 52px;
margin-top: -28px;
border-radius: 999px;
background: var(--color-primary);
color: #fff;
box-shadow: 0 6px 16px rgba(var(--color-primary-rgb), 0.35);
}
.nav-label {
font-size: 0.6875rem;
font-weight: 500;
line-height: 1.2;
white-space: nowrap;
}
.nav-label--fab {
font-size: 0.625rem;
}
.nav-badge {
position: absolute;
top: -2px;
inset-inline-end: -2px;
background: var(--color-danger);
color: #fff;
font-size: 0.625rem;
font-weight: 700;
min-width: 16px;
height: 16px;
border-radius: 999px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 4px;
line-height: 1;
pointer-events: none;
}
</style>