@meeovi/layer-commerce 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/catalog/product/ProductAccordion/types.ts +3 -3
- package/app/components/catalog/product/ProductProperties/types.ts +3 -3
- package/app/components/catalog/product/ProductSlider/types.ts +5 -5
- package/app/components/catalog/product/RecommendedProducts/types.ts +3 -3
- package/app/components/catalog/product/bestsellers.vue +8 -20
- package/app/components/catalog/product/deals.vue +7 -22
- package/app/components/catalog/product/exclusives.vue +8 -10
- package/app/components/catalog/product/featuredproducts.vue +8 -20
- package/app/components/catalog/product/latestproducts.vue +8 -20
- package/app/components/catalog/product/productCard.vue +55 -21
- package/app/components/catalog/product/productDetails.vue +20 -14
- package/app/components/catalog/product/relatedproducts.vue +5 -20
- package/app/components/catalog/product/sizeOptions.vue +3 -8
- package/app/components/catalog/shops/relatedstores.vue +6 -21
- package/app/components/categories/chart/[id].vue +200 -0
- package/app/components/categories/chart/add-chart.vue +142 -0
- package/app/components/categories/chart/chart.vue +82 -0
- package/app/components/categories/chart/monthlyChart.vue +46 -0
- package/app/components/categories/chart/weeklyChart.vue +46 -0
- package/app/components/categories/chart/yearlyChart.vue +46 -0
- package/app/components/categories/charts.vue +118 -0
- package/app/components/categories/deals.vue +101 -0
- package/app/components/categories/eats.vue +49 -0
- package/app/components/categories/restaurants.vue +26 -0
- package/app/components/categories/station/[id].vue +72 -0
- package/app/components/categories/stations.vue +124 -0
- package/app/components/categories/time/time.vue +63 -0
- package/app/components/categories/travel.vue +75 -0
- package/app/components/categories/weather/weather.vue +44 -0
- package/app/components/content/pages/showcases.vue +1 -1
- package/app/components/marketing/promotions/giftcards.vue +20 -45
- package/app/components/marketing/promotions/subscriptions.vue +8 -21
- package/app/components/placeholders/Comments.vue +15 -0
- package/app/components/placeholders/CreateListBtn.vue +7 -0
- package/app/components/placeholders/Event.vue +9 -0
- package/app/components/placeholders/ListShowcases.vue +9 -0
- package/app/components/placeholders/Short.vue +9 -0
- package/app/components/placeholders/Space.vue +9 -0
- package/app/components/placeholders/Tag.vue +7 -0
- package/app/components/sales/CheckoutAddress/types.ts +12 -11
- package/app/components/sales/OrderSummary/types.ts +3 -3
- package/app/components/sales/incentives.vue +13 -37
- package/app/composables/cart/registry.ts +7 -0
- package/app/composables/index.ts +1 -0
- package/app/composables/products/registry.ts +7 -0
- package/app/composables/registry.ts +21 -0
- package/app/composables/useCatalog.ts +64 -0
- package/app/composables/useContent.ts +57 -0
- package/app/composables/useProducts/types.ts +15 -10
- package/app/pages/brand/[...slug].vue +1 -1
- package/app/pages/departments/[...slug].vue +385 -0
- package/app/pages/departments/category/[...slug].vue +135 -0
- package/app/pages/product/[...id].vue +3 -3
- package/app/pages/shop/[...slug].vue +12 -18
- package/app/pages/shops.vue +18 -25
- package/global.d.ts +14 -0
- package/package.json +4 -2
- package/tsconfig.json +10 -1
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div v-if="department?.name === 'Deals'">
|
|
4
|
+
<v-toolbar :style="`background-color: ${department?.color}; color: ${department?.colortext}`"
|
|
5
|
+
:title="department?.name"></v-toolbar>
|
|
6
|
+
<deals :category="department?.id" />
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div v-else>
|
|
10
|
+
<v-card variant="text">
|
|
11
|
+
<v-toolbar :style="`background-color: ${department?.color}; color: ${department?.colortext}`"
|
|
12
|
+
:title="department?.name">
|
|
13
|
+
<v-slide-group show-arrows v-if="department?.categories?.length">
|
|
14
|
+
<v-slide-group-item v-slot="{ isSelected, toggle }">
|
|
15
|
+
<v-menu>
|
|
16
|
+
<template v-slot:activator="{ props }">
|
|
17
|
+
<v-btn :color="isSelected ? 'primary' : undefined" class="ma-2" @click="toggle"
|
|
18
|
+
v-bind="props" append-icon="fas:fa fa-caret-down" variant="text">
|
|
19
|
+
Categories
|
|
20
|
+
</v-btn>
|
|
21
|
+
</template>
|
|
22
|
+
<v-list class="departmentMenu">
|
|
23
|
+
<v-row>
|
|
24
|
+
<v-col cols="3" v-for="categories in department?.categories"
|
|
25
|
+
:key="categories?.id">
|
|
26
|
+
<v-list-item>
|
|
27
|
+
<v-chip><NuxtLink
|
|
28
|
+
:to="`/departments/category/${categories?.categories_id?.slug}`">
|
|
29
|
+
{{ categories?.categories_id?.name }}</NuxtLink></v-chip>
|
|
30
|
+
</v-list-item>
|
|
31
|
+
</v-col>
|
|
32
|
+
</v-row>
|
|
33
|
+
</v-list>
|
|
34
|
+
</v-menu>
|
|
35
|
+
</v-slide-group-item>
|
|
36
|
+
|
|
37
|
+
<v-slide-group-item v-if="department?.menus?.length" v-for="menu in department?.menus"
|
|
38
|
+
:key="menu" v-slot="{ isSelected, toggle }">
|
|
39
|
+
<v-btn :color="isSelected ? 'primary' : undefined" class="ma-2" @click="toggle"
|
|
40
|
+
:href="`${menu?.url}`">
|
|
41
|
+
{{ menu?.name }}
|
|
42
|
+
</v-btn>
|
|
43
|
+
</v-slide-group-item>
|
|
44
|
+
</v-slide-group>
|
|
45
|
+
</v-toolbar>
|
|
46
|
+
|
|
47
|
+
<!--Department Top Banner Section-->
|
|
48
|
+
<section data-bs-version="5.1" class="pricing6 shopm5 cid-tZY31Y2JxZ" id="apricing6-6g">
|
|
49
|
+
|
|
50
|
+
<div class="mbr-overlay"></div>
|
|
51
|
+
<div class="container-fluid">
|
|
52
|
+
<div class="row align-items-stretch items-row justify-content-center">
|
|
53
|
+
|
|
54
|
+
<div class="col-lg-6">
|
|
55
|
+
<div v-if="department?.name === 'Travel'">
|
|
56
|
+
<travel :category="department?.name" />
|
|
57
|
+
</div>
|
|
58
|
+
<!--<div v-else-if="department?.name === 'Appstore'">
|
|
59
|
+
<appstore :category="department?.name" />
|
|
60
|
+
</div>-->
|
|
61
|
+
<div v-else-if="department?.name === 'Weather'">
|
|
62
|
+
<weather :category="department?.name" />
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div v-else-if="department?.name === 'Time'">
|
|
66
|
+
<timeComponent :category="department?.name" />
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div v-else class="mbr-section-head" :style="`background-color: ${department?.color}`">
|
|
70
|
+
<h4 class="mbr-section-title mbr-fonts-style mb-0 display-7"
|
|
71
|
+
:style="`color: ${department?.colortext}`">
|
|
72
|
+
<strong>Meeovi</strong>
|
|
73
|
+
</h4>
|
|
74
|
+
<h5 class="mbr-section-subtitle mbr-fonts-style mb-0 display-2"
|
|
75
|
+
:style="`color: ${department?.colortext}`">
|
|
76
|
+
<strong>{{ department?.name }}</strong>
|
|
77
|
+
</h5>
|
|
78
|
+
<h5 class="main-text mbr-fonts-style mb-0 display-7"
|
|
79
|
+
:style="`color: ${department?.colortext}`">
|
|
80
|
+
{{ department?.description }}
|
|
81
|
+
</h5>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<v-sheet
|
|
86
|
+
class="mx-auto col-lg-6" style="background-color: transparent; box-shadow: none;">
|
|
87
|
+
<h4 style="left: 15px; position: relative;">{{ callouts?.menus?.[1]?.name }}</h4>
|
|
88
|
+
<v-slide-group v-model="model" class="pa-4" selected-class="bg-success" show-arrows>
|
|
89
|
+
<v-slide-group-item v-slot="{ isSelected, toggle, selectedClass }"
|
|
90
|
+
v-for="products in department?.products" :key="products">
|
|
91
|
+
<productCard :product="products?.products_id" :class="['ma-4', selectedClass]"
|
|
92
|
+
@click="toggle" />
|
|
93
|
+
<div class="d-flex fill-height align-center justify-center">
|
|
94
|
+
<v-scale-transition>
|
|
95
|
+
<v-icon v-if="isSelected" color="white" icon="mdi-close-circle-outline"
|
|
96
|
+
size="48"></v-icon>
|
|
97
|
+
</v-scale-transition>
|
|
98
|
+
</div>
|
|
99
|
+
</v-slide-group-item>
|
|
100
|
+
</v-slide-group>
|
|
101
|
+
</v-sheet>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</section>
|
|
105
|
+
|
|
106
|
+
<!--Department Content Section-->
|
|
107
|
+
<section data-bs-version="5.1" class="gallery2 shopm5 cid-uW1BojE78S" id="agallery2-0" v-if="department?.shorts?.length && department?.products?.products_id?.type === 'department'"
|
|
108
|
+
:style="`background-image: url(${$directus?.url}assets/${department?.image?.filename_disk})`">
|
|
109
|
+
<div class="mbr-overlay" style="opacity: 0.8; background-color: rgb(255, 255, 255);">
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div class="container-fluid">
|
|
113
|
+
<div class="row">
|
|
114
|
+
<!--Vibez Slider-->
|
|
115
|
+
<v-sheet
|
|
116
|
+
class="mx-auto sliderProducts row align-items-stretch items-row justify-content-center">
|
|
117
|
+
<v-slide-group v-model="model" class="pa-4" selected-class="bg-success" show-arrows>
|
|
118
|
+
<v-slide-group-item v-slot="{ isSelected, toggle, selectedClass }"
|
|
119
|
+
v-for="shorts in department?.shorts" :key="shorts">
|
|
120
|
+
<shorts :short="shorts?.shorts_id" :class="['ma-4', selectedClass]"
|
|
121
|
+
@click="toggle" />
|
|
122
|
+
<div class="d-flex fill-height align-center justify-center">
|
|
123
|
+
<v-scale-transition>
|
|
124
|
+
<v-icon v-if="isSelected" color="white" icon="mdi-close-circle-outline"
|
|
125
|
+
size="48"></v-icon>
|
|
126
|
+
</v-scale-transition>
|
|
127
|
+
</div>
|
|
128
|
+
</v-slide-group-item>
|
|
129
|
+
</v-slide-group>
|
|
130
|
+
</v-sheet>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</section>
|
|
134
|
+
|
|
135
|
+
<v-row class="departmentRow">
|
|
136
|
+
<!--Best Seller Product Slider-->
|
|
137
|
+
<v-sheet class="mx-auto sliderProducts row align-items-stretch items-row justify-content-center">
|
|
138
|
+
<h4 style="left: 15px; position: relative;">{{ callouts?.menus?.[1]?.name }}</h4>
|
|
139
|
+
<v-slide-group v-model="model" class="pa-4" selected-class="bg-success" show-arrows>
|
|
140
|
+
<v-slide-group-item v-slot="{ isSelected, toggle, selectedClass }"
|
|
141
|
+
v-for="products in best?.products" :key="products">
|
|
142
|
+
<productCard :product="products?.products_id" :class="['ma-4', selectedClass]"
|
|
143
|
+
@click="toggle" />
|
|
144
|
+
<div class="d-flex fill-height align-center justify-center">
|
|
145
|
+
<v-scale-transition>
|
|
146
|
+
<v-icon v-if="isSelected" color="white" icon="mdi-close-circle-outline"
|
|
147
|
+
size="48"></v-icon>
|
|
148
|
+
</v-scale-transition>
|
|
149
|
+
</div>
|
|
150
|
+
</v-slide-group-item>
|
|
151
|
+
</v-slide-group>
|
|
152
|
+
</v-sheet>
|
|
153
|
+
|
|
154
|
+
<!--List of latest products in the department-->
|
|
155
|
+
<v-sheet class="mx-auto sliderProducts row align-items-stretch items-row justify-content-center">
|
|
156
|
+
<h4 style="left: 15px; position: relative;">{{ callouts?.menus?.[2]?.name }}</h4>
|
|
157
|
+
<v-slide-group v-model="model" class="pa-4" selected-class="bg-success" show-arrows>
|
|
158
|
+
<v-slide-group-item v-slot="{ isSelected, toggle, selectedClass }"
|
|
159
|
+
v-for="products in latestProducts?.products" :key="products">
|
|
160
|
+
<productCard :product="products?.products_id" :class="['ma-4', selectedClass]"
|
|
161
|
+
@click="toggle" />
|
|
162
|
+
<div class="d-flex fill-height align-center justify-center">
|
|
163
|
+
<v-scale-transition>
|
|
164
|
+
<v-icon v-if="isSelected" color="white" icon="mdi-close-circle-outline"
|
|
165
|
+
size="48"></v-icon>
|
|
166
|
+
</v-scale-transition>
|
|
167
|
+
</div>
|
|
168
|
+
</v-slide-group-item>
|
|
169
|
+
</v-slide-group>
|
|
170
|
+
</v-sheet>
|
|
171
|
+
|
|
172
|
+
<!--List of products in the department-->
|
|
173
|
+
<v-sheet class="mx-auto sliderProducts row align-items-stretch items-row justify-content-center">
|
|
174
|
+
<v-slide-group v-model="model" class="pa-4" selected-class="bg-success" show-arrows>
|
|
175
|
+
<v-slide-group-item v-slot="{ isSelected, toggle, selectedClass }"
|
|
176
|
+
v-for="products in department?.products" :key="products">
|
|
177
|
+
<productCard :product="products?.products_id" :class="['ma-4', selectedClass]"
|
|
178
|
+
@click="toggle" />
|
|
179
|
+
<div class="d-flex fill-height align-center justify-center">
|
|
180
|
+
<v-scale-transition>
|
|
181
|
+
<v-icon v-if="isSelected" color="white" icon="mdi-close-circle-outline"
|
|
182
|
+
size="48"></v-icon>
|
|
183
|
+
</v-scale-transition>
|
|
184
|
+
</div>
|
|
185
|
+
</v-slide-group-item>
|
|
186
|
+
</v-slide-group>
|
|
187
|
+
</v-sheet>
|
|
188
|
+
|
|
189
|
+
<!--List of events in this department-->
|
|
190
|
+
<v-sheet class="mx-auto sliderProducts row align-items-stretch items-row justify-content-center"
|
|
191
|
+
v-if="department?.products?.products_id?.type === 'department' && events?.length">
|
|
192
|
+
<h4 style="left: 15px; position: relative;">{{ callouts?.menus?.[3]?.name }}
|
|
193
|
+
{{ department?.name }}</h4>
|
|
194
|
+
<v-slide-group v-model="model" class="pa-4" selected-class="bg-success" show-arrows>
|
|
195
|
+
<v-slide-group-item v-slot="{ isSelected, toggle, selectedClass }"
|
|
196
|
+
v-for="products in events" :key="products">
|
|
197
|
+
<productCard :product="products?.events_id" :class="['ma-4', selectedClass]"
|
|
198
|
+
@click="toggle" />
|
|
199
|
+
<div class="d-flex fill-height align-center justify-center">
|
|
200
|
+
<v-scale-transition>
|
|
201
|
+
<v-icon v-if="isSelected" color="white" icon="mdi-close-circle-outline"
|
|
202
|
+
size="48"></v-icon>
|
|
203
|
+
</v-scale-transition>
|
|
204
|
+
</div>
|
|
205
|
+
</v-slide-group-item>
|
|
206
|
+
</v-slide-group>
|
|
207
|
+
</v-sheet>
|
|
208
|
+
<!---->
|
|
209
|
+
|
|
210
|
+
<!--List of spaces in the department-->
|
|
211
|
+
<v-sheet class="mx-auto sliderProducts row align-items-stretch items-row justify-content-center"
|
|
212
|
+
v-if="department?.spaces?.length">
|
|
213
|
+
<h4 style="left: 15px; position: relative;">{{ callouts?.menus?.[4]?.name }}
|
|
214
|
+
{{ department?.name }}</h4>
|
|
215
|
+
<v-slide-group v-model="model" class="pa-4" selected-class="bg-success" show-arrows>
|
|
216
|
+
<v-slide-group-item v-slot="{ isSelected, toggle, selectedClass }"
|
|
217
|
+
v-for="spaces in department?.spaces" :key="spaces">
|
|
218
|
+
<spaces :space="spaces?.spaces_id" :class="['ma-4', selectedClass]" @click="toggle" />
|
|
219
|
+
<div class="d-flex fill-height align-center justify-center">
|
|
220
|
+
<v-scale-transition>
|
|
221
|
+
<v-icon v-if="isSelected" color="white" icon="mdi-close-circle-outline"
|
|
222
|
+
size="48"></v-icon>
|
|
223
|
+
</v-scale-transition>
|
|
224
|
+
</div>
|
|
225
|
+
</v-slide-group-item>
|
|
226
|
+
</v-slide-group>
|
|
227
|
+
</v-sheet>
|
|
228
|
+
</v-row>
|
|
229
|
+
</v-card>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</template>
|
|
233
|
+
|
|
234
|
+
<script setup>
|
|
235
|
+
import shorts from '#social/app/components/related/short.vue'
|
|
236
|
+
import spaces from '#social/app/components/related/space.vue'
|
|
237
|
+
import productCard from '#commerce/app/components/catalog/product/productCard.vue'
|
|
238
|
+
import travel from '@/components/categories/travel.vue'
|
|
239
|
+
import deals from '@/components/categories/deals.vue'
|
|
240
|
+
import timeComponent from '@/components/categories/time/time.vue'
|
|
241
|
+
import weather from '@/components/categories/weather/weather.vue'
|
|
242
|
+
|
|
243
|
+
const route = useRoute()
|
|
244
|
+
const model = ref(null)
|
|
245
|
+
const {
|
|
246
|
+
$directus,
|
|
247
|
+
$readItem,
|
|
248
|
+
$readItems
|
|
249
|
+
} = useNuxtApp()
|
|
250
|
+
|
|
251
|
+
const slug = computed(() => {
|
|
252
|
+
const s = route.params.slug
|
|
253
|
+
return Array.isArray(s) ? s[0] : s
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
const {
|
|
257
|
+
data: departmentRaw
|
|
258
|
+
} = await useAsyncData('department', () => {
|
|
259
|
+
return $directus.request(
|
|
260
|
+
$readItems('departments', {
|
|
261
|
+
fields: [
|
|
262
|
+
'*',
|
|
263
|
+
'categories.categories_id.*',
|
|
264
|
+
'spaces.spaces_id.*',
|
|
265
|
+
'products.products_id.*',
|
|
266
|
+
'products.products_id.image.*',
|
|
267
|
+
'shorts.shorts_id.*',
|
|
268
|
+
'shops.shops_id.*',
|
|
269
|
+
'image.*'
|
|
270
|
+
],
|
|
271
|
+
filter: {
|
|
272
|
+
slug: {
|
|
273
|
+
_eq: slug.value
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
limit: 1
|
|
277
|
+
})
|
|
278
|
+
)
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const department = computed(() => departmentRaw.value?.[0] || null)
|
|
282
|
+
|
|
283
|
+
const {
|
|
284
|
+
data: introProducts
|
|
285
|
+
} = await useAsyncData('introProducts', () => {
|
|
286
|
+
return $directus.request($readItems('departments', {
|
|
287
|
+
fields: ['*', { '*': ['*'] }],
|
|
288
|
+
limit: 2,
|
|
289
|
+
}))
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
const {
|
|
293
|
+
data: best
|
|
294
|
+
} = await useAsyncData('best', () => {
|
|
295
|
+
return $directus.request($readItems('departments', {
|
|
296
|
+
fields: ['*',
|
|
297
|
+
'products.products_id.*',
|
|
298
|
+
'images.*'
|
|
299
|
+
],
|
|
300
|
+
limit: 10,
|
|
301
|
+
filter: {
|
|
302
|
+
showcases: {
|
|
303
|
+
showcases_id: {
|
|
304
|
+
name: {
|
|
305
|
+
_eq: "Best Sellers"
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
}
|
|
310
|
+
}))
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
const {
|
|
314
|
+
data: latestProducts
|
|
315
|
+
} = await useAsyncData('latestProducts', () => {
|
|
316
|
+
return $directus.request($readItems('departments', {
|
|
317
|
+
fields: ['*',
|
|
318
|
+
'products.products_id.*',
|
|
319
|
+
'images.*'
|
|
320
|
+
],
|
|
321
|
+
limit: 10,
|
|
322
|
+
filter: {
|
|
323
|
+
products: {
|
|
324
|
+
products_id: {
|
|
325
|
+
status: {
|
|
326
|
+
_eq: "published"
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
}
|
|
331
|
+
}))
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
const {
|
|
335
|
+
data: limitProducts
|
|
336
|
+
} = await useAsyncData('limitProducts', () => {
|
|
337
|
+
return $directus.request($readItems('departments', {
|
|
338
|
+
fields: ['*',
|
|
339
|
+
'products.products_id.*',
|
|
340
|
+
'images.*'
|
|
341
|
+
],
|
|
342
|
+
limit: 2,
|
|
343
|
+
filter: {
|
|
344
|
+
products: {
|
|
345
|
+
products_id: {
|
|
346
|
+
status: {
|
|
347
|
+
_eq: "published"
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
}
|
|
352
|
+
}))
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
const {
|
|
356
|
+
data: events
|
|
357
|
+
} = await useAsyncData('events', () => {
|
|
358
|
+
return $directus.request($readItems('departments', {
|
|
359
|
+
fields: ['*',
|
|
360
|
+
'products.products_id.*',
|
|
361
|
+
'images.*'
|
|
362
|
+
],
|
|
363
|
+
limit: 10,
|
|
364
|
+
filter: {
|
|
365
|
+
products: {
|
|
366
|
+
products_id: {
|
|
367
|
+
type: {
|
|
368
|
+
_eq: "event"
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
}
|
|
373
|
+
}))
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
const {
|
|
377
|
+
data: callouts
|
|
378
|
+
} = await useAsyncData('callouts', () => {
|
|
379
|
+
return $directus.request($readItem('callouts', '2'))
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
useHead({
|
|
383
|
+
title: computed(() => department?.value?.name || 'Department Page')
|
|
384
|
+
});
|
|
385
|
+
</script>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="category">
|
|
3
|
+
|
|
4
|
+
<!-- Special Categories -->
|
|
5
|
+
<div v-if="category.slug === 'charts'">
|
|
6
|
+
<charts />
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div v-else-if="category.slug === 'radio-stations'">
|
|
10
|
+
<stations />
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div v-else-if="category.slug === 'eats'">
|
|
14
|
+
<eats />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div v-else-if="category.slug === 'restaurants'">
|
|
18
|
+
<div v-for="(shop, i) in restaurantsList" :key="i">
|
|
19
|
+
<restaurants :restaurant="shop" />
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<!-- Default Category Layout -->
|
|
24
|
+
<v-card variant="text" v-else>
|
|
25
|
+
<v-toolbar :style="`background-color: ${category?.color}; color: ${category?.colortext}`">
|
|
26
|
+
<v-toolbar-title><NuxtLink :to="`/departments/${category?.departments?.[0]?.departments_id?.name}`">Meeovi {{ category?.departments?.[0]?.departments_id?.name }}</NuxtLink> - {{ category?.name }}</v-toolbar-title>
|
|
27
|
+
<v-slide-group show-arrows v-if="category?.categories?.length">
|
|
28
|
+
<v-slide-group-item v-slot="{ isSelected, toggle }">
|
|
29
|
+
<v-menu>
|
|
30
|
+
<template #activator="{ props }">
|
|
31
|
+
<v-btn :color="isSelected ? 'primary' : undefined" class="ma-2" v-bind="props"
|
|
32
|
+
variant="text">
|
|
33
|
+
Categories
|
|
34
|
+
</v-btn>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<v-list class="departmentMenu">
|
|
38
|
+
<v-row>
|
|
39
|
+
<v-col cols="3" v-for="sub in category.categories" :key="sub?.categories_id?.id">
|
|
40
|
+
<v-list-item>
|
|
41
|
+
<NuxtLink :to="`/departments/categories/${sub.categories_id.id}`">
|
|
42
|
+
{{ sub.categories_id.name }}
|
|
43
|
+
</NuxtLink>
|
|
44
|
+
</v-list-item>
|
|
45
|
+
</v-col>
|
|
46
|
+
</v-row>
|
|
47
|
+
</v-list>
|
|
48
|
+
</v-menu>
|
|
49
|
+
</v-slide-group-item>
|
|
50
|
+
|
|
51
|
+
<v-slide-group-item v-for="menu in category.menus" :key="menu.id" v-slot="{ isSelected, toggle }">
|
|
52
|
+
<v-btn :color="isSelected ? 'primary' : undefined" class="ma-2" :href="menu.url">
|
|
53
|
+
{{ menu.name }}
|
|
54
|
+
</v-btn>
|
|
55
|
+
</v-slide-group-item>
|
|
56
|
+
</v-slide-group>
|
|
57
|
+
</v-toolbar>
|
|
58
|
+
</v-card>
|
|
59
|
+
|
|
60
|
+
<!-- Product List -->
|
|
61
|
+
<v-row>
|
|
62
|
+
<v-col cols="3" v-for="productRel in category.products" :key="productRel.products_id.id">
|
|
63
|
+
<productCard :product="productRel.products_id" />
|
|
64
|
+
</v-col>
|
|
65
|
+
</v-row>
|
|
66
|
+
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Loading / Not Found -->
|
|
70
|
+
<div v-else class="p-10 text-center text-xl text-neutral-700">
|
|
71
|
+
Loading category...
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
75
|
+
<script setup>
|
|
76
|
+
import charts from '~/components/categories/charts.vue'
|
|
77
|
+
import stations from '~/components/categories/stations.vue'
|
|
78
|
+
import eats from '~/components/categories/eats.vue'
|
|
79
|
+
import restaurants from '~/components/categories/restaurants.vue'
|
|
80
|
+
import productCard from '#commerce/app/components/catalog/product/productCard.vue'
|
|
81
|
+
|
|
82
|
+
const route = useRoute()
|
|
83
|
+
const {
|
|
84
|
+
$directus,
|
|
85
|
+
$readItem,
|
|
86
|
+
$readItems
|
|
87
|
+
} = useNuxtApp()
|
|
88
|
+
|
|
89
|
+
const slug = computed(() => {
|
|
90
|
+
const s = route.params.slug
|
|
91
|
+
return Array.isArray(s) ? s[0] : s
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const {
|
|
95
|
+
data: categoryRaw
|
|
96
|
+
} = await useAsyncData('categoryRaw', () => {
|
|
97
|
+
return $directus.request(
|
|
98
|
+
$readItems('categories', {
|
|
99
|
+
fields: [
|
|
100
|
+
'*',
|
|
101
|
+
'tags.tags_id.*',
|
|
102
|
+
'departments.departments_id.*',
|
|
103
|
+
'products.products_id.*',
|
|
104
|
+
'products.products_id.image.*',
|
|
105
|
+
'menus.*',
|
|
106
|
+
'image.*'
|
|
107
|
+
],
|
|
108
|
+
filter: {
|
|
109
|
+
slug: {
|
|
110
|
+
_eq: slug.value
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
limit: 1
|
|
114
|
+
})
|
|
115
|
+
)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// Unwrap array cleanly
|
|
119
|
+
const category = computed(() => categoryRaw.value?.[0] || null)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
// FETCH SHOPS FOR RESTAURANTS CATEGORY
|
|
123
|
+
const {
|
|
124
|
+
data: restaurantsList
|
|
125
|
+
} = await useAsyncData('restaurantsList', () => {
|
|
126
|
+
return $directus.request($readItems('shops', {
|
|
127
|
+
fields: ['*']
|
|
128
|
+
}))
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
// SEO
|
|
132
|
+
useHead({
|
|
133
|
+
title: computed(() => category.value?.name || 'Category Page')
|
|
134
|
+
})
|
|
135
|
+
</script>
|
|
@@ -246,14 +246,14 @@
|
|
|
246
246
|
computed,
|
|
247
247
|
watch
|
|
248
248
|
} from 'vue';
|
|
249
|
-
import comments from '
|
|
249
|
+
import comments from '@/components/placeholders/Comments.vue'
|
|
250
250
|
|
|
251
251
|
import productDetails from '../../components/catalog/product/productDetails.vue'
|
|
252
252
|
import productSpecs from '../../components/catalog/product/productSpecs.vue'
|
|
253
253
|
import productCard from '../../components/catalog/product/productCard.vue'
|
|
254
254
|
import giftCard from '../../components/catalog/product/giftCard.vue'
|
|
255
|
-
import short from '
|
|
256
|
-
import spaces from '
|
|
255
|
+
import short from '@/components/placeholders/Short.vue'
|
|
256
|
+
import spaces from '@/components/placeholders/Space.vue'
|
|
257
257
|
import shop from '../../components/catalog/shops/stores.vue'
|
|
258
258
|
|
|
259
259
|
const tab = ref(null);
|
|
@@ -100,31 +100,27 @@
|
|
|
100
100
|
</template>
|
|
101
101
|
|
|
102
102
|
<script setup>
|
|
103
|
-
import {
|
|
104
|
-
ref
|
|
105
|
-
} from 'vue'
|
|
103
|
+
import { ref } from 'vue'
|
|
106
104
|
import showcases from '~/components/catalog/product/relatedproducts.vue'
|
|
107
105
|
import productCard from '~/components/catalog/product/productCard.vue'
|
|
108
|
-
import comments from '
|
|
109
|
-
import spaces from '
|
|
110
|
-
import events from '
|
|
106
|
+
import comments from '@/components/placeholders/Comments.vue'
|
|
107
|
+
import spaces from '@/components/placeholders/Space.vue'
|
|
108
|
+
import events from '@/components/placeholders/Event.vue'
|
|
109
|
+
import { useContentFallback } from '../../composables/useContent'
|
|
111
110
|
|
|
112
111
|
const route = useRoute();
|
|
113
112
|
const tab = ref(null);
|
|
114
|
-
const {
|
|
115
|
-
$directus,
|
|
116
|
-
$readItem
|
|
117
|
-
} = useNuxtApp()
|
|
113
|
+
const { $directus, $readItem } = useNuxtApp()
|
|
118
114
|
|
|
119
115
|
const slug = computed(() => {
|
|
120
116
|
const s = route.params.slug
|
|
121
117
|
return Array.isArray(s) ? s[0] : s
|
|
122
118
|
})
|
|
123
119
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
} = await useAsyncData('shop', () => {
|
|
127
|
-
return
|
|
120
|
+
const content = useContentFallback()
|
|
121
|
+
|
|
122
|
+
const { data: shopRaw } = await useAsyncData('shop', () => {
|
|
123
|
+
return content.listShops({
|
|
128
124
|
fields: ['*',
|
|
129
125
|
'media.*',
|
|
130
126
|
'spaces.spaces_id.*',
|
|
@@ -143,14 +139,12 @@
|
|
|
143
139
|
}
|
|
144
140
|
},
|
|
145
141
|
limit: 1
|
|
146
|
-
})
|
|
142
|
+
})
|
|
147
143
|
})
|
|
148
144
|
|
|
149
145
|
const shop = computed(() => shopRaw.value?.[0] || null)
|
|
150
146
|
|
|
151
|
-
const {
|
|
152
|
-
data: shopbar
|
|
153
|
-
} = await useAsyncData('shopbar', () => {
|
|
147
|
+
const { data: shopbar } = await useAsyncData('shopbar', () => {
|
|
154
148
|
return $directus.request($readItem('navigation', '55'))
|
|
155
149
|
})
|
|
156
150
|
|