@crm-market/template-shared 1.0.6 → 1.0.8
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/scss/_variables.scss +3 -3
- package/assets/scss/components/_header.scss +1 -1
- package/assets/scss/style.css +4 -4
- package/components/AboutUs/StaticContent.vue +32 -0
- package/components/Cart/CartEmpty.vue +42 -0
- package/components/Cart/CartItem.vue +145 -0
- package/components/Cart/CartSummary.vue +57 -0
- package/components/Cart/ProductQuantity.vue +23 -13
- package/components/Cart/index.vue +68 -150
- package/components/Categories/index.vue +88 -291
- package/components/Checkout/AddressFields.vue +74 -0
- package/components/Checkout/CheckoutForm.vue +75 -0
- package/components/Checkout/CityAutocomplete.vue +68 -0
- package/components/Checkout/DeliveryMethodCard.vue +66 -0
- package/components/Checkout/DeliveryOptions.vue +148 -0
- package/components/Checkout/OrderSummary.vue +116 -0
- package/components/Checkout/PaymentOptions.vue +76 -0
- package/components/Checkout/PickupPoints.vue +46 -0
- package/components/Checkout/PromoCode.vue +166 -0
- package/components/Checkout/index.vue +235 -173
- package/components/Checkout/types.ts +45 -0
- package/components/Common/PageBanner.vue +22 -20
- package/components/Common/ProductCard.vue +139 -115
- package/components/Common/Services.vue +4 -4
- package/components/Contact/ContactForm.vue +44 -74
- package/components/Contact/ContactInfo.vue +35 -61
- package/components/FAQ/index.vue +6 -119
- package/components/Layout/Copyright.vue +11 -9
- package/components/Layout/Footer.vue +49 -136
- package/components/Layout/HeaderBar.vue +174 -0
- package/components/Layout/HeaderLogo.vue +27 -0
- package/components/Layout/MiddleHeader.vue +1 -228
- package/components/Layout/MiddleHeaderThree.vue +1 -203
- package/components/Layout/MiddleHeaderTwo.vue +1 -239
- package/components/Layout/NavLinks.vue +23 -0
- package/components/Layout/Navbar.vue +38 -151
- package/components/Layout/NavbarStyleFour.vue +1 -332
- package/components/Layout/NavbarStyleThree.vue +1 -188
- package/components/Layout/NavbarStyleTwo.vue +1 -108
- package/components/Layout/Preloader.vue +5 -12
- package/components/Layout/ResponsiveNavbar.vue +32 -418
- package/components/Layout/SitewideBanner.vue +285 -0
- package/components/Layout/TopHeader.vue +17 -83
- package/components/Layout/layoutData.ts +83 -0
- package/components/PrivacyPolicy/index.vue +6 -110
- package/components/ProductDetails/ProductDetailsTab.vue +31 -321
- package/components/ProductDetails/ProductGallery.vue +45 -0
- package/components/ProductDetails/ProductQuantity.vue +8 -14
- package/components/ProductDetails/RecentlyViewed.vue +53 -289
- package/components/ProductDetails/RelatedProducts.vue +64 -0
- package/components/ProductDetails/index.vue +90 -230
- package/components/Products/index.vue +78 -16
- package/components/TermsConditions/index.vue +6 -110
- package/components/Wishlist/index.vue +62 -88
- package/composables/useCart.ts +133 -81
- package/composables/useCategories.ts +67 -31
- package/composables/useCategoryImages.ts +45 -0
- package/composables/useCheckout.ts +302 -97
- package/composables/useContactForm.ts +57 -0
- package/composables/useHomeContent.ts +220 -0
- package/composables/useI18n.ts +12 -24
- package/composables/useJsonLd.ts +162 -0
- package/composables/useProducts.ts +244 -83
- package/composables/useRecent.ts +30 -0
- package/composables/useSanitize.ts +76 -0
- package/composables/useSiteConfig.ts +51 -47
- package/composables/useStaticPages.ts +48 -0
- package/composables/useStoreOrigin.ts +32 -0
- package/composables/useTemplateSections.ts +51 -3
- package/composables/useThemeVars.ts +113 -0
- package/composables/useWishlist.ts +72 -0
- package/layouts/default.vue +80 -19
- package/locales/en.json +255 -86
- package/locales/uk.json +251 -82
- package/modules/template-schema.ts +35 -0
- package/nuxt.config.ts +8 -11
- package/package.json +1 -1
- package/pages/about-us.vue +9 -9
- package/pages/cart.vue +0 -1
- package/pages/categories.vue +0 -1
- package/pages/category/[slug].vue +84 -0
- package/pages/checkout.vue +0 -1
- package/pages/contact.vue +6 -6
- package/pages/delivery.vue +12 -0
- package/pages/faq.vue +6 -6
- package/pages/order-success.vue +113 -0
- package/pages/privacy-policy.vue +6 -6
- package/pages/product/[slug].vue +82 -0
- package/pages/product-details.vue +14 -6
- package/pages/products.vue +12 -1
- package/pages/returns.vue +12 -0
- package/pages/terms-conditions.vue +6 -6
- package/pages/wishlist.vue +2 -2
- package/utils/image.ts +0 -1
- package/utils/seo-urls.ts +70 -0
- package/utils/store-origin.ts +36 -0
- package/components/AboutUs/AboutUsTuan.vue +0 -25
- package/components/AboutUs/Statistics.vue +0 -42
- package/components/AboutUs/SubscribeToTheNewsletter.vue +0 -57
- package/components/AddAddress/index.vue +0 -68
- package/components/BestSellers/Products.vue +0 -1562
- package/components/BestSellers/RecentlyViewed.vue +0 -304
- package/components/ChangePassword/index.vue +0 -69
- package/components/Common/DashboardNavigation.vue +0 -35
- package/components/Dashboard/RecentOrder.vue +0 -173
- package/components/Dashboard/index.vue +0 -77
- package/components/EditAddress/index.vue +0 -117
- package/components/EditProfile/index.vue +0 -95
- package/components/FeaturedProduct/FeaturedProducts.vue +0 -304
- package/components/FeaturedProduct/Products.vue +0 -1562
- package/components/ForgotPassword/index.vue +0 -49
- package/components/Layout/FooterTwo.vue +0 -159
- package/components/Layout/LocationOption.vue +0 -178
- package/components/Layout/RTLSwitchBtn.vue +0 -40
- package/components/Login/index.vue +0 -89
- package/components/MyAccount/index.vue +0 -154
- package/components/NewArrivals/Products.vue +0 -1969
- package/components/NewArrivals/RecentlyViewed.vue +0 -304
- package/components/OrderDetails/index.vue +0 -75
- package/components/OrderHistory/index.vue +0 -195
- package/components/Products/RecentlyViewed.vue +0 -302
- package/components/Register/index.vue +0 -83
- package/components/TrendingProducts/FeaturedProducts.vue +0 -304
- package/components/TrendingProducts/Products.vue +0 -1564
- package/components/Wishlist/ProductQuantity.vue +0 -29
- package/layouts/inner.vue +0 -70
- package/locales/ar.json +0 -234
- package/locales/ru.json +0 -234
- package/pages/address.vue +0 -11
- package/pages/change-password.vue +0 -11
- package/pages/dashboard.vue +0 -11
- package/pages/edit-address.vue +0 -11
- package/pages/edit-profile.vue +0 -11
- package/pages/forgot-password.vue +0 -11
- package/pages/login.vue +0 -11
- package/pages/my-account.vue +0 -11
- package/pages/order-details.vue +0 -11
- package/pages/order-history.vue +0 -11
- package/pages/register.vue +0 -11
|
@@ -1,230 +1,3 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<div class="container">
|
|
4
|
-
<div class="d-lg-flex justify-content-between align-items-center">
|
|
5
|
-
<div
|
|
6
|
-
class="d-flex align-items-center middle-header-left justify-content-center justify-content-lg-end"
|
|
7
|
-
>
|
|
8
|
-
<NuxtLink to="/" class="d-none d-lg-block middle-logo">
|
|
9
|
-
<img :src="logoUrl || defaultLogo" alt="logo" />
|
|
10
|
-
</NuxtLink>
|
|
11
|
-
<div class="d-flex">
|
|
12
|
-
<div class="dropdown">
|
|
13
|
-
<button
|
|
14
|
-
class="dropdown-toggle border border-2 bg-transparent all-categories"
|
|
15
|
-
@click="toggleAllCategories"
|
|
16
|
-
:aria-pressed="show ? 'true' : 'false'"
|
|
17
|
-
:class="{ show: buttonShowState }"
|
|
18
|
-
>
|
|
19
|
-
{{ t('nav.allCategories') }}
|
|
20
|
-
</button>
|
|
21
|
-
<ul class="dropdown-menu" :class="{ toggler: show }">
|
|
22
|
-
<li v-for="category in topLevelCategories" :key="category.id">
|
|
23
|
-
<NuxtLink
|
|
24
|
-
class="dropdown-item"
|
|
25
|
-
:to="`/products?categoryId=${category.id}`"
|
|
26
|
-
>
|
|
27
|
-
{{ category.name }}
|
|
28
|
-
</NuxtLink>
|
|
29
|
-
</li>
|
|
30
|
-
<li v-if="topLevelCategories.length === 0">
|
|
31
|
-
<span class="dropdown-item text-muted">{{ t('nav.noCategories') }}</span>
|
|
32
|
-
</li>
|
|
33
|
-
</ul>
|
|
34
|
-
</div>
|
|
35
|
-
<div class="position-relative">
|
|
36
|
-
<input
|
|
37
|
-
type="text"
|
|
38
|
-
class="form-control border-2"
|
|
39
|
-
:placeholder="t('nav.searchProducts')"
|
|
40
|
-
v-model="searchQuery"
|
|
41
|
-
@keyup.enter="handleSearch"
|
|
42
|
-
/>
|
|
43
|
-
<button
|
|
44
|
-
type="submit"
|
|
45
|
-
class="position-absolute top-50 end-0 translate-middle-y btn btn-primary fs-14 fw-medium text-white"
|
|
46
|
-
@click="handleSearch"
|
|
47
|
-
>
|
|
48
|
-
<i class="ri-search-line"></i>
|
|
49
|
-
<span class="d-none d-sm-inline-block">{{ t('nav.search') }}</span>
|
|
50
|
-
</button>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<ul
|
|
56
|
-
class="d-flex middle-header-right ps-0 mb-0 list-unstyled justify-content-center justify-content-lg-end mt-3 mt-lg-0"
|
|
57
|
-
>
|
|
58
|
-
<li class="buy-info">
|
|
59
|
-
<NuxtLink to="/login" class="text-decoration-none">
|
|
60
|
-
<div class="d-flex align-items-center">
|
|
61
|
-
<div class="flex-shrink-0">
|
|
62
|
-
<i class="ri-user-line"></i>
|
|
63
|
-
</div>
|
|
64
|
-
<div class="flex-grow-1 ms-10">
|
|
65
|
-
<span>{{ t('auth.login') }}</span>
|
|
66
|
-
<h3>{{ t('account.yourAccount') }}</h3>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
</NuxtLink>
|
|
70
|
-
</li>
|
|
71
|
-
<li class="buy-info">
|
|
72
|
-
<NuxtLink to="/wishlist" class="text-decoration-none">
|
|
73
|
-
<div class="position-relative me-9">
|
|
74
|
-
<i class="ri-heart-line"></i>
|
|
75
|
-
<span class="count">0</span>
|
|
76
|
-
</div>
|
|
77
|
-
</NuxtLink>
|
|
78
|
-
</li>
|
|
79
|
-
<li class="buy-info">
|
|
80
|
-
<div class="dropdown">
|
|
81
|
-
<a
|
|
82
|
-
class="text-decoration-none"
|
|
83
|
-
href="javascript:void(0);"
|
|
84
|
-
@click="toggleBuyInfo"
|
|
85
|
-
:aria-pressed="active ? 'true' : 'false'"
|
|
86
|
-
:class="{ active: buttonActiveState }"
|
|
87
|
-
>
|
|
88
|
-
<div class="d-flex align-items-center">
|
|
89
|
-
<div class="flex-shrink-0">
|
|
90
|
-
<div class="position-relative me-9">
|
|
91
|
-
<i class="ri-shopping-cart-line"></i>
|
|
92
|
-
<span class="count">{{ itemCount }}</span>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
<div class="flex-grow-1 ms-1">
|
|
96
|
-
<span>{{ t('account.yourCart') }}</span>
|
|
97
|
-
<h3>${{ subtotal.toFixed(2) }}</h3>
|
|
98
|
-
</div>
|
|
99
|
-
</div>
|
|
100
|
-
</a>
|
|
101
|
-
<ul
|
|
102
|
-
class="dropdown-menu cart-dropdown dropdown-menu-end"
|
|
103
|
-
:class="{ toggler: active }"
|
|
104
|
-
>
|
|
105
|
-
<li
|
|
106
|
-
v-for="item in cart.items.slice(0, 3)"
|
|
107
|
-
:key="item.productId"
|
|
108
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
109
|
-
>
|
|
110
|
-
<button
|
|
111
|
-
class="p-0 border-0 bg-transparent delete-btn"
|
|
112
|
-
@click="removeFromCart(item.productId)"
|
|
113
|
-
>
|
|
114
|
-
<i class="ri-delete-bin-7-line"></i>
|
|
115
|
-
</button>
|
|
116
|
-
<NuxtLink
|
|
117
|
-
class="dropdown-item d-flex align-items-center"
|
|
118
|
-
:to="`/product-details?id=${item.productId}`"
|
|
119
|
-
>
|
|
120
|
-
<img
|
|
121
|
-
v-if="item.image"
|
|
122
|
-
:src="resolveImageUrl(item.image)"
|
|
123
|
-
alt="product"
|
|
124
|
-
/>
|
|
125
|
-
<div class="ms-3 d-inline-block text-truncate">
|
|
126
|
-
<span>{{ item.name }}</span>
|
|
127
|
-
<h3>${{ (item.discountPrice || item.price).toFixed(2) }}</h3>
|
|
128
|
-
</div>
|
|
129
|
-
</NuxtLink>
|
|
130
|
-
</li>
|
|
131
|
-
<li v-if="isEmpty" class="cart-item text-center text-muted py-3">
|
|
132
|
-
Cart is empty
|
|
133
|
-
</li>
|
|
134
|
-
<template v-if="!isEmpty">
|
|
135
|
-
<li
|
|
136
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
137
|
-
>
|
|
138
|
-
<h3 class="fs-15 mb-0">Total</h3>
|
|
139
|
-
<h3 class="fs-15 mb-0">${{ subtotal.toFixed(2) }}</h3>
|
|
140
|
-
</li>
|
|
141
|
-
<li
|
|
142
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
143
|
-
>
|
|
144
|
-
<NuxtLink to="/cart" class="btn btn-primary fs-14 text-white">
|
|
145
|
-
{{ t('account.viewCart') }}
|
|
146
|
-
</NuxtLink>
|
|
147
|
-
<NuxtLink
|
|
148
|
-
to="/checkout"
|
|
149
|
-
class="btn btn-warning fs-14 text-white"
|
|
150
|
-
>
|
|
151
|
-
{{ t('account.checkout') }}
|
|
152
|
-
</NuxtLink>
|
|
153
|
-
</li>
|
|
154
|
-
</template>
|
|
155
|
-
</ul>
|
|
156
|
-
</div>
|
|
157
|
-
</li>
|
|
158
|
-
</ul>
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
2
|
+
<LayoutHeaderBar btn-class="btn-primary" />
|
|
162
3
|
</template>
|
|
163
|
-
|
|
164
|
-
<script lang="ts">
|
|
165
|
-
import { defineComponent, ref } from "vue";
|
|
166
|
-
|
|
167
|
-
import defaultLogoImg from "~/assets/images/logo.png";
|
|
168
|
-
|
|
169
|
-
export default defineComponent({
|
|
170
|
-
name: "MiddleHeader",
|
|
171
|
-
setup() {
|
|
172
|
-
const show = ref(false);
|
|
173
|
-
const buttonShowState = ref(false);
|
|
174
|
-
const active = ref(false);
|
|
175
|
-
const buttonActiveState = ref(false);
|
|
176
|
-
const searchQuery = ref("");
|
|
177
|
-
const defaultLogo = defaultLogoImg;
|
|
178
|
-
const router = useRouter();
|
|
179
|
-
|
|
180
|
-
const { t } = useI18n();
|
|
181
|
-
const { topLevelCategories } = useCategories();
|
|
182
|
-
const { logoUrl } = useSiteConfig();
|
|
183
|
-
const { cart, itemCount, subtotal, isEmpty, removeFromCart } = useCart();
|
|
184
|
-
|
|
185
|
-
const resolveImageUrl = (url: string) => {
|
|
186
|
-
if (!url) return '';
|
|
187
|
-
if (url.startsWith('http')) return url;
|
|
188
|
-
const apiBase = getApiBaseUrl();
|
|
189
|
-
const baseUrl = apiBase.replace('/api', '');
|
|
190
|
-
return `${baseUrl}${url}`;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
const toggleAllCategories = () => {
|
|
194
|
-
show.value = !show.value;
|
|
195
|
-
buttonShowState.value = !buttonShowState.value;
|
|
196
|
-
};
|
|
197
|
-
const toggleBuyInfo = () => {
|
|
198
|
-
active.value = !active.value;
|
|
199
|
-
buttonActiveState.value = !buttonActiveState.value;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
const handleSearch = () => {
|
|
203
|
-
if (searchQuery.value.trim()) {
|
|
204
|
-
router.push(`/products?search=${encodeURIComponent(searchQuery.value.trim())}`);
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
show,
|
|
210
|
-
buttonShowState,
|
|
211
|
-
active,
|
|
212
|
-
buttonActiveState,
|
|
213
|
-
toggleAllCategories,
|
|
214
|
-
toggleBuyInfo,
|
|
215
|
-
searchQuery,
|
|
216
|
-
handleSearch,
|
|
217
|
-
defaultLogo,
|
|
218
|
-
topLevelCategories,
|
|
219
|
-
logoUrl,
|
|
220
|
-
cart,
|
|
221
|
-
itemCount,
|
|
222
|
-
subtotal,
|
|
223
|
-
isEmpty,
|
|
224
|
-
removeFromCart,
|
|
225
|
-
resolveImageUrl,
|
|
226
|
-
t,
|
|
227
|
-
};
|
|
228
|
-
},
|
|
229
|
-
});
|
|
230
|
-
</script>
|
|
@@ -1,205 +1,3 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<div class="container">
|
|
4
|
-
<div class="d-lg-flex justify-content-between align-items-center">
|
|
5
|
-
<div
|
|
6
|
-
class="d-flex align-items-center middle-header-left justify-content-center justify-content-lg-end"
|
|
7
|
-
>
|
|
8
|
-
<NuxtLink to="/" class="d-none d-lg-block middle-logo style-two">
|
|
9
|
-
<img :src="logoUrl || defaultLogo" alt="logo" />
|
|
10
|
-
</NuxtLink>
|
|
11
|
-
<div class="position-relative search-style-two">
|
|
12
|
-
<input
|
|
13
|
-
type="text"
|
|
14
|
-
class="form-control border-2"
|
|
15
|
-
:placeholder="t('nav.searchProducts')"
|
|
16
|
-
v-model="searchQuery"
|
|
17
|
-
@keyup.enter="handleSearch"
|
|
18
|
-
/>
|
|
19
|
-
<button
|
|
20
|
-
type="submit"
|
|
21
|
-
class="position-absolute top-50 end-0 translate-middle-y btn btn-success fs-14 fw-medium text-white"
|
|
22
|
-
@click="handleSearch"
|
|
23
|
-
>
|
|
24
|
-
<i class="ri-search-line"></i>
|
|
25
|
-
<span class="d-none d-sm-inline-block">{{ t('nav.search') }}</span>
|
|
26
|
-
</button>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<ul
|
|
31
|
-
class="d-flex middle-header-right ps-0 mb-0 list-unstyled justify-content-center justify-content-lg-end mt-3 mt-lg-0"
|
|
32
|
-
>
|
|
33
|
-
<li class="info" v-if="phone">
|
|
34
|
-
<a :href="`tel:${phone}`" class="text-decoration-none">
|
|
35
|
-
<div class="d-flex align-items-center">
|
|
36
|
-
<div class="flex-shrink-0">
|
|
37
|
-
<i class="ri-phone-line bg-danger-10"></i>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="flex-grow-1 ms-10">
|
|
40
|
-
<span>{{ t('nav.hotline') }}</span>
|
|
41
|
-
<h3>{{ phone }}</h3>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
</a>
|
|
45
|
-
</li>
|
|
46
|
-
<li class="buy-info position-relative tops-3">
|
|
47
|
-
<NuxtLink to="/login" class="text-decoration-none success-hover-bg">
|
|
48
|
-
<div class="d-flex align-items-center">
|
|
49
|
-
<div class="flex-shrink-0">
|
|
50
|
-
<i class="ri-user-line"></i>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</NuxtLink>
|
|
54
|
-
</li>
|
|
55
|
-
<li class="buy-info tops-4 position-relative">
|
|
56
|
-
<NuxtLink
|
|
57
|
-
to="/wishlist"
|
|
58
|
-
class="text-decoration-none success-hover-bg"
|
|
59
|
-
>
|
|
60
|
-
<div class="position-relative me-9">
|
|
61
|
-
<i class="ri-heart-line"></i>
|
|
62
|
-
<span class="count bg-success">0</span>
|
|
63
|
-
</div>
|
|
64
|
-
</NuxtLink>
|
|
65
|
-
</li>
|
|
66
|
-
<li class="buy-info">
|
|
67
|
-
<div class="dropdown">
|
|
68
|
-
<a
|
|
69
|
-
class="text-decoration-none success-hover-bg"
|
|
70
|
-
href="javascript:void(0);"
|
|
71
|
-
@click="toggleBuyInfo"
|
|
72
|
-
:aria-pressed="active ? 'true' : 'false'"
|
|
73
|
-
:class="{ active: buttonActiveState }"
|
|
74
|
-
>
|
|
75
|
-
<div class="d-flex align-items-center">
|
|
76
|
-
<div class="flex-shrink-0">
|
|
77
|
-
<div class="position-relative me-9">
|
|
78
|
-
<i class="ri-shopping-cart-line"></i>
|
|
79
|
-
<span class="count bg-success">{{ itemCount }}</span>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
</a>
|
|
84
|
-
<ul
|
|
85
|
-
class="dropdown-menu cart-dropdown dropdown-menu-end"
|
|
86
|
-
:class="{ toggler: active }"
|
|
87
|
-
>
|
|
88
|
-
<li
|
|
89
|
-
v-for="item in cart.items.slice(0, 3)"
|
|
90
|
-
:key="item.productId"
|
|
91
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
92
|
-
>
|
|
93
|
-
<button
|
|
94
|
-
class="p-0 border-0 bg-transparent delete-btn"
|
|
95
|
-
@click="removeFromCart(item.productId)"
|
|
96
|
-
>
|
|
97
|
-
<i class="ri-delete-bin-7-line"></i>
|
|
98
|
-
</button>
|
|
99
|
-
<NuxtLink
|
|
100
|
-
class="dropdown-item d-flex align-items-center"
|
|
101
|
-
:to="`/product-details?id=${item.productId}`"
|
|
102
|
-
>
|
|
103
|
-
<img
|
|
104
|
-
v-if="item.image"
|
|
105
|
-
:src="resolveImageUrl(item.image)"
|
|
106
|
-
alt="product"
|
|
107
|
-
/>
|
|
108
|
-
<div class="ms-3 d-inline-block text-truncate">
|
|
109
|
-
<span>{{ item.name }}</span>
|
|
110
|
-
<h3>${{ (item.discountPrice || item.price).toFixed(2) }}</h3>
|
|
111
|
-
</div>
|
|
112
|
-
</NuxtLink>
|
|
113
|
-
</li>
|
|
114
|
-
<li v-if="isEmpty" class="cart-item text-center text-muted py-3">
|
|
115
|
-
Cart is empty
|
|
116
|
-
</li>
|
|
117
|
-
<template v-if="!isEmpty">
|
|
118
|
-
<li
|
|
119
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
120
|
-
>
|
|
121
|
-
<h3 class="fs-15 mb-0">Total</h3>
|
|
122
|
-
<h3 class="fs-15 mb-0">${{ subtotal.toFixed(2) }}</h3>
|
|
123
|
-
</li>
|
|
124
|
-
<li
|
|
125
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
126
|
-
>
|
|
127
|
-
<NuxtLink to="/cart" class="btn btn-primary fs-14 text-white">
|
|
128
|
-
{{ t('account.viewCart') }}
|
|
129
|
-
</NuxtLink>
|
|
130
|
-
<NuxtLink
|
|
131
|
-
to="/checkout"
|
|
132
|
-
class="btn btn-warning fs-14 text-white"
|
|
133
|
-
>
|
|
134
|
-
{{ t('account.checkout') }}
|
|
135
|
-
</NuxtLink>
|
|
136
|
-
</li>
|
|
137
|
-
</template>
|
|
138
|
-
</ul>
|
|
139
|
-
</div>
|
|
140
|
-
</li>
|
|
141
|
-
</ul>
|
|
142
|
-
</div>
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
2
|
+
<LayoutHeaderBar :with-categories="false" btn-class="btn-success" area-class="border-bottom" logo-class="style-two" search-class="search-style-two" />
|
|
145
3
|
</template>
|
|
146
|
-
|
|
147
|
-
<script lang="ts">
|
|
148
|
-
import { defineComponent, ref, computed } from "vue";
|
|
149
|
-
|
|
150
|
-
import defaultLogoImg from "~/assets/images/grocery-shop-logo.png";
|
|
151
|
-
|
|
152
|
-
export default defineComponent({
|
|
153
|
-
name: "MiddleHeaderThree",
|
|
154
|
-
setup() {
|
|
155
|
-
const active = ref(false);
|
|
156
|
-
const buttonActiveState = ref(false);
|
|
157
|
-
const searchQuery = ref("");
|
|
158
|
-
const defaultLogo = defaultLogoImg;
|
|
159
|
-
const router = useRouter();
|
|
160
|
-
|
|
161
|
-
const { t } = useI18n();
|
|
162
|
-
const { logoUrl, contactInfo } = useSiteConfig();
|
|
163
|
-
const { cart, itemCount, subtotal, isEmpty, removeFromCart } = useCart();
|
|
164
|
-
|
|
165
|
-
const phone = computed(() => contactInfo.value?.phone);
|
|
166
|
-
|
|
167
|
-
const resolveImageUrl = (url: string) => {
|
|
168
|
-
if (!url) return '';
|
|
169
|
-
if (url.startsWith('http')) return url;
|
|
170
|
-
const apiBase = getApiBaseUrl();
|
|
171
|
-
const baseUrl = apiBase.replace('/api', '');
|
|
172
|
-
return `${baseUrl}${url}`;
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
const toggleBuyInfo = () => {
|
|
176
|
-
active.value = !active.value;
|
|
177
|
-
buttonActiveState.value = !buttonActiveState.value;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const handleSearch = () => {
|
|
181
|
-
if (searchQuery.value.trim()) {
|
|
182
|
-
router.push(`/products?search=${encodeURIComponent(searchQuery.value.trim())}`);
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
active,
|
|
188
|
-
buttonActiveState,
|
|
189
|
-
toggleBuyInfo,
|
|
190
|
-
searchQuery,
|
|
191
|
-
handleSearch,
|
|
192
|
-
defaultLogo,
|
|
193
|
-
logoUrl,
|
|
194
|
-
phone,
|
|
195
|
-
cart,
|
|
196
|
-
itemCount,
|
|
197
|
-
subtotal,
|
|
198
|
-
isEmpty,
|
|
199
|
-
removeFromCart,
|
|
200
|
-
resolveImageUrl,
|
|
201
|
-
t,
|
|
202
|
-
};
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
</script>
|
|
@@ -1,241 +1,3 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<div class="container">
|
|
4
|
-
<div class="d-lg-flex justify-content-between align-items-center">
|
|
5
|
-
<div
|
|
6
|
-
class="d-flex align-items-center middle-header-left justify-content-center justify-content-lg-end"
|
|
7
|
-
>
|
|
8
|
-
<NuxtLink to="/" class="d-none d-lg-block middle-logo">
|
|
9
|
-
<img :src="logoUrl || defaultLogo" alt="logo" />
|
|
10
|
-
</NuxtLink>
|
|
11
|
-
<div class="d-flex">
|
|
12
|
-
<div class="dropdown">
|
|
13
|
-
<button
|
|
14
|
-
class="dropdown-toggle border border-2 bg-transparent all-categories"
|
|
15
|
-
@click="toggleAllCategories"
|
|
16
|
-
:aria-pressed="show ? 'true' : 'false'"
|
|
17
|
-
:class="{ show: buttonShowState }"
|
|
18
|
-
>
|
|
19
|
-
{{ t('nav.allCategories') }}
|
|
20
|
-
</button>
|
|
21
|
-
<ul class="dropdown-menu" :class="{ toggler: show }">
|
|
22
|
-
<li v-for="category in topLevelCategories" :key="category.id">
|
|
23
|
-
<NuxtLink
|
|
24
|
-
class="dropdown-item"
|
|
25
|
-
:to="`/products?categoryId=${category.id}`"
|
|
26
|
-
>
|
|
27
|
-
{{ category.name }}
|
|
28
|
-
</NuxtLink>
|
|
29
|
-
</li>
|
|
30
|
-
<li v-if="topLevelCategories.length === 0">
|
|
31
|
-
<span class="dropdown-item text-muted">{{ t('nav.noCategories') }}</span>
|
|
32
|
-
</li>
|
|
33
|
-
</ul>
|
|
34
|
-
</div>
|
|
35
|
-
<div class="position-relative">
|
|
36
|
-
<input
|
|
37
|
-
type="text"
|
|
38
|
-
class="form-control border-2"
|
|
39
|
-
:placeholder="t('nav.searchProducts')"
|
|
40
|
-
v-model="searchQuery"
|
|
41
|
-
@keyup.enter="handleSearch"
|
|
42
|
-
/>
|
|
43
|
-
<button
|
|
44
|
-
type="submit"
|
|
45
|
-
class="position-absolute top-50 end-0 translate-middle-y btn btn-warning fs-14 fw-medium text-white"
|
|
46
|
-
@click="handleSearch"
|
|
47
|
-
>
|
|
48
|
-
<i class="ri-search-line"></i>
|
|
49
|
-
<span class="d-none d-sm-inline-block">{{ t('nav.search') }}</span>
|
|
50
|
-
</button>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<ul
|
|
56
|
-
class="d-flex middle-header-right ps-0 mb-0 list-unstyled justify-content-center justify-content-lg-end mt-3 mt-lg-0"
|
|
57
|
-
>
|
|
58
|
-
<li class="info" v-if="phone">
|
|
59
|
-
<a :href="`tel:${phone}`" class="text-decoration-none">
|
|
60
|
-
<div class="d-flex align-items-center">
|
|
61
|
-
<div class="flex-shrink-0">
|
|
62
|
-
<i class="ri-phone-line bg-danger-10"></i>
|
|
63
|
-
</div>
|
|
64
|
-
<div class="flex-grow-1 ms-10">
|
|
65
|
-
<span>{{ t('nav.hotline') }}</span>
|
|
66
|
-
<h3>{{ phone }}</h3>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
</a>
|
|
70
|
-
</li>
|
|
71
|
-
<li class="buy-info position-relative tops-3">
|
|
72
|
-
<NuxtLink to="/login" class="text-decoration-none success-hover-bg">
|
|
73
|
-
<div class="d-flex align-items-center">
|
|
74
|
-
<div class="flex-shrink-0">
|
|
75
|
-
<i class="ri-user-line"></i>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
</NuxtLink>
|
|
79
|
-
</li>
|
|
80
|
-
<li class="buy-info tops-4 position-relative">
|
|
81
|
-
<NuxtLink
|
|
82
|
-
to="/wishlist"
|
|
83
|
-
class="text-decoration-none success-hover-bg"
|
|
84
|
-
>
|
|
85
|
-
<div class="position-relative me-9">
|
|
86
|
-
<i class="ri-heart-line"></i>
|
|
87
|
-
<span class="count bg-success">0</span>
|
|
88
|
-
</div>
|
|
89
|
-
</NuxtLink>
|
|
90
|
-
</li>
|
|
91
|
-
<li class="buy-info">
|
|
92
|
-
<div class="dropdown">
|
|
93
|
-
<a
|
|
94
|
-
class="text-decoration-none success-hover-bg"
|
|
95
|
-
href="javascript:void(0);"
|
|
96
|
-
@click="toggleBuyInfo"
|
|
97
|
-
:aria-pressed="active ? 'true' : 'false'"
|
|
98
|
-
:class="{ active: buttonActiveState }"
|
|
99
|
-
>
|
|
100
|
-
<div class="d-flex align-items-center">
|
|
101
|
-
<div class="flex-shrink-0">
|
|
102
|
-
<div class="position-relative me-9">
|
|
103
|
-
<i class="ri-shopping-cart-line"></i>
|
|
104
|
-
<span class="count bg-success">{{ itemCount }}</span>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
</a>
|
|
109
|
-
<ul
|
|
110
|
-
class="dropdown-menu cart-dropdown dropdown-menu-end"
|
|
111
|
-
:class="{ toggler: active }"
|
|
112
|
-
>
|
|
113
|
-
<li
|
|
114
|
-
v-for="item in cart.items.slice(0, 3)"
|
|
115
|
-
:key="item.productId"
|
|
116
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
117
|
-
>
|
|
118
|
-
<button
|
|
119
|
-
class="p-0 border-0 bg-transparent delete-btn"
|
|
120
|
-
@click="removeFromCart(item.productId)"
|
|
121
|
-
>
|
|
122
|
-
<i class="ri-delete-bin-7-line"></i>
|
|
123
|
-
</button>
|
|
124
|
-
<NuxtLink
|
|
125
|
-
class="dropdown-item d-flex align-items-center"
|
|
126
|
-
:to="`/product-details?id=${item.productId}`"
|
|
127
|
-
>
|
|
128
|
-
<img
|
|
129
|
-
v-if="item.image"
|
|
130
|
-
:src="resolveImageUrl(item.image)"
|
|
131
|
-
alt="product"
|
|
132
|
-
/>
|
|
133
|
-
<div class="ms-3 d-inline-block text-truncate">
|
|
134
|
-
<span>{{ item.name }}</span>
|
|
135
|
-
<h3>${{ (item.discountPrice || item.price).toFixed(2) }}</h3>
|
|
136
|
-
</div>
|
|
137
|
-
</NuxtLink>
|
|
138
|
-
</li>
|
|
139
|
-
<li v-if="isEmpty" class="cart-item text-center text-muted py-3">
|
|
140
|
-
Cart is empty
|
|
141
|
-
</li>
|
|
142
|
-
<template v-if="!isEmpty">
|
|
143
|
-
<li
|
|
144
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
145
|
-
>
|
|
146
|
-
<h3 class="fs-15 mb-0">Total</h3>
|
|
147
|
-
<h3 class="fs-15 mb-0">${{ subtotal.toFixed(2) }}</h3>
|
|
148
|
-
</li>
|
|
149
|
-
<li
|
|
150
|
-
class="d-flex justify-content-between align-items-center cart-item"
|
|
151
|
-
>
|
|
152
|
-
<NuxtLink to="/cart" class="btn btn-primary fs-14 text-white">
|
|
153
|
-
{{ t('account.viewCart') }}
|
|
154
|
-
</NuxtLink>
|
|
155
|
-
<NuxtLink
|
|
156
|
-
to="/checkout"
|
|
157
|
-
class="btn btn-warning fs-14 text-white"
|
|
158
|
-
>
|
|
159
|
-
{{ t('account.checkout') }}
|
|
160
|
-
</NuxtLink>
|
|
161
|
-
</li>
|
|
162
|
-
</template>
|
|
163
|
-
</ul>
|
|
164
|
-
</div>
|
|
165
|
-
</li>
|
|
166
|
-
</ul>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
2
|
+
<LayoutHeaderBar btn-class="btn-warning" />
|
|
170
3
|
</template>
|
|
171
|
-
|
|
172
|
-
<script lang="ts">
|
|
173
|
-
import { defineComponent, ref, computed } from "vue";
|
|
174
|
-
|
|
175
|
-
import defaultLogoImg from "~/assets/images/grocery-shop-logo.png";
|
|
176
|
-
|
|
177
|
-
export default defineComponent({
|
|
178
|
-
name: "MiddleHeaderTwo",
|
|
179
|
-
setup() {
|
|
180
|
-
const show = ref(false);
|
|
181
|
-
const buttonShowState = ref(false);
|
|
182
|
-
const active = ref(false);
|
|
183
|
-
const buttonActiveState = ref(false);
|
|
184
|
-
const searchQuery = ref("");
|
|
185
|
-
const defaultLogo = defaultLogoImg;
|
|
186
|
-
const router = useRouter();
|
|
187
|
-
|
|
188
|
-
const { t } = useI18n();
|
|
189
|
-
const { topLevelCategories } = useCategories();
|
|
190
|
-
const { logoUrl, contactInfo } = useSiteConfig();
|
|
191
|
-
const { cart, itemCount, subtotal, isEmpty, removeFromCart } = useCart();
|
|
192
|
-
|
|
193
|
-
const phone = computed(() => contactInfo.value?.phone);
|
|
194
|
-
|
|
195
|
-
const resolveImageUrl = (url: string) => {
|
|
196
|
-
if (!url) return '';
|
|
197
|
-
if (url.startsWith('http')) return url;
|
|
198
|
-
const apiBase = getApiBaseUrl();
|
|
199
|
-
const baseUrl = apiBase.replace('/api', '');
|
|
200
|
-
return `${baseUrl}${url}`;
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
const toggleAllCategories = () => {
|
|
204
|
-
show.value = !show.value;
|
|
205
|
-
buttonShowState.value = !buttonShowState.value;
|
|
206
|
-
};
|
|
207
|
-
const toggleBuyInfo = () => {
|
|
208
|
-
active.value = !active.value;
|
|
209
|
-
buttonActiveState.value = !buttonActiveState.value;
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
const handleSearch = () => {
|
|
213
|
-
if (searchQuery.value.trim()) {
|
|
214
|
-
router.push(`/products?search=${encodeURIComponent(searchQuery.value.trim())}`);
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
show,
|
|
220
|
-
buttonShowState,
|
|
221
|
-
active,
|
|
222
|
-
buttonActiveState,
|
|
223
|
-
toggleAllCategories,
|
|
224
|
-
toggleBuyInfo,
|
|
225
|
-
searchQuery,
|
|
226
|
-
handleSearch,
|
|
227
|
-
defaultLogo,
|
|
228
|
-
topLevelCategories,
|
|
229
|
-
logoUrl,
|
|
230
|
-
phone,
|
|
231
|
-
cart,
|
|
232
|
-
itemCount,
|
|
233
|
-
subtotal,
|
|
234
|
-
isEmpty,
|
|
235
|
-
removeFromCart,
|
|
236
|
-
resolveImageUrl,
|
|
237
|
-
t,
|
|
238
|
-
};
|
|
239
|
-
},
|
|
240
|
-
});
|
|
241
|
-
</script>
|