This commit is contained in:
mohadese namavar
2024-06-16 00:22:14 +04:30
commit ec84dfd222
322 changed files with 77942 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
<template>
<section class="breadcrumbs">
<div>
<ul>
<li v-for="(item, i) in items" :key="i">
<router-link :to="item.link">
{{ item.name }}
</router-link>
</li>
</ul>
</div>
</section>
</template>
<script setup>
defineProps({ items: { type: Array, default: [] } });
</script>
<style lang="scss">
.breadcrumbs {
@apply w-full flex max-lg:px-6;
div {
@apply overflow-x-auto h-max;
&::-webkit-scrollbar{
@apply hidden;
}
ul {
@apply flex items-center gap-3.5 lg:gap-6 w-max;
li {
@apply relative text-[0.7em] lg:text-[1.1em];
a {
@apply text-[#999999] font-bold font-vazir;
}
&:not(:last-child)::after {
@apply content-['/'] absolute -left-2 lg:-left-3.5;
}
&:last-child a {
@apply text-[#666666];
}
}
}
}
}
</style>
File diff suppressed because it is too large Load Diff
+96
View File
@@ -0,0 +1,96 @@
<template>
<ul v-if="pages > 1" class="pagination">
<li v-for="i in [-1, 1]" :key="i">
<router-link
:to="{ query: { ...$route.query, page: page + i } }"
:class="{ 'pointer-events-none': page + i < 1 || page + i > pages }"
>
<Button :icon="getIcon(i)" link />
</router-link>
</li>
<li v-for="(item, i) in items" :key="i" :style="{ order: i + 2 }">
<router-link
:to="{ query: { ...$route.query, page: item } }"
:class="{ 'pointer-events-none': item == page }"
>
<Button :label="item" link :disabled="item == page" />
</router-link>
</li>
<li v-show="pages > 5" :style="{ order: pages / 2 > page ? 6 : 2 }">
<span>...</span>
</li>
</ul>
</template>
<script setup>
const props = defineProps(['pages'])
const route = useRoute()
const page = computed(() => +(route.query.page || 1))
const items = ref([])
const init = () => {
items.value = [page.value]
let temp = 1
while (items.value.length < 5) {
if (page.value - temp > 0) items.value.unshift(page.value - temp)
if (page.value + temp <= props.pages) items.value.push(page.value + temp)
temp++
if (temp > 10) break
}
if (props.pages > 5) {
if (props.pages / 2 > page.value) items.value.push(props.pages)
else items.value.unshift(1)
}
}
init()
watch(() => page.value, init)
const getIcon = (i) => 'isax isax-arrow-' + (i > 0 ? 'right-3' : 'left-2')
</script>
<style lang="scss">
.pagination {
box-shadow: 0px 2px 20px rgba(1, 86, 153, 0.08);
@apply bg-white rounded-lg gap-2 lg:gap-4 flex flex-row-reverse items-center justify-between px-2 lg:px-4;
@apply w-auto h-10 lg:h-[3.7rem];
li {
@apply h-full flex items-center;
button {
@apply w-5 h-5 lg:w-6 lg:h-6 p-0 rounded-sm #{!important};
.p-button-label {
@apply text-sm lg:text-base font-bold font-vazir lg:leading-tight text-[#8C8C8C] lg:mt-0.5;
}
.p-button-icon {
@apply text-[#8C8C8C] lg:mt-[0.2rem] text-xs;
}
&[disabled] {
@apply bg-[#379956] opacity-100;
.p-button-label {
@apply text-white;
}
}
// &:has(.p-button-icon){
// @apply max-lg:bg-[#F2F2F2];
// }
}
& > span {
@apply text-[#8C8C8C] font-medium font-vazir leading-[1.7rem] mt-0.5;
}
&:nth-child(2) {
@apply order-last;
}
}
}
</style>
+60
View File
@@ -0,0 +1,60 @@
<template>
<div class="about-us">
<div>
<img src="/images/logo.svg" alt="logo" />
<p>{{ $t("aboutUsDesc") }}</p>
</div>
<ul>
<li v-for="item in items" :key="item">
<i :class="`isax isax-${item.icon}`" />
<span>{{ $t(item.title) }}</span>
</li>
</ul>
</div>
</template>
<script setup>
const items = reactive([
{ icon: "call", title: "aboutUsPhone" },
{ icon: "sms", title: "aboutUsPostalCode" },
{ icon: "location", title: "aboutUsAddress" },
]);
</script>
<style lang="scss">
footer .about-us {
@apply flex flex-col gap-6 p-8 font-vazir;
@apply w-full h-auto bg-zinc-100 rounded-2xl border-2 border-neutral-200;
@apply sm:w-[32.7rem] sm:h-[31.3rem];
@apply lg:flex-row lg:w-[57.7rem] lg:h-auto;
@apply xl:flex-col xl:w-[32.7rem] xl:h-[31.3rem];
&>div {
@apply flex flex-col gap-6;
img {
@apply w-60 h-10;
}
p {
@apply w-auto sm:w-[28.1rem] text-zinc-800 text-lg leading-[1.9rem];
}
}
ul {
@apply flex flex-col gap-4 mt-4;
li {
@apply flex gap-3 h-max;
i {
@apply text-2xl h-[1.9rem];
}
span {
@apply text-zinc-800 text-base font-medium leading-[1.9rem];
}
}
}
}
</style>
@@ -0,0 +1,43 @@
<template>
<div class="customer-services">
<h2>{{ $t("customer-services") }}</h2>
<ul>
<li v-for="(service, i) in services" :key="i">
<a :href="service.url">
<span>{{ $t(service.title) }}</span>
</a>
</li>
</ul>
</div>
</template>
<script setup>
const services = reactive([
{ url: "/contact-us", title: "contactUs" },
{ url: "/about-us", title: "aboutUs" },
{ url: "/search", title: "shop" },
{ url: "/blog", title: "media" },
]);
</script>
<style lang="scss">
footer .customer-services {
@apply flex flex-col gap-4 w-max font-vazir items-center sm:items-start;
h2 {
@apply text-zinc-800 text-xl font-bold leading-[1.9rem];
}
ul {
@apply flex gap-4 sm:flex-col justify-between sm:gap-2;
li {
a {
span {
@apply text-stone-500 text-[0.9em] leading-[1.9rem] hover:text-primary-600;
}
}
}
}
}
</style>
+32
View File
@@ -0,0 +1,32 @@
<template>
<footer>
<AppDesktopFooterAboutUs />
<div>
<AppDesktopFooterNewsletters />
<AppDesktopFooterSocialNetworks />
<div>
<AppDesktopFooterCustomerServices />
<AppDesktopFooterPurchaseGuide />
<AppDesktopFooterTrustSymbols />
</div>
</div>
</footer>
</template>
<script setup></script>
<style lang="scss">
footer {
@apply w-full flex flex-col sm:items-center justify-center bg-[#F5F5F5];
@apply gap-4 px-3 py-12;
@apply xl:flex-row xl:gap-[6.7rem] 2xl:py-[6.3rem];
&>div:not([class]) {
@apply flex flex-col gap-6;
&>div:not([class]) {
@apply flex flex-col items-center sm:items-start sm:flex-row justify-center gap-8 mt-4 lg:justify-between xl:gap-6 xl:mt-10;
}
}
}
</style>
@@ -0,0 +1,81 @@
<template>
<div class="newsletters">
<h2>{{ $t("newslettersDesc") }}</h2>
<form>
<div>
<i class="isax isax-sms" />
<span>|</span>
<input v-model="email" :class="{ '!ltr': email }" :placeholder="$t('emailAddress')" />
</div>
<Button :label="$t('submit')" :loading="loading" @click="submit()" />
</form>
</div>
</template>
<script setup>
const { toast, t } = inject('service')
const loading = ref(false)
const email = ref()
const submit = async () => {
if (email.value.includes('@')) {
loading.value = true;
const { status, error } = await useFetch('/api/news', { method: 'post', body: { email: email.value } })
loading.value = false;
email.value = '';
if (status.value == 'success')
toast.add({
life: 3000,
severity: 'success',
summary: t('success'),
detail: t('submitedSuccessfully')
})
else
toast.add({
life: 3000,
severity: 'error',
summary: t('error'),
detail: error.value
})
}
}
</script>
<style lang="scss">
footer .newsletters {
@apply bg-zinc-100 rounded-xl border-2 border-neutral-200;
@apply flex flex-col items-center justify-between p-3 font-vazir;
@apply w-full h-auto gap-4 py-4;
@apply lg:w-[57.7rem] lg:h-[4.5rem] lg:flex-row;
h2 {
@apply text-zinc-800 text-lg font-medium leading-[1.9rem] mr-3;
}
form {
@apply flex gap-2;
div {
@apply w-[16.9rem] md:w-[21.5rem] h-12 bg-neutral-200 rounded-lg flex gap-3 items-center p-3;
i {
@apply text-2xl;
}
input {
@apply h-12 bg-transparent w-full rtl text-neutral-600 font-medium outline-none;
&:placeholder {
@apply text-neutral-600;
}
}
}
button {
@apply w-[4.5rem] h-12 bg-[#47B556] rounded-md text-white text-base font-medium #{!important};
}
}
}
</style>
@@ -0,0 +1,42 @@
<template>
<div class="purchase-guide">
<h2>{{ $t("purchaseGuideFromAM") }}</h2>
<ul>
<li v-for="(guide, i) in guides" :key="i">
<a :href="guide.url">
<span>{{ $t(guide.title) }}</span>
</a>
</li>
</ul>
</div>
</template>
<script setup>
const guides = reactive([
{ url: "/", title: "howToPlaceOrder" },
{ url: "/", title: "orderSendingProcedure" },
{ url: "/", title: "paymentMethods" },
]);
</script>
<style lang="scss">
footer .purchase-guide {
@apply flex flex-col gap-4 sm:gap-[1.4rem] w-max font-vazir items-center sm:items-start;
h2 {
@apply text-zinc-800 text-xl font-bold leading-[1.9rem];
}
ul {
@apply flex gap-4 sm:flex-col sm:gap-2;
li {
a {
span {
@apply text-stone-500 text-[0.9em] leading-[1.9rem] hover:text-primary-600;
}
}
}
}
}
</style>
@@ -0,0 +1,48 @@
<template>
<div class="social-networks">
<h2>{{ $t("followUs") }}</h2>
<ul>
<li v-for="({url, icon}, i) in socials" :key="i">
<a :href="url" target="_blank">
<img :src="`/icons/${icon}.svg`" />
</a>
</li>
</ul>
</div>
</template>
<script setup>
const socials = reactive([
{ url: "/", icon: "linkedin" },
{ url: "/", icon: "telegram" },
{ url: "/", icon: "whatsapp" },
{ url: "/", icon: "instagram" },
]);
</script>
<style lang="scss">
footer .social-networks {
@apply bg-zinc-100 rounded-xl border-2 border-neutral-200;
@apply flex flex-col items-center justify-between px-6;
@apply w-full h-auto gap-4 py-4;
@apply lg:w-[57.7rem] lg:h-[4.5rem] md:flex-row;
h2 {
@apply text-zinc-800 text-lg font-medium font-vazir leading-[1.9rem];
}
ul {
@apply flex gap-2;
li {
@apply w-max h-max;
a {
@apply w-10 h-10 bg-[#B2B2B2] hover:bg-[#43E97B] rounded-full flex items-center justify-center;
img {
@apply h-6 w-6 object-scale-down;
}
}
}
}
}
</style>
@@ -0,0 +1,37 @@
<template>
<div class="trust-symbols">
<h2>{{ $t('symbolOfTrust')}}</h2>
<div>
<picture v-for="(symbol, i) in symbols" :key="i">
<img :src="`/images/${symbol}.svg`" />
</picture>
</div>
</div>
</template>
<script setup>
const symbols = reactive(['samandehi', 'kasbokar'])
</script>
<style lang="scss">
footer .trust-symbols{
@apply flex flex-col items-center gap-4;
@apply sm:items-start;
h2{
@apply text-zinc-800 text-xl font-bold font-vazir leading-[1.9rem];
}
div{
@apply flex gap-4;
picture{
@apply flex w-24 h-32 bg-white rounded-lg border border-neutral-300;
img{
@apply m-auto;
}
}
}
}
</style>
+99
View File
@@ -0,0 +1,99 @@
<template>
<header class="header-desktop">
<router-link to="/">
<img src="/images/logo.svg" alt="Asan Market" />
</router-link>
<AppDesktopHeaderNavigation />
<router-link v-if="!logged" :to="{ path: '/auth/login' }">
<Button v-bind="btns.login.props" />
</router-link>
<div v-else>
<template v-for="({ props, component }, key) in btns.logged" :key="key">
<Button v-bind="props" @click="overlay($event, component)" />
</template>
</div>
</header>
</template>
<script setup>
import init from '../../../../initialize/header'
const { btns } = init()
const logged = useCookie('token')
const { popup } = inject('service')
const overlay = (event, is) => {
popup.value.is = is
popup.value.toggle(event)
}
</script>
<style lang="scss">
.header-desktop {
box-shadow: 0px 2px 20px rgba(0.22, 75.27, 129.62, 0.14);
@apply w-full h-[3.3rem] lg:h-24 bg-white shadow border-b pl-3 lg:px-3 2xl:p-6 flex items-center justify-between;
@apply sticky top-0 z-10 xl:gap-4;
&>a>img {
@apply w-60 h-10;
}
&>a {
@apply shrink-0;
&>button {
@apply flex items-center text-white;
.p-button-icon {
@apply text-2xl;
}
.p-button-label {
@apply font-bold font-iran-sans tracking-widest whitespace-nowrap;
}
}
}
&>div {
@apply flex items-center gap-6 2xl:gap-12 relative;
&::after {
@apply content-['_'] w-0.5 h-[1.3rem] bg-[#DCDCDC] absolute left-[3.6rem] 2xl:left-[4.4rem];
}
button {
@apply border-[#CCCCCC] h-12 rounded-[0.6rem] #{!important};
.p-button-label {
@apply text-[#333333] text-lg font-medium font-vazir whitespace-nowrap;
}
.p-button-icon {
@apply text-[#333333] text-2xl;
}
&:first-child {
@apply pl-6 #{!important};
.p-button-icon {
@apply ml-2.5;
}
}
&:last-child {
@apply w-12 p-2 relative;
.p-badge {
@apply absolute w-4 h-4 bg-[#B3261E] top-0.5 right-0.5 flex items-center justify-center;
@apply text-white text-[0.7em] font-medium leading-none tracking-wide;
}
}
}
.p-blockui-container {
@apply absolute;
}
}
}
</style>
+189
View File
@@ -0,0 +1,189 @@
<template>
<Transition>
<nav v-if="visible" class="mega-menu" @click.self="visible = false">
<TransitionGroup name="list" tag="section">
<template v-for="(list, i) in menu" :key="i">
<ul v-if="list?.length">
<li v-for="(item, j) in list" :key="j" @mouseover="open(item, i)">
<router-link :to="{ path: '/search', query: { category: item.link } }">
<Button v-bind="getProps(item, i)" />
</router-link>
</li>
</ul>
</template>
</TransitionGroup>
</nav>
</Transition>
</template>
<script setup>
const visible = defineModel()
const store = useCategoriesStore()
const menu = reactive([])
const getProps = (item, i) => {
const temp = { label: item.name, link: true }
if (i === 0) {
temp.iconPos = 'right'
temp.icon = 'isax ' + item.icon
// temp.disabled = menu[1] == item.sub
} else if (i === 1 && item.sub.length > 0) {
temp.icon = 'isax isax-arrow-left-2'
// temp.disabled = menu[2] == item.sub
}
return temp
}
const open = (item, i) => {
if (i < 2) {
delete menu[i + 2]
menu[i + 1] = item.sub
}
}
onMounted(() => {
let cat = store.items
while (true) {
menu.push(cat)
if (cat[0]?.sub) cat = cat[0].sub
else break
}
})
const route = useRoute()
watch(() => route.query, () => visible.value = false)
</script>
<style lang="scss">
.mega-menu {
@apply fixed inset-x-0 z-[1] bottom-0 top-24 bg-black/40;
&>section {
@apply flex h-[32.4rem] w-full bg-white shadow-inner;
ul:nth-of-type(1) {
@apply flex flex-col gap-2 py-3 px-4 w-[16.5rem] h-[26.8rem] z-[10];
li {
button {
@apply w-full h-12 justify-end;
.p-button-label {
@apply text-[#292D32] text-lg font-medium font-vazir grow-0;
}
.p-button-icon {
@apply text-[#292D32] text-2xl ml-4;
}
&:hover * {
@apply text-primary-600;
}
&:disabled {
@apply opacity-100;
* {
@apply text-primary-600;
}
}
}
}
}
ul:nth-of-type(2) {
@apply border-x-2 border-[#E5E5E5] w-[16.5rem] h-[32.4rem] flex flex-col;
li {
@apply border-b border-[#E5E5E5];
button {
@apply w-full h-[3.7rem] justify-between px-2.5;
.p-button-label {
@apply text-[#292D32] text-lg font-vazir grow-0 ml-auto;
}
.p-button-icon {
@apply text-[#292D32] text-sm transition-transform;
}
&:hover * {
@apply text-primary-600;
}
&:disabled {
@apply opacity-100 bg-[#FAFAFA];
.p-button-label {
@apply text-[#333333] font-medium;
}
.p-button-icon {
@apply text-[#333333] -rotate-90;
}
}
}
}
}
ul:nth-of-type(3) {
@apply flex flex-col;
li {
@apply px-4;
button {
@apply w-full h-[3.8rem] justify-end;
.p-button-label {
@apply text-[#333333] text-lg font-normal font-vazir grow-0;
}
&:hover * {
@apply text-primary-600;
}
}
}
}
}
.list-enter-active,
.list-leave-active {
transition: all 0.2s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.menu-enter-active,
.menu-leave-active {
transition: all 0.3s ease;
div {
transition: all 0.3s ease;
}
}
.menu-enter-from,
.menu-leave-to {
opacity: 0;
div {
transform: translateX(30px);
}
}
}
.v-enter-active,
.v-leave-active {
transition: opacity 0.1s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>
@@ -0,0 +1,70 @@
<template>
<ul class="mini-menu">
<li v-for="(item, i) in items" :key="i">
<router-link :to="item.to" @click="popup.hide()">
<Button v-bind="item.props" iconPos="right" severity="secondary" link />
</router-link>
</li>
<li>
<Button :label="$t('logout')" icon="isax isax-logout-1" iconPos="right" severity="secondary" link
@click="logout()" />
</li>
</ul>
</template>
<script setup>
const items = reactive([
{
to: "/panel/profile",
props: { label: "پروفایل کاربری", icon: "isax isax-user-square" },
},
{ to: "/panel/favorites", props: { label: "علاقه مندی ها", icon: "isax isax-heart" } },
{
to: "/panel/comments",
props: { label: "نظرات من", icon: "isax isax-message-text4" },
},
{ to: "/panel/factors", props: { label: "فاکتورها", icon: "isax isax-receipt-2-1" } },
{
to: "/panel/moeen",
props: { label: "فاکتور معین", icon: "isax isax-archive-book4" },
},
{ to: "/panel/notifications", props: { label: "اعلان ها", icon: "isax isax-notification" } },
{
to: "/panel/orders",
props: { label: "سفارشات", icon: "isax isax-shopping-cart" },
},
])
const { popup } = inject('service')
const { dialog } = inject('service')
const logout = () => {
popup.value.hide();
dialog.show(resolveComponent('PanelDialogLogout'))
}
</script>
<style lang="scss">
.mini-menu {
@apply flex flex-col gap-3 px-4 pt-[1.4rem] rtl shadow-[0px_2px_10px_#004b8229];
@apply w-[13.4rem] h-[27.8rem] bg-white rounded-2xl shadow border;
li {
button {
@apply h-10 py-1.5 justify-end #{!important};
.p-button-icon {
@apply text-[#333333] text-2xl ml-3;
}
.p-button-label {
@apply text-[#333333] text-lg font-medium font-vazir grow-0 whitespace-nowrap;
}
}
}
}
.p-overlaypanel:has(.mini-menu) {
@apply -translate-x-8;
}
</style>
@@ -0,0 +1,97 @@
<template>
<ul class="navigation">
<li>
<Button :label="$t('product-categories')" iconPos="right" severity="secondary" text icon="isax isax-menu-1"
@click="visible = !visible" />
</li>
<li v-for="(item, i) in items" :key="i">
<component :is="item.link.includes('http') ? 'a' : 'router-link'" :to="item.link" :href="item.link">
<Button iconPos="right" severity="secondary" text v-bind="item.props" />
</component>
</li>
<li>
<Button iconPos="right" severity="secondary" text icon="isax isax-search-normal-1"
@click="$router.push('/search')" />
</li>
</ul>
<AppDesktopHeaderMegaMenu v-model="visible" />
</template>
<script setup>
const items = ref([])
const visible = ref(false)
const { status, data, error } = await useFetch('/api/headers')
if (status.value == 'success')
items.value = data.value.map((item) => {
item.props = { label: item.title, icon: 'isax ' + item.icon }
return item
})
else throw createError(error.value)
</script>
<style lang="scss">
.navigation {
@apply flex items-center justify-center lg:gap-6 2xl:justify-between w-full max-w-[70.6rem];
li:first-child,
li:last-child {
@apply flex items-center relative;
}
li:first-child::after,
li:last-child::before {
@apply content-['_'] w-0.5 h-[1.3rem] bg-[#DCDCDC] absolute;
}
li:first-child {
@apply -ml-1;
&::after {
@apply left-0 2xl:-left-3;
}
}
li:last-child {
@apply -mr-1;
&::before {
@apply 2xl:-right-3;
}
}
li {
button {
.p-button-icon {
@apply text-[#333333] text-xl;
}
&:not(.p-button-icon-only) .p-button-icon {
@apply ml-2;
}
.p-button-label {
@apply text-[#333333] text-lg font-medium font-vazir whitespace-nowrap no-underline;
}
}
}
li:nth-child(n + 7):not(:last-child) {
@apply max-[1500px]:hidden;
}
li:nth-child(n + 6):not(:last-child) {
@apply max-[1380px]:hidden;
}
li:nth-child(n + 5):not(:last-child) {
@apply max-xl:hidden;
}
li:not(:last-child:first-child) {
@apply max-2xl:-mx-1;
}
}
</style>
@@ -0,0 +1,57 @@
<template>
<div class="header-cart-list-item">
<span>{{ quantity }}x</span>
<img :src="data.coverPath" />
<div>
<h3>{{ data.category[data.category.length - 1]?.name }}</h3>
<h2>{{ data.title }}</h2>
<span>
<b>{{ numberFormat(data.specialPrice || data.price) }} </b>
{{ $t('priceUnit') }}
</span>
</div>
<Button icon="isax isax-trash" severity="secondary" text @click="$emit('remove', data.id)" />
</div>
</template>
<script setup>
defineProps(['data', 'quantity'])
const numberFormat = (number) =>
new Intl.NumberFormat('fa-IR', { maximumSignificantDigits: 3 }).format(number)
</script>
<style lang="scss">
.header-cart-list-item {
box-shadow: 0px 2px 12px #004b8226;
@apply flex p-2 pl-6 w-[26.9rem] h-[10.1rem] bg-white rounded-lg shadow border relative;
&>span {
@apply absolute left-5 top-4 text-xs font-poppins;
}
img {
@apply w-[9.2rem] h-[9.2rem] p-2;
}
div {
@apply w-max gap-1 flex flex-col py-4 font-vazir mr-6;
h3 {
@apply text-right text-neutral-400 text-[0.9em] font-medium;
}
h2 {
@apply w-[13.1rem] h-14 text-right text-zinc-800 text-[1.1em] font-bold line-clamp-2;
}
span {
@apply text-zinc-800 text-[0.9em] mt-auto;
}
}
button {
@apply w-10 h-10 mb-2 -mx-2 shrink-0 self-end text-2xl text-[#7F7F7F] rounded-full #{!important};
}
}
</style>
@@ -0,0 +1,64 @@
<template>
<div class="header-cart-list">
<h3>{{ $t('itemsSubmittedInCart', { count: cart.count }) }}</h3>
<div>
<ul>
<li v-for="({ product, quantity }, i) in items" :key="i">
<AppDesktopHeaderCartItem :data="product" :quantity="quantity" @remove="remove" />
</li>
</ul>
</div>
<Button :label="$t('showCart')" @click="show()" />
</div>
</template>
<script setup>
const { popup } = inject('service')
const cart = useCartStore()
const items = computed(() => cart.items)
const emit = defineEmits(['hide'])
const router = useRouter()
const show = () => {
popup.value.hide()
router.push('/checkout/cart')
}
const remove = async (id) => {
await cart.update(id)
if (cart.count < 1) popup.value.hide()
}
</script>
<style lang="scss">
.header-cart-list {
box-shadow: 0px 2px 10px 0px rgba(0, 75, 130, 0.16);
@apply rtl w-[30.9rem] h-[40.6rem] flex flex-col gap-5 py-6 pl-2 bg-white rounded-2xl border overflow-hidden relative;
&>h3 {
@apply text-sky-700 text-[0.9em] font-medium font-vazir mb-2.5 mr-8 ml-6;
}
&>div {
@apply overflow-y-auto h-[29.8rem];
ul {
@apply w-full flex py-3 pr-8 pl-4 flex-col gap-3 items-center;
}
&::-webkit-scrollbar {
@apply hidden;
}
}
&>button {
@apply bg-sky-700 border-sky-700 mr-8 ml-6 text-xl font-bold font-vazir #{!important};
}
&::before {
content: ' ';
box-shadow: 0px -3px 16px 0px rgba(7, 50, 115, 0.16);
@apply absolute inset-x-0 -bottom-3 h-28 z-0;
}
}
</style>
+40
View File
@@ -0,0 +1,40 @@
<template>
<ul class="drawer-menu">
<li v-for="(item, i) in items" :key="i">
<router-link :to="item.link" @click="sidebar.visible = false">
<Button v-bind="item.props" iconPos="right" severity="secondary" text />
</router-link>
</li>
</ul>
</template>
<script setup>
const props = defineProps(['menu'])
const { sidebar } = inject('service')
const items = ref([])
items.value = props.menu.map((item) => {
item.props = { label: item.title, icon: 'isax ' + item.icon }
return item
})
</script>
<style lang="scss">
.drawer-menu {
@apply rtl w-60 flex flex-col gap-3 px-4 pt-[1.4rem];
li {
button {
@apply h-10 py-1.5 justify-end;
.p-button-icon {
@apply text-[#333333] text-2xl ml-3;
}
.p-button-label {
@apply text-[#333333] text-lg font-medium font-vazir grow-0 whitespace-nowrap;
}
}
}
}
</style>
+51
View File
@@ -0,0 +1,51 @@
<template>
<header class="header-mobile">
<div>
<Button v-if="h.back" v-bind="btns.back.props" @click="$router.go(-1)" />
<Button v-if="h.menu" v-bind="btns.menu.props" @click="sidebar.visible = true" />
<h2 v-if="h.title" v-text="h.title" />
<AppMobileSearchBox v-if="h.search" />
<span />
<template v-for="(opt, i) in h.options" :key="i">
<Button v-bind="opt.props" @click="opt.click" />
</template>
</div>
<AppMobileToolbar v-if="h.toolbar" />
</header>
</template>
<script setup>
const { btns, navigation } = inject('mobile')
const { sidebar } = inject('service')
const { mobile } = inject('config')
const h = computed(() => mobile.header)
</script>
<style lang="scss">
.header-mobile {
box-shadow: 0px 2px 20px #004b8224;
@apply w-full h-max bg-white shadow border-b pl-3 flex flex-col sticky top-0 z-10;
&>div {
@apply h-[3.3rem] flex items-center;
&>button {
@apply flex items-center text-[#292D32] shrink-0;
.p-button-icon {
@apply text-2xl;
}
}
&>h2{
@apply text-[#333333] text-sm font-medium font-vazir;
}
&>span {
@apply mr-auto;
}
}
}
</style>
+48
View File
@@ -0,0 +1,48 @@
<template>
<nav class="bottom-navigation">
<ul>
<li v-for="(item, i) in navigation" :key="i">
<router-link :to="item.to" v-ripple>
<Button v-bind="item.props" />
</router-link>
</li>
</ul>
</nav>
</template>
<script setup>
const { navigation } = inject('mobile');
const route = useRoute()
Object.keys(navigation).forEach(key => {
const item = navigation[key]
if (item.to == route.path)
item.props.icon += '5'
});
</script>
<style lang="scss">
.bottom-navigation {
@apply fixed inset-x-0 bottom-0 h-16 pb-2 bg-white z-10;
@apply shadow-[0px_-2px_5px_#0000000a] border-t border-[#F1F2F4];
ul {
@apply w-full h-full flex justify-between items-center;
li {
@apply flex justify-center flex-1;
a {
button span {
@apply text-[#7F7F7F] text-2xl;
}
&.router-link-active button span {
@apply text-primary-600;
}
}
}
}
}
</style>
+44
View File
@@ -0,0 +1,44 @@
<template>
<div class="search-box" @click="active = true">
<i class="isax isax-search-normal-1" />
<template v-if="active">
<InputText v-model="q" :placeholder="$t('searchIn')" autofocus @blur="active = false"
@keypress.enter="search" />
</template>
<template v-else>
<span>{{ $t("searchIn") }}</span>
<img src="/images/logo-search.svg" />
</template>
</div>
</template>
<script setup>
const route = useRoute()
const router = useRouter()
const active = ref(false);
const q = ref(route.query.q || '');
const search = () => router.push({ path: '/search', query: { q: q.value } })
</script>
<style lang="scss">
.search-box {
@apply grow flex gap-1.5 items-center h-10 bg-[#F2F2F2] rounded-[0.4rem] px-3;
input {
@apply h-full text-xs px-0 w-auto bg-transparent border-0 rtl focus:border-0 focus:shadow-none #{!important};
}
i {
@apply text-lg ml-1.5;
}
span {
@apply text-[#5D5D5D] text-xs font-vazir;
}
img {
@apply w-24 h-5;
}
}
</style>
+44
View File
@@ -0,0 +1,44 @@
<template>
<ul>
<li v-for="({ label, link }, i) in items" :key="i">
<router-link :to="link">
<span>{{ label }}</span>
</router-link>
</li>
</ul>
</template>
<script setup>
const items = reactive([
{ link: '/panel/seller/store', label: 'فروشگاه', icon: 'isax isax-shop' },
{ link: '/panel/seller/products', label: 'همه کالاها', icon: 'isax isax-bag' },
{ link: '/panel/seller/new-product', label: 'معرفی کالا', icon: 'isax isax-bag-cross' },
{ link: '/panel/seller/orders', label: 'سفارشات', icon: 'isax isax-bag-tick-2' },
])
</script>
<style lang="scss">
.header-mobile>ul {
@apply w-full h-8 flex gap-6 px-6;
li {
@apply translate-y-px;
a {
@apply h-full w-max text-[#333333] text-xs font-vazir;
&.router-link-active {
@apply text-[#47B556] font-bold;
}
}
&:has(.router-link-active) {
@apply border-b-2 border-[#47B556];
}
}
}
</style>