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
+342
View File
@@ -0,0 +1,342 @@
<template>
<div class="products-filters-popup">
<div>
<Button :icon="getIcon()" severity="secondary" rounded link @click="back()" />
<h2>{{ $t(state) }}</h2>
<Button v-if="state == 'filters'" link :label="$t('removeFilters')" @click="remove()" />
</div>
<div>
<Transition>
<div v-if="state == 'filters'">
<Button :label="$t('categories')" icon="isax isax-arrow-left-2" severity="secondary" link
@click="state = 'categories'" />
<Accordion expand-icon="isax left" collapse-icon="isax up">
<AccordionTab :header="$t('brand')">
<ul>
<li v-for="(brand, i) in data.brands" :key="i">
<Checkbox v-model="brands" :value="brand.link" :input-id="i" />
<label :for="i"> {{ brand.title }} </label>
</li>
</ul>
</AccordionTab>
</Accordion>
<div>
<label>{{ $t("availableInStock") }}</label>
<InputSwitch v-model="stock" />
</div>
<Accordion expand-icon="isax left" collapse-icon="isax up">
<AccordionTab :header="$t('priceRange')">
<ul>
<li>
<span>{{ $t('from') }}</span>
<InputNumber v-model="prices[0]" :sync="true" />
<span>{{ $t('priceUnit') }}</span>
</li>
<li>
<span>{{ $t('until') }}</span>
<InputNumber v-model="prices[1]" :sync="true" />
<span>{{ $t('priceUnit') }}</span>
</li>
<li>
<Slider v-model="prices" :min="1000" :max="200000000" :step="1000" range />
</li>
</ul>
</AccordionTab>
</Accordion>
</div>
<PanelMenu v-else :model="categories" v-model:expandedKeys="expandedKeys">
<template #submenuicon="{ active }">
<i :class="'isax isax-arrow-' + (active ? 'up-2' : 'left-2')" />
</template>
</PanelMenu>
</Transition>
</div>
<div>
<Button :label="loading ? $t('loading') : $t('viewProductCount', { count: data?.products.length })"
icon="isax isax-arrow-up-2" severity="secondary" link @click="dialog.close()" :loading="loading" />
</div>
</div>
</template>
<script setup>
const route = useRoute()
const data = computed(() => route.meta.data || {})
const loading = computed(() => !route.meta.hasOwnProperty('data'))
const router = useRouter()
const dialog = inject('dialogRef')
const state = ref("filters");
const expandedKeys = ref({ });
const stock = ref('stock' in route.query)
const brands = ref([...(route.query?.brands?.split(',') ?? [])])
const prices = ref([...(route.query?.prices?.split(',').map(i => parseInt(i)) ?? [1000, 200000000])])
watch(brands, (v) => {
const query = Object.assign({}, route.query)
if (v?.length > 0)
query.brands = v.join(',')
else
delete query.brands
router.push({ query })
})
watch(stock, (v) => {
const query = Object.assign({}, route.query)
if (v)
query.stock = true
else
delete query.stock
router.push({ query })
})
let timer
watch(prices, (v) => {
clearTimeout(timer)
timer = setTimeout(() => {
const query = Object.assign({}, route.query)
const [$gte, $lte] = v
query.prices = ''
if ($gte > 1000 || $lte < 200000000)
query.prices = v.join(',')
else
delete query.prices
router.push({ query })
}, 500)
}, { deep: true })
const catMap = (items) => {
if (!items) return []
const list = []
try {
items.forEach((cat) => {
const temp = {
key: cat._id,
label: cat.name,
class: route.query.category == cat.link ? 'active' : '',
command: ({ originalEvent }) => {
if (cat.link && originalEvent.target.nodeName == 'SPAN') {
router.push({ query: { category: cat.link } })
back()
}
}
}
if (cat.sub.length > 0) temp.items = catMap(cat.sub)
list.push(temp)
})
} catch (error) {
}
return list
}
const categories = ref(catMap(data.value?.categories))
const back = () => {
if (state.value == "filters") dialog.value.close();
else state.value = "filters";
}
const remove = () => {
router.push('/search')
dialog.value.close()
}
const getIcon = () => 'isax isax-' + (state.value == 'filters' ? 'close-circle' : 'arrow-right-1')
</script>
<style lang="scss">
.products-filters-popup {
@apply w-full flex flex-col bg-white rounded-t-[0.6rem];
&>div:nth-of-type(1) {
@apply flex items-center gap-3 p-6;
h2 {
@apply text-black text-sm font-medium font-vazir;
}
&>button {
@apply -mx-4 -my-3 last:mr-auto last:text-primary-600;
&:first-child {
@apply text-xl text-black #{!important};
}
}
}
&>div:nth-of-type(2) {
&>div:not(.p-panelmenu) {
@apply flex flex-col px-6;
&>button {
@apply grow -mx-4 py-[1.1rem];
.p-button-label {
@apply text-right text-zinc-800 text-sm font-bold font-vazir;
}
.p-button-icon {
@apply text-lg text-zinc-800;
}
}
&>div.p-accordion {
@apply py-[1.1rem] first-of-type:border-y-2 border-[#EBEBEB] font-vazir;
.isax {
@apply text-lg;
}
.p-accordion-header-text {
@apply text-zinc-800 text-sm font-bold font-vazir #{!important};
}
&:nth-of-type(1) .p-accordion-content {
@apply pt-8 pb-4 rtl;
ul {
@apply flex flex-col gap-4;
li {
@apply flex items-center gap-3;
.p-checkbox {
@apply w-5 h-5 p-0.5 rounded border border-neutral-400;
.p-checkbox-box {
@apply w-full h-full border-none;
svg {
@apply hidden;
}
}
}
label {
@apply text-[#666666] text-sm font-bold cursor-pointer select-none;
}
}
}
}
&:nth-of-type(3) .p-accordion-content {
@apply pt-8 pb-4 rtl;
ul {
@apply flex flex-col gap-10 w-full;
li {
@apply flex justify-between items-end gap-[1.9rem] w-full;
&>span {
@apply text-[#666666] text-sm font-bold font-vazir grow;
}
input {
box-shadow: none;
@apply text-center w-[15rem] h-6 border-x-0 border-t-0 rounded-none #{!important};
@apply border-b-2 border-[#EBEBEB] text-[#333333] text-[1.4em] font-vazir;
&:focus {
@apply border-primary-600;
}
}
div {
@apply w-full mt-4;
.p-slider-handle {
@apply w-4 h-4 border-none bg-primary-600 -mt-2 focus:shadow-none;
}
}
}
}
}
}
&>div:not([class]) {
@apply flex items-center justify-between py-[1.1rem] border-b-2 border-[#EBEBEB];
label {
@apply text-[#333333] text-sm font-bold font-vazir;
}
.p-inputswitch {
@apply w-[2.1rem] h-[1.1rem] bg-white;
.p-inputswitch-slider::before {
@apply w-[0.7rem] h-[0.7rem] -mt-[0.3rem];
}
&.p-highlight .p-inputswitch-slider::before {
@apply translate-x-4;
}
}
}
}
.p-panelmenu {
@apply font-vazir text-sm font-bold flex flex-col gap-4 px-6 pb-4 rtl;
.p-panelmenu-header {
@apply flex;
.p-panelmenu-header-action{
@apply h-4 flex gap-1;
}
&:not(:has(i)){
@apply pr-4;
}
}
.p-toggleable-content {
@apply w-full h-full overflow-y-auto pr-4 pt-2 self-end rtl;
}
.p-menuitem-link {
@apply h-8 flex gap-1 #{!important};
&:not(:has(i)){
@apply pr-4;
}
}
.p-submenu-list{
@apply pl-0;
}
.active>.p-panelmenu-header .p-menuitem-text ,
.active>.p-menuitem-content .p-menuitem-text ,
{
@apply text-primary-600 #{!important};
}
}
}
&>div:nth-of-type(3) {
@apply w-full mt-auto shadow-[0_-2px_5px_#0000000a];
button {
@apply w-full px-6 rounded-none;
.p-button-label {
@apply text-right text-stone-500 text-sm font-bold font-vazir rtl;
}
.p-button-icon {
@apply text-lg text-zinc-800;
}
}
}
}
</style>
+60
View File
@@ -0,0 +1,60 @@
<template>
<div class="products-sort-popup">
<div>
<Button v-bind="btns.close.props" @click="dialog.close()" />
<h2>{{ $t("sortBy") }}</h2>
</div>
<ul>
<li v-for="(item, i) in sorts" :key="i">
<h3 @click="select(item)" v-ripple>
{{ $t(item) }}
</h3>
<i v-if="sort == item" class="isax isax-tick-circle" />
</li>
</ul>
</div>
</template>
<script setup>
const { meta } = useRoute()
const { btns, sorts } = meta.init
const dialog = inject('dialogRef')
const { query } = useRoute()
const sort = ref(query.sort || "mostVisited");
const router = useRouter()
const select = (key) => {
router.push({ path: '/search', query: {...query, sort: key} })
dialog.value.close()
}
</script>
<style lang="scss">
.products-sort-popup {
@apply w-full h-max flex flex-col gap-9 p-6 bg-white rounded-t-[0.6rem];
&>div {
@apply flex items-center gap-3;
&>button {
@apply -mx-4 -my-3 text-[#333333] text-[1.4em] #{!important};
}
&>h2 {
@apply text-[#333333] text-sm font-medium font-vazir;
}
}
&>ul {
@apply w-full flex flex-col gap-4;
&>li {
@apply flex items-center justify-between pb-4 border-b last:border-b-0 text-[#333333];
h3 {
@apply text-xs font-medium font-vazir overflow-hidden relative;
}
}
}
}
</style>