Files
tehran_taj/apps/user-app/src/components/ui/Navigation.vue
T
s.esmaeili e756fbaf85 Redesign orders/cart/search flows and fix RTL/auth edge cases in user-app
- Fix silent redirect-to-home for unauthenticated users on protected routes;
  now redirects to login with a return path
- Restyle OrderCard, SearchInput, Filters, DropDown, and product card image
  sizing/centering to match the app's LESS-token design language
- Fix ant-design Slider handle placement/drag under RTL and seed a valid
  default range so handles actually render
- Fix chip-row edge padding and top spacing across Orders/Cart/Search lists
- Add pull-to-refresh to the dashboard and fix its header/padding to match
  the fixed PageBar pattern
- Remove the floating WhatsApp button from index.html
2026-09-16 01:15:16 +03:30

120 lines
3.1 KiB
Vue

<!--
Redesigned bottom nav — replaces the old GSAP SVG-notch bar (4 tabs: user,
cart, search, home) with a flat pill-bar of 5 tabs (Home, Search, Likes,
Notifications, Profile), each showing icon + label, and a single sliding
indicator behind the active tab instead of a cut-out notch.
windowData/SVG path math from the old version is gone — the indicator is
now pure CSS, positioned with a transform driven by the active tab's index,
so it needs no measurement of the container width.
-->
<template>
<nav class="tabbar" v-show="nav.showNav">
<div class="tabbar__inner" :style="{ '--count': nav.navBarRoutes.length }">
<div
class="tabbar__indicator"
:style="{ transform: `translateX(${indicatorOffset}%)` }"
aria-hidden="true"
/>
<router-link
v-for="item in nav.navBarRoutes"
:key="item.index"
:to="{ name: item.name }"
class="tabbar__item"
:class="{ 'is-active': nav.activeLink === item.index }"
>
<Icon :icon="item.icon" size="21" />
<span class="tabbar__label">{{ item.label }}</span>
</router-link>
</div>
</nav>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import Icon from '../icon/Icon.vue'
import { useNavStore } from '../../stores/navStore'
const nav = useNavStore()
// Index is 1-based; the indicator sits in tab slot (activeLink - 1) out of N.
// The whole app runs `direction: rtl` (see App.vue), which flips the grid's
// visual column order but NOT a physical translateX — so slot 0 renders on
// the right, and moving right needs a NEGATIVE offset here.
const indicatorOffset = computed(() => -(nav.activeLink - 1) * 100)
</script>
<style scoped lang="less">
.tabbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 10;
padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
background: transparent;
}
.tabbar__inner {
position: relative;
display: grid;
grid-template-columns: repeat(var(--count), 1fr);
max-width: 420px;
margin: 0 auto;
padding: 6px;
border-radius: 22px;
background: @canvas;
border: 1px solid @hairline;
box-shadow: 0 10px 28px -12px rgba(20, 22, 26, 0.18);
}
.tabbar__indicator {
position: absolute;
inset: 6px 6px 6px auto;
width: calc((100% - 12px) / var(--count));
border-radius: 16px;
background: @wineWash;
transition: transform 0.35s cubic-bezier(0.65, 0, 0.35, 1);
will-change: transform;
}
.tabbar__item {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
padding: 8px 4px;
border-radius: 16px;
color: @inkFaint;
text-decoration: none;
transition: color 0.25s ease, transform 0.25s cubic-bezier(0.65, 0, 0.35, 1.4);
}
.tabbar__item :deep(svg) {
transition: transform 0.3s cubic-bezier(0.65, 0, 0.35, 1.4);
}
.tabbar__item.is-active {
color: @wine;
transform: translateY(-2px);
}
.tabbar__item.is-active :deep(svg) {
transform: scale(1.08);
}
.tabbar__item:active {
transform: scale(0.94);
}
.tabbar__label {
font-size: 10px;
font-weight: 600;
line-height: 1;
opacity: 0.9;
}
</style>