@crm-market/template-shared 1.0.0
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/assets/css/custom.css +70 -0
- package/assets/css/remixicon.css +2782 -0
- package/assets/css/satoshi-font.css +31 -0
- package/assets/fonts/flaticon.css +463 -0
- package/assets/fonts/flaticon.eot +0 -0
- package/assets/fonts/flaticon.html +2153 -0
- package/assets/fonts/flaticon.svg +441 -0
- package/assets/fonts/flaticon.ttf +0 -0
- package/assets/fonts/flaticon.woff +0 -0
- package/assets/fonts/flaticon.woff2 +0 -0
- package/assets/fonts/remixicon.eot +0 -0
- package/assets/fonts/remixicon.svg +8230 -0
- package/assets/fonts/remixicon.ttf +0 -0
- package/assets/fonts/remixicon.woff +0 -0
- package/assets/fonts/remixicon.woff2 +0 -0
- package/assets/scss/_variables.scss +31 -0
- package/assets/scss/components/_about.scss +58 -0
- package/assets/scss/components/_authentication.scss +124 -0
- package/assets/scss/components/_backtoptop.scss +27 -0
- package/assets/scss/components/_banner.scss +396 -0
- package/assets/scss/components/_best-deals.scss +74 -0
- package/assets/scss/components/_blank.scss +40 -0
- package/assets/scss/components/_blog.scss +193 -0
- package/assets/scss/components/_cart.scss +108 -0
- package/assets/scss/components/_categories.scss +82 -0
- package/assets/scss/components/_checkout.scss +110 -0
- package/assets/scss/components/_dashboard.scss +388 -0
- package/assets/scss/components/_faq.scss +22 -0
- package/assets/scss/components/_filter-rang.scss +109 -0
- package/assets/scss/components/_footer.scss +270 -0
- package/assets/scss/components/_global.scss +550 -0
- package/assets/scss/components/_header.scss +587 -0
- package/assets/scss/components/_hurry.scss +52 -0
- package/assets/scss/components/_navbar.scss +1008 -0
- package/assets/scss/components/_offers.scss +689 -0
- package/assets/scss/components/_pagination.scss +71 -0
- package/assets/scss/components/_popup.scss +172 -0
- package/assets/scss/components/_preloader.scss +108 -0
- package/assets/scss/components/_products.scss +1147 -0
- package/assets/scss/components/_rtl.scss +806 -0
- package/assets/scss/components/_services.scss +16 -0
- package/assets/scss/components/_sidebar.scss +259 -0
- package/assets/scss/style.css +6676 -0
- package/assets/scss/style.css.map +1 -0
- package/assets/scss/style.scss +40 -0
- package/assets/webfonts/Satoshi-Bold.eot +0 -0
- package/assets/webfonts/Satoshi-Bold.woff +0 -0
- package/assets/webfonts/Satoshi-Bold.woff2 +0 -0
- package/assets/webfonts/Satoshi-Medium.eot +0 -0
- package/assets/webfonts/Satoshi-Medium.woff +0 -0
- package/assets/webfonts/Satoshi-Medium.woff2 +0 -0
- package/assets/webfonts/Satoshi-Regular.eot +0 -0
- package/assets/webfonts/Satoshi-Regular.woff +0 -0
- package/assets/webfonts/Satoshi-Regular.woff2 +0 -0
- package/components/AboutUs/AboutUsTuan.vue +25 -0
- package/components/AboutUs/Statistics.vue +42 -0
- package/components/AboutUs/SubscribeToTheNewsletter.vue +57 -0
- package/components/AddAddress/index.vue +70 -0
- package/components/BestSellers/Products.vue +1562 -0
- package/components/BestSellers/RecentlyViewed.vue +304 -0
- package/components/Cart/ProductQuantity.vue +29 -0
- package/components/Cart/index.vue +167 -0
- package/components/Categories/index.vue +305 -0
- package/components/ChangePassword/index.vue +71 -0
- package/components/Checkout/index.vue +192 -0
- package/components/Common/DashboardNavigation.vue +37 -0
- package/components/Common/PageBanner.vue +28 -0
- package/components/Common/ProductCard.vue +152 -0
- package/components/Common/Services.vue +58 -0
- package/components/Contact/ContactForm.vue +91 -0
- package/components/Contact/ContactInfo.vue +74 -0
- package/components/Dashboard/RecentOrder.vue +173 -0
- package/components/Dashboard/index.vue +79 -0
- package/components/EditAddress/index.vue +119 -0
- package/components/EditProfile/index.vue +97 -0
- package/components/FAQ/index.vue +121 -0
- package/components/FeaturedProduct/FeaturedProducts.vue +304 -0
- package/components/FeaturedProduct/Products.vue +1562 -0
- package/components/ForgotPassword/index.vue +51 -0
- package/components/Layout/BackToUp.vue +38 -0
- package/components/Layout/Copyright.vue +25 -0
- package/components/Layout/Footer.vue +183 -0
- package/components/Layout/FooterTwo.vue +165 -0
- package/components/Layout/LocationOption.vue +178 -0
- package/components/Layout/MiddleHeader.vue +229 -0
- package/components/Layout/MiddleHeaderThree.vue +204 -0
- package/components/Layout/MiddleHeaderTwo.vue +240 -0
- package/components/Layout/Navbar.vue +185 -0
- package/components/Layout/NavbarStyleFour.vue +334 -0
- package/components/Layout/NavbarStyleThree.vue +188 -0
- package/components/Layout/NavbarStyleTwo.vue +108 -0
- package/components/Layout/Preloader.vue +18 -0
- package/components/Layout/RTLSwitchBtn.vue +40 -0
- package/components/Layout/ResponsiveNavbar.vue +431 -0
- package/components/Layout/TopHeader.vue +130 -0
- package/components/Login/index.vue +94 -0
- package/components/MyAccount/index.vue +154 -0
- package/components/NewArrivals/Products.vue +1969 -0
- package/components/NewArrivals/RecentlyViewed.vue +304 -0
- package/components/OrderDetails/index.vue +77 -0
- package/components/OrderHistory/index.vue +197 -0
- package/components/PrivacyPolicy/index.vue +112 -0
- package/components/ProductDetails/ProductDetailsTab.vue +343 -0
- package/components/ProductDetails/ProductQuantity.vue +29 -0
- package/components/ProductDetails/RecentlyViewed.vue +304 -0
- package/components/ProductDetails/index.vue +268 -0
- package/components/Products/RecentlyViewed.vue +304 -0
- package/components/Products/index.vue +292 -0
- package/components/Register/index.vue +88 -0
- package/components/TermsConditions/index.vue +112 -0
- package/components/TrendingProducts/FeaturedProducts.vue +304 -0
- package/components/TrendingProducts/Products.vue +1564 -0
- package/components/Wishlist/ProductQuantity.vue +29 -0
- package/components/Wishlist/index.vue +128 -0
- package/composables/useCart.ts +149 -0
- package/composables/useCategories.ts +87 -0
- package/composables/useCheckout.ts +131 -0
- package/composables/useProducts.ts +162 -0
- package/composables/useSiteConfig.ts +236 -0
- package/composables/useTemplateSections.ts +74 -0
- package/e2e/cart.spec.ts +71 -0
- package/e2e/fixtures/mock-api.ts +166 -0
- package/e2e/homepage.spec.ts +65 -0
- package/e2e/layout.spec.ts +73 -0
- package/e2e/navigation.spec.ts +61 -0
- package/e2e/pages/cart.page.ts +44 -0
- package/e2e/pages/homepage.page.ts +46 -0
- package/e2e/playwright.config.ts +32 -0
- package/e2e/products.spec.ts +33 -0
- package/layouts/default.vue +94 -0
- package/layouts/inner.vue +70 -0
- package/nuxt.config.ts +86 -0
- package/package.json +38 -0
- package/pages/about-us.vue +12 -0
- package/pages/address.vue +10 -0
- package/pages/cart.vue +10 -0
- package/pages/categories.vue +10 -0
- package/pages/change-password.vue +10 -0
- package/pages/checkout.vue +10 -0
- package/pages/contact.vue +11 -0
- package/pages/dashboard.vue +10 -0
- package/pages/edit-address.vue +10 -0
- package/pages/edit-profile.vue +10 -0
- package/pages/faq.vue +10 -0
- package/pages/forgot-password.vue +10 -0
- package/pages/login.vue +10 -0
- package/pages/my-account.vue +10 -0
- package/pages/order-details.vue +10 -0
- package/pages/order-history.vue +10 -0
- package/pages/privacy-policy.vue +10 -0
- package/pages/product-details.vue +10 -0
- package/pages/products.vue +10 -0
- package/pages/register.vue +10 -0
- package/pages/terms-conditions.vue +10 -0
- package/pages/wishlist.vue +10 -0
- package/plugins/site-init.client.ts +24 -0
- package/plugins/vuetify.ts +18 -0
- package/types/index.ts +121 -0
- package/utils/image.ts +13 -0
- package/utils/store.ts +21 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="recently-viewed-area pb-60 products-page">
|
|
3
|
+
<div class="container position-relative">
|
|
4
|
+
<div
|
|
5
|
+
class="d-lg-flex align-items-center justify-content-between text-center mb-27 mt-minus-6 border-top pt-4"
|
|
6
|
+
>
|
|
7
|
+
<h3 class="fs-3 mb-0 mb-1 mb-sm-0">Recently Viewed</h3>
|
|
8
|
+
<div>
|
|
9
|
+
<NuxtLink to="/products" class="read-more">
|
|
10
|
+
<span>See All Deals</span>
|
|
11
|
+
<i class="ri-arrow-right-up-line ms-1"></i>
|
|
12
|
+
</NuxtLink>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="row justify-content-center g-0">
|
|
16
|
+
<div class="col-c-20">
|
|
17
|
+
<div class="single-product-telemobile-item">
|
|
18
|
+
<div class="product-img position-relative">
|
|
19
|
+
<NuxtLink to="/product-details" class="d-block">
|
|
20
|
+
<img src="~/assets/images/product-1.png" alt="product" />
|
|
21
|
+
</NuxtLink>
|
|
22
|
+
<div
|
|
23
|
+
class="d-flex justify-content-between align-items-center position-absolute top-0 start-0 end-0"
|
|
24
|
+
>
|
|
25
|
+
<span class="minus-count">-11%</span>
|
|
26
|
+
<button class="border-0 wish-btn">
|
|
27
|
+
<i class="ri-heart-line"></i>
|
|
28
|
+
<i class="ri-heart-fill d-none"></i>
|
|
29
|
+
<v-tooltip activator="parent" location="top">
|
|
30
|
+
Favorite
|
|
31
|
+
</v-tooltip>
|
|
32
|
+
</button>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="product-content">
|
|
36
|
+
<NuxtLink to="/product-details" class="title">
|
|
37
|
+
Microwave Oven With LED Lighting - 700 Watts, 0.7 cu ft
|
|
38
|
+
</NuxtLink>
|
|
39
|
+
<div class="d-flex gap-1 review">
|
|
40
|
+
<i class="flaticon-star"></i>
|
|
41
|
+
<i class="flaticon-star"></i>
|
|
42
|
+
<i class="flaticon-star"></i>
|
|
43
|
+
<i class="flaticon-star"></i>
|
|
44
|
+
<i class="flaticon-star"></i>
|
|
45
|
+
<span>(5 Reviews)</span>
|
|
46
|
+
</div>
|
|
47
|
+
<h3>$399 <del>$450</del></h3>
|
|
48
|
+
<div class="d-flex sold-stock gap-4 align-items-center">
|
|
49
|
+
<span class="sold">620 Sold</span>
|
|
50
|
+
<span class="stock">
|
|
51
|
+
<i class="ri-check-line"></i> 150 In Stock
|
|
52
|
+
</span>
|
|
53
|
+
</div>
|
|
54
|
+
<div
|
|
55
|
+
class="d-flex align-items-center justify-content-between delivery-cart gap-4"
|
|
56
|
+
>
|
|
57
|
+
<span class="delivery">
|
|
58
|
+
<i class="ri-truck-line"></i>
|
|
59
|
+
Free Delivery
|
|
60
|
+
</span>
|
|
61
|
+
<button class="cart-btn">
|
|
62
|
+
<i class="ri-shopping-cart-line"></i>
|
|
63
|
+
<v-tooltip activator="parent" location="top">
|
|
64
|
+
Add To Cart
|
|
65
|
+
</v-tooltip>
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="col-c-20">
|
|
72
|
+
<div class="single-product-telemobile-item">
|
|
73
|
+
<div class="product-img position-relative">
|
|
74
|
+
<NuxtLink to="/product-details" class="d-block">
|
|
75
|
+
<img src="~/assets/images/product-6.png" alt="product" />
|
|
76
|
+
</NuxtLink>
|
|
77
|
+
<div
|
|
78
|
+
class="d-flex justify-content-between align-items-center position-absolute top-0 start-0 end-0"
|
|
79
|
+
>
|
|
80
|
+
<span class="minus-count">-15%</span>
|
|
81
|
+
<button class="border-0 wish-btn">
|
|
82
|
+
<i class="ri-heart-line"></i>
|
|
83
|
+
<i class="ri-heart-fill d-none"></i>
|
|
84
|
+
<v-tooltip activator="parent" location="top">
|
|
85
|
+
Favorite
|
|
86
|
+
</v-tooltip>
|
|
87
|
+
</button>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="product-content">
|
|
91
|
+
<NuxtLink to="/product-details" class="title">
|
|
92
|
+
Multiplatform Wireless Noise-Cancelling Gaming Headset
|
|
93
|
+
</NuxtLink>
|
|
94
|
+
<div class="d-flex gap-1 review">
|
|
95
|
+
<i class="flaticon-star"></i>
|
|
96
|
+
<i class="flaticon-star"></i>
|
|
97
|
+
<i class="flaticon-star"></i>
|
|
98
|
+
<i class="flaticon-star"></i>
|
|
99
|
+
<i class="flaticon-star"></i>
|
|
100
|
+
<span>(18 Reviews)</span>
|
|
101
|
+
</div>
|
|
102
|
+
<h3>$279 <del>$329</del></h3>
|
|
103
|
+
<div class="d-flex sold-stock gap-4 align-items-center">
|
|
104
|
+
<span class="sold">20 Sold</span>
|
|
105
|
+
<span class="stock">
|
|
106
|
+
<i class="ri-check-line"></i>
|
|
107
|
+
78 In Stock
|
|
108
|
+
</span>
|
|
109
|
+
</div>
|
|
110
|
+
<div
|
|
111
|
+
class="d-flex align-items-center justify-content-between delivery-cart gap-4"
|
|
112
|
+
>
|
|
113
|
+
<span class="delivery">
|
|
114
|
+
<i class="ri-truck-line"></i>
|
|
115
|
+
Free Delivery
|
|
116
|
+
</span>
|
|
117
|
+
<button class="cart-btn">
|
|
118
|
+
<i class="ri-shopping-cart-line"></i>
|
|
119
|
+
<v-tooltip activator="parent" location="top">
|
|
120
|
+
Add To Cart
|
|
121
|
+
</v-tooltip>
|
|
122
|
+
</button>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="col-c-20">
|
|
128
|
+
<div class="single-product-telemobile-item">
|
|
129
|
+
<div class="product-img position-relative">
|
|
130
|
+
<NuxtLink to="/product-details" class="d-block">
|
|
131
|
+
<img src="~/assets/images/product-7.png" alt="product" />
|
|
132
|
+
</NuxtLink>
|
|
133
|
+
<div
|
|
134
|
+
class="d-flex justify-content-between align-items-center position-absolute top-0 start-0 end-0"
|
|
135
|
+
>
|
|
136
|
+
<span class="minus-count">-40%</span>
|
|
137
|
+
<button class="border-0 wish-btn">
|
|
138
|
+
<i class="ri-heart-line"></i>
|
|
139
|
+
<i class="ri-heart-fill d-none"></i>
|
|
140
|
+
<v-tooltip activator="parent" location="top">
|
|
141
|
+
Favorite
|
|
142
|
+
</v-tooltip>
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
<div class="product-content">
|
|
147
|
+
<NuxtLink to="/product-details" class="title">
|
|
148
|
+
GPS Smartwatch with Bright Touchscreen Display
|
|
149
|
+
</NuxtLink>
|
|
150
|
+
<div class="d-flex gap-1 review">
|
|
151
|
+
<i class="flaticon-star"></i>
|
|
152
|
+
<i class="flaticon-star"></i>
|
|
153
|
+
<i class="flaticon-star"></i>
|
|
154
|
+
<i class="flaticon-star"></i>
|
|
155
|
+
<i class="flaticon-star"></i>
|
|
156
|
+
<span>(24 Reviews)</span>
|
|
157
|
+
</div>
|
|
158
|
+
<h3>$119 <del>$199</del></h3>
|
|
159
|
+
<div class="d-flex sold-stock gap-4 align-items-center">
|
|
160
|
+
<span class="sold">435 Sold</span>
|
|
161
|
+
<span class="stock">
|
|
162
|
+
<i class="ri-check-line"></i>
|
|
163
|
+
180 In Stock
|
|
164
|
+
</span>
|
|
165
|
+
</div>
|
|
166
|
+
<div
|
|
167
|
+
class="d-flex align-items-center justify-content-between delivery-cart gap-4"
|
|
168
|
+
>
|
|
169
|
+
<span class="delivery">
|
|
170
|
+
<i class="ri-truck-line"></i>
|
|
171
|
+
Free Delivery
|
|
172
|
+
</span>
|
|
173
|
+
<button class="cart-btn">
|
|
174
|
+
<i class="ri-shopping-cart-line"></i>
|
|
175
|
+
<v-tooltip activator="parent" location="top">
|
|
176
|
+
Add To Cart
|
|
177
|
+
</v-tooltip>
|
|
178
|
+
</button>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
<div class="col-c-20">
|
|
184
|
+
<div class="single-product-telemobile-item">
|
|
185
|
+
<div class="product-img position-relative">
|
|
186
|
+
<NuxtLink to="/product-details" class="d-block">
|
|
187
|
+
<img src="~/assets/images/product-8.png" alt="product" />
|
|
188
|
+
</NuxtLink>
|
|
189
|
+
<div
|
|
190
|
+
class="d-flex justify-content-between align-items-center position-absolute top-0 start-0 end-0"
|
|
191
|
+
>
|
|
192
|
+
<span class="minus-count">-20%</span>
|
|
193
|
+
<button class="border-0 wish-btn">
|
|
194
|
+
<i class="ri-heart-line"></i>
|
|
195
|
+
<i class="ri-heart-fill d-none"></i>
|
|
196
|
+
<v-tooltip activator="parent" location="top">
|
|
197
|
+
Favorite
|
|
198
|
+
</v-tooltip>
|
|
199
|
+
</button>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
<div class="product-content">
|
|
203
|
+
<NuxtLink to="/product-details" class="title">
|
|
204
|
+
SAMSUNG 32-Inch Class QLED 4K Q60C Series Quantum HDR
|
|
205
|
+
</NuxtLink>
|
|
206
|
+
<div class="d-flex gap-1 review">
|
|
207
|
+
<i class="flaticon-star"></i>
|
|
208
|
+
<i class="flaticon-star"></i>
|
|
209
|
+
<i class="flaticon-star"></i>
|
|
210
|
+
<i class="flaticon-star"></i>
|
|
211
|
+
<i class="flaticon-star"></i>
|
|
212
|
+
<span>(19 Reviews)</span>
|
|
213
|
+
</div>
|
|
214
|
+
<h3>$397 <del>$497</del></h3>
|
|
215
|
+
<div class="d-flex sold-stock gap-4 align-items-center">
|
|
216
|
+
<span class="sold">35 Sold</span>
|
|
217
|
+
<span class="stock">
|
|
218
|
+
<i class="ri-check-line"></i>
|
|
219
|
+
125 In Stock
|
|
220
|
+
</span>
|
|
221
|
+
</div>
|
|
222
|
+
<div
|
|
223
|
+
class="d-flex align-items-center justify-content-between delivery-cart gap-4"
|
|
224
|
+
>
|
|
225
|
+
<span class="delivery">
|
|
226
|
+
<i class="ri-truck-line"></i>
|
|
227
|
+
Free Delivery
|
|
228
|
+
</span>
|
|
229
|
+
<button class="cart-btn">
|
|
230
|
+
<i class="ri-shopping-cart-line"></i>
|
|
231
|
+
<v-tooltip activator="parent" location="top">
|
|
232
|
+
Add To Cart
|
|
233
|
+
</v-tooltip>
|
|
234
|
+
</button>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
<div class="col-c-20">
|
|
240
|
+
<div class="single-product-telemobile-item">
|
|
241
|
+
<div class="product-img position-relative">
|
|
242
|
+
<NuxtLink to="/product-details" class="d-block">
|
|
243
|
+
<img src="~/assets/images/product-9.png" alt="product" />
|
|
244
|
+
</NuxtLink>
|
|
245
|
+
<div
|
|
246
|
+
class="d-flex justify-content-between align-items-center position-absolute top-0 start-0 end-0"
|
|
247
|
+
>
|
|
248
|
+
<span class="minus-count">-10%</span>
|
|
249
|
+
<button class="border-0 wish-btn">
|
|
250
|
+
<i class="ri-heart-line"></i>
|
|
251
|
+
<i class="ri-heart-fill d-none"></i>
|
|
252
|
+
<v-tooltip activator="parent" location="top">
|
|
253
|
+
Favorite
|
|
254
|
+
</v-tooltip>
|
|
255
|
+
</button>
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
<div class="product-content">
|
|
259
|
+
<NuxtLink to="/product-details" class="title">
|
|
260
|
+
Apple MacBook Pro 16.2" with Liquid Retina XDR Display
|
|
261
|
+
</NuxtLink>
|
|
262
|
+
<div class="d-flex gap-1 review">
|
|
263
|
+
<i class="flaticon-star"></i>
|
|
264
|
+
<i class="flaticon-star"></i>
|
|
265
|
+
<i class="flaticon-star"></i>
|
|
266
|
+
<i class="flaticon-star"></i>
|
|
267
|
+
<i class="flaticon-star"></i>
|
|
268
|
+
<span>(76 Reviews)</span>
|
|
269
|
+
</div>
|
|
270
|
+
<h3>$3,499 <del>$3,799</del></h3>
|
|
271
|
+
<div class="d-flex sold-stock gap-4 align-items-center">
|
|
272
|
+
<span class="sold">348 Sold</span>
|
|
273
|
+
<span class="stock">
|
|
274
|
+
<i class="ri-check-line"></i>
|
|
275
|
+
245 In Stock
|
|
276
|
+
</span>
|
|
277
|
+
</div>
|
|
278
|
+
<div
|
|
279
|
+
class="d-flex align-items-center justify-content-between delivery-cart gap-4"
|
|
280
|
+
>
|
|
281
|
+
<span class="delivery">
|
|
282
|
+
<i class="ri-truck-line"></i>
|
|
283
|
+
Free Delivery
|
|
284
|
+
</span>
|
|
285
|
+
<button class="cart-btn">
|
|
286
|
+
<i class="ri-shopping-cart-line"></i>
|
|
287
|
+
<v-tooltip activator="parent" location="top">
|
|
288
|
+
Add To Cart
|
|
289
|
+
</v-tooltip>
|
|
290
|
+
</button>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
</template>
|
|
299
|
+
|
|
300
|
+
<script>
|
|
301
|
+
export default {
|
|
302
|
+
name: "RecentlyViewed",
|
|
303
|
+
};
|
|
304
|
+
</script>
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="products-area products-page ptb-60">
|
|
3
|
+
<div class="container">
|
|
4
|
+
<v-row>
|
|
5
|
+
<!-- Sidebar filters -->
|
|
6
|
+
<v-col
|
|
7
|
+
cols="12"
|
|
8
|
+
xl="2"
|
|
9
|
+
lg="3"
|
|
10
|
+
md="3"
|
|
11
|
+
class="mb-4 mt-xxl-0 overflow-hidden"
|
|
12
|
+
>
|
|
13
|
+
<div class="sidebar product-sidebar">
|
|
14
|
+
<!-- Categories filter -->
|
|
15
|
+
<div class="single-sidebar-widget">
|
|
16
|
+
<h3>Filter By Categories</h3>
|
|
17
|
+
<ul class="ps-0 mb-0 list-unstyled filter-selecet">
|
|
18
|
+
<li v-for="category in topLevelCategories" :key="category.id">
|
|
19
|
+
<div class="form-check">
|
|
20
|
+
<input
|
|
21
|
+
class="form-check-input"
|
|
22
|
+
type="radio"
|
|
23
|
+
:value="category.id"
|
|
24
|
+
:id="`cat-${category.id}`"
|
|
25
|
+
v-model="selectedCategoryId"
|
|
26
|
+
name="categoryFilter"
|
|
27
|
+
/>
|
|
28
|
+
<label class="form-check-label" :for="`cat-${category.id}`">
|
|
29
|
+
{{ category.name }}
|
|
30
|
+
</label>
|
|
31
|
+
</div>
|
|
32
|
+
</li>
|
|
33
|
+
<li v-if="selectedCategoryId">
|
|
34
|
+
<a href="javascript:void(0)" class="text-primary fs-13" @click="selectedCategoryId = ''">
|
|
35
|
+
Clear filter
|
|
36
|
+
</a>
|
|
37
|
+
</li>
|
|
38
|
+
</ul>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<!-- Price filter -->
|
|
42
|
+
<div class="single-sidebar-widget">
|
|
43
|
+
<h3>Price Range</h3>
|
|
44
|
+
<div class="d-flex gap-2 align-items-center">
|
|
45
|
+
<input
|
|
46
|
+
type="number"
|
|
47
|
+
class="form-control form-control-sm"
|
|
48
|
+
placeholder="Min"
|
|
49
|
+
v-model.number="minPrice"
|
|
50
|
+
min="0"
|
|
51
|
+
/>
|
|
52
|
+
<span>-</span>
|
|
53
|
+
<input
|
|
54
|
+
type="number"
|
|
55
|
+
class="form-control form-control-sm"
|
|
56
|
+
placeholder="Max"
|
|
57
|
+
v-model.number="maxPrice"
|
|
58
|
+
min="0"
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
<button
|
|
62
|
+
class="btn btn-sm btn-outline-primary mt-2 w-100"
|
|
63
|
+
@click="applyFilters"
|
|
64
|
+
>
|
|
65
|
+
Apply
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Sort -->
|
|
70
|
+
<div class="single-sidebar-widget">
|
|
71
|
+
<h3>Sort By</h3>
|
|
72
|
+
<select class="form-select form-select-sm" v-model="sortBy">
|
|
73
|
+
<option value="newest">Newest</option>
|
|
74
|
+
<option value="price-asc">Price: Low to High</option>
|
|
75
|
+
<option value="price-desc">Price: High to Low</option>
|
|
76
|
+
<option value="name">Name A-Z</option>
|
|
77
|
+
</select>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</v-col>
|
|
81
|
+
|
|
82
|
+
<!-- Products grid -->
|
|
83
|
+
<v-col cols="12" xl="10" lg="9" md="9">
|
|
84
|
+
<!-- Search info -->
|
|
85
|
+
<div class="d-flex align-items-center justify-content-between mb-3" v-if="searchQuery || selectedCategoryId">
|
|
86
|
+
<p class="mb-0 text-muted">
|
|
87
|
+
<span v-if="searchQuery">Search: "{{ searchQuery }}"</span>
|
|
88
|
+
<span v-if="selectedCategoryName"> | Category: {{ selectedCategoryName }}</span>
|
|
89
|
+
<span v-if="totalProducts"> | {{ totalProducts }} products found</span>
|
|
90
|
+
</p>
|
|
91
|
+
<button class="btn btn-sm btn-outline-secondary" @click="clearAllFilters">
|
|
92
|
+
Clear all
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<!-- Products count and total -->
|
|
97
|
+
<div class="d-flex align-items-center justify-content-between mb-3" v-else>
|
|
98
|
+
<p class="mb-0 text-muted">{{ totalProducts }} products</p>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Loading -->
|
|
102
|
+
<div v-if="loading" class="text-center py-5">
|
|
103
|
+
<div class="spinner-border text-primary" role="status">
|
|
104
|
+
<span class="visually-hidden">Loading...</span>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<!-- Products grid -->
|
|
109
|
+
<div class="row g-3" v-else-if="products.length > 0">
|
|
110
|
+
<div
|
|
111
|
+
v-for="product in products"
|
|
112
|
+
:key="product.id"
|
|
113
|
+
class="col-6 col-lg-4 col-xl-3"
|
|
114
|
+
>
|
|
115
|
+
<CommonProductCard :product="product" />
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<!-- No products -->
|
|
120
|
+
<div v-else class="text-center py-5">
|
|
121
|
+
<i class="ri-shopping-bag-line fs-1 text-muted"></i>
|
|
122
|
+
<p class="mt-3 text-muted">No products found</p>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<!-- Pagination -->
|
|
126
|
+
<div class="d-flex justify-content-center mt-4" v-if="totalPages > 1">
|
|
127
|
+
<nav>
|
|
128
|
+
<ul class="pagination">
|
|
129
|
+
<li class="page-item" :class="{ disabled: currentPage <= 1 }">
|
|
130
|
+
<a class="page-link" href="javascript:void(0)" @click="goToPage(currentPage - 1)">
|
|
131
|
+
<i class="ri-arrow-left-line"></i>
|
|
132
|
+
</a>
|
|
133
|
+
</li>
|
|
134
|
+
<li
|
|
135
|
+
v-for="page in visiblePages"
|
|
136
|
+
:key="page"
|
|
137
|
+
class="page-item"
|
|
138
|
+
:class="{ active: page === currentPage }"
|
|
139
|
+
>
|
|
140
|
+
<a class="page-link" href="javascript:void(0)" @click="goToPage(page)">
|
|
141
|
+
{{ page }}
|
|
142
|
+
</a>
|
|
143
|
+
</li>
|
|
144
|
+
<li class="page-item" :class="{ disabled: currentPage >= totalPages }">
|
|
145
|
+
<a class="page-link" href="javascript:void(0)" @click="goToPage(currentPage + 1)">
|
|
146
|
+
<i class="ri-arrow-right-line"></i>
|
|
147
|
+
</a>
|
|
148
|
+
</li>
|
|
149
|
+
</ul>
|
|
150
|
+
</nav>
|
|
151
|
+
</div>
|
|
152
|
+
</v-col>
|
|
153
|
+
</v-row>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</template>
|
|
157
|
+
|
|
158
|
+
<script lang="ts">
|
|
159
|
+
import { defineComponent, ref, computed, watch, onMounted } from "vue";
|
|
160
|
+
|
|
161
|
+
export default defineComponent({
|
|
162
|
+
name: "ProductsIndex",
|
|
163
|
+
setup() {
|
|
164
|
+
const route = useRoute();
|
|
165
|
+
const router = useRouter();
|
|
166
|
+
const { fetchProducts, products, loading } = useProducts();
|
|
167
|
+
const { topLevelCategories, getCategoryById } = useCategories();
|
|
168
|
+
|
|
169
|
+
const selectedCategoryId = ref('');
|
|
170
|
+
const minPrice = ref<number | undefined>(undefined);
|
|
171
|
+
const maxPrice = ref<number | undefined>(undefined);
|
|
172
|
+
const sortBy = ref('newest');
|
|
173
|
+
const searchQuery = ref('');
|
|
174
|
+
const currentPage = ref(1);
|
|
175
|
+
const totalProducts = ref(0);
|
|
176
|
+
const perPage = 20;
|
|
177
|
+
|
|
178
|
+
const selectedCategoryName = computed(() => {
|
|
179
|
+
if (!selectedCategoryId.value) return '';
|
|
180
|
+
const cat = getCategoryById(selectedCategoryId.value);
|
|
181
|
+
return cat?.name || '';
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const totalPages = computed(() => Math.ceil(totalProducts.value / perPage));
|
|
185
|
+
|
|
186
|
+
const visiblePages = computed(() => {
|
|
187
|
+
const pages: number[] = [];
|
|
188
|
+
const total = totalPages.value;
|
|
189
|
+
const current = currentPage.value;
|
|
190
|
+
const start = Math.max(1, current - 2);
|
|
191
|
+
const end = Math.min(total, current + 2);
|
|
192
|
+
for (let i = start; i <= end; i++) {
|
|
193
|
+
pages.push(i);
|
|
194
|
+
}
|
|
195
|
+
return pages;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const loadProducts = async () => {
|
|
199
|
+
const sortParts = sortBy.value.split('-');
|
|
200
|
+
const sortField = sortParts[0] as any;
|
|
201
|
+
const sortOrder = sortParts[1] as 'asc' | 'desc' | undefined;
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const result = await fetchProducts({
|
|
205
|
+
categoryId: selectedCategoryId.value || undefined,
|
|
206
|
+
minPrice: minPrice.value,
|
|
207
|
+
maxPrice: maxPrice.value,
|
|
208
|
+
search: searchQuery.value || undefined,
|
|
209
|
+
sortBy: sortField === 'price' ? 'price' : sortField === 'name' ? 'name' : 'newest',
|
|
210
|
+
sortOrder: sortOrder || (sortField === 'price' ? 'asc' : 'desc'),
|
|
211
|
+
});
|
|
212
|
+
totalProducts.value = result?.length || 0;
|
|
213
|
+
} catch (e) {
|
|
214
|
+
console.error('Error loading products:', e);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const applyFilters = () => {
|
|
219
|
+
currentPage.value = 1;
|
|
220
|
+
syncToUrl();
|
|
221
|
+
loadProducts();
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const clearAllFilters = () => {
|
|
225
|
+
selectedCategoryId.value = '';
|
|
226
|
+
minPrice.value = undefined;
|
|
227
|
+
maxPrice.value = undefined;
|
|
228
|
+
searchQuery.value = '';
|
|
229
|
+
sortBy.value = 'newest';
|
|
230
|
+
currentPage.value = 1;
|
|
231
|
+
router.push('/products');
|
|
232
|
+
loadProducts();
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const goToPage = (page: number) => {
|
|
236
|
+
if (page < 1 || page > totalPages.value) return;
|
|
237
|
+
currentPage.value = page;
|
|
238
|
+
syncToUrl();
|
|
239
|
+
loadProducts();
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const syncToUrl = () => {
|
|
243
|
+
const query: any = {};
|
|
244
|
+
if (selectedCategoryId.value) query.categoryId = selectedCategoryId.value;
|
|
245
|
+
if (searchQuery.value) query.search = searchQuery.value;
|
|
246
|
+
if (minPrice.value) query.minPrice = minPrice.value;
|
|
247
|
+
if (maxPrice.value) query.maxPrice = maxPrice.value;
|
|
248
|
+
if (sortBy.value !== 'newest') query.sortBy = sortBy.value;
|
|
249
|
+
if (currentPage.value > 1) query.page = currentPage.value;
|
|
250
|
+
router.replace({ path: '/products', query });
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const syncFromUrl = () => {
|
|
254
|
+
const q = route.query;
|
|
255
|
+
if (q.categoryId) selectedCategoryId.value = q.categoryId as string;
|
|
256
|
+
if (q.search) searchQuery.value = q.search as string;
|
|
257
|
+
if (q.minPrice) minPrice.value = Number(q.minPrice);
|
|
258
|
+
if (q.maxPrice) maxPrice.value = Number(q.maxPrice);
|
|
259
|
+
if (q.sortBy) sortBy.value = q.sortBy as string;
|
|
260
|
+
if (q.page) currentPage.value = Number(q.page);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// Watch for category and sort changes
|
|
264
|
+
watch(selectedCategoryId, () => applyFilters());
|
|
265
|
+
watch(sortBy, () => applyFilters());
|
|
266
|
+
|
|
267
|
+
onMounted(() => {
|
|
268
|
+
syncFromUrl();
|
|
269
|
+
loadProducts();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
products,
|
|
274
|
+
loading,
|
|
275
|
+
topLevelCategories,
|
|
276
|
+
selectedCategoryId,
|
|
277
|
+
selectedCategoryName,
|
|
278
|
+
minPrice,
|
|
279
|
+
maxPrice,
|
|
280
|
+
sortBy,
|
|
281
|
+
searchQuery,
|
|
282
|
+
currentPage,
|
|
283
|
+
totalProducts,
|
|
284
|
+
totalPages,
|
|
285
|
+
visiblePages,
|
|
286
|
+
applyFilters,
|
|
287
|
+
clearAllFilters,
|
|
288
|
+
goToPage,
|
|
289
|
+
};
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
</script>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="authentication-area ptb-60">
|
|
3
|
+
<div class="container">
|
|
4
|
+
<div class="authentication-content">
|
|
5
|
+
<div class="row">
|
|
6
|
+
<div class="col-lg-5">
|
|
7
|
+
<div class="login h-100 text-center">
|
|
8
|
+
<img
|
|
9
|
+
src="~/assets/images/register.png"
|
|
10
|
+
class="h-100 object-fit-cover"
|
|
11
|
+
alt="register"
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="col-lg-7">
|
|
16
|
+
<div class="authentication-form">
|
|
17
|
+
<ul class="nav nav-tabs login-tabs" id="myTab" role="tablist">
|
|
18
|
+
<li class="nav-item" role="presentation">
|
|
19
|
+
<NuxtLink to="/login" class="nav-link">Login</NuxtLink>
|
|
20
|
+
</li>
|
|
21
|
+
<li class="nav-item" role="presentation">
|
|
22
|
+
<NuxtLink to="/register" class="nav-link active">
|
|
23
|
+
Register
|
|
24
|
+
</NuxtLink>
|
|
25
|
+
</li>
|
|
26
|
+
</ul>
|
|
27
|
+
<p>
|
|
28
|
+
If you have an account, sign in with your username or email
|
|
29
|
+
address.
|
|
30
|
+
</p>
|
|
31
|
+
<form>
|
|
32
|
+
<div class="form-group mb-4">
|
|
33
|
+
<label class="label">Username *</label>
|
|
34
|
+
<input
|
|
35
|
+
type="text"
|
|
36
|
+
class="form-control"
|
|
37
|
+
placeholder="Enter your user name"
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="form-group mb-4">
|
|
41
|
+
<label class="label">Email Address *</label>
|
|
42
|
+
<input
|
|
43
|
+
type="email"
|
|
44
|
+
class="form-control"
|
|
45
|
+
placeholder="Enter your email address"
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="form-group mb-4">
|
|
49
|
+
<label class="label">Password *</label>
|
|
50
|
+
<input
|
|
51
|
+
type="password"
|
|
52
|
+
class="form-control"
|
|
53
|
+
placeholder="Enter password"
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="form-group mb-4">
|
|
57
|
+
<button
|
|
58
|
+
type="submit"
|
|
59
|
+
class="btn btn-warning btn-pill text-white w-100 d-block"
|
|
60
|
+
>
|
|
61
|
+
Register
|
|
62
|
+
</button>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="form-group mb-0">
|
|
65
|
+
<p class="text-secondary ms-1 text-primary">
|
|
66
|
+
Already have an account?
|
|
67
|
+
<NuxtLink
|
|
68
|
+
to="/login"
|
|
69
|
+
class="text-decoration-none text-primary"
|
|
70
|
+
>
|
|
71
|
+
Login
|
|
72
|
+
</NuxtLink>
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
</form>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<script>
|
|
85
|
+
export default {
|
|
86
|
+
name: "Register",
|
|
87
|
+
};
|
|
88
|
+
</script>
|