@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.
Files changed (139) hide show
  1. package/assets/scss/_variables.scss +3 -3
  2. package/assets/scss/components/_header.scss +1 -1
  3. package/assets/scss/style.css +4 -4
  4. package/components/AboutUs/StaticContent.vue +32 -0
  5. package/components/Cart/CartEmpty.vue +42 -0
  6. package/components/Cart/CartItem.vue +145 -0
  7. package/components/Cart/CartSummary.vue +57 -0
  8. package/components/Cart/ProductQuantity.vue +23 -13
  9. package/components/Cart/index.vue +68 -150
  10. package/components/Categories/index.vue +88 -291
  11. package/components/Checkout/AddressFields.vue +74 -0
  12. package/components/Checkout/CheckoutForm.vue +75 -0
  13. package/components/Checkout/CityAutocomplete.vue +68 -0
  14. package/components/Checkout/DeliveryMethodCard.vue +66 -0
  15. package/components/Checkout/DeliveryOptions.vue +148 -0
  16. package/components/Checkout/OrderSummary.vue +116 -0
  17. package/components/Checkout/PaymentOptions.vue +76 -0
  18. package/components/Checkout/PickupPoints.vue +46 -0
  19. package/components/Checkout/PromoCode.vue +166 -0
  20. package/components/Checkout/index.vue +235 -173
  21. package/components/Checkout/types.ts +45 -0
  22. package/components/Common/PageBanner.vue +22 -20
  23. package/components/Common/ProductCard.vue +139 -115
  24. package/components/Common/Services.vue +4 -4
  25. package/components/Contact/ContactForm.vue +44 -74
  26. package/components/Contact/ContactInfo.vue +35 -61
  27. package/components/FAQ/index.vue +6 -119
  28. package/components/Layout/Copyright.vue +11 -9
  29. package/components/Layout/Footer.vue +49 -136
  30. package/components/Layout/HeaderBar.vue +174 -0
  31. package/components/Layout/HeaderLogo.vue +27 -0
  32. package/components/Layout/MiddleHeader.vue +1 -228
  33. package/components/Layout/MiddleHeaderThree.vue +1 -203
  34. package/components/Layout/MiddleHeaderTwo.vue +1 -239
  35. package/components/Layout/NavLinks.vue +23 -0
  36. package/components/Layout/Navbar.vue +38 -151
  37. package/components/Layout/NavbarStyleFour.vue +1 -332
  38. package/components/Layout/NavbarStyleThree.vue +1 -188
  39. package/components/Layout/NavbarStyleTwo.vue +1 -108
  40. package/components/Layout/Preloader.vue +5 -12
  41. package/components/Layout/ResponsiveNavbar.vue +32 -418
  42. package/components/Layout/SitewideBanner.vue +285 -0
  43. package/components/Layout/TopHeader.vue +17 -83
  44. package/components/Layout/layoutData.ts +83 -0
  45. package/components/PrivacyPolicy/index.vue +6 -110
  46. package/components/ProductDetails/ProductDetailsTab.vue +31 -321
  47. package/components/ProductDetails/ProductGallery.vue +45 -0
  48. package/components/ProductDetails/ProductQuantity.vue +8 -14
  49. package/components/ProductDetails/RecentlyViewed.vue +53 -289
  50. package/components/ProductDetails/RelatedProducts.vue +64 -0
  51. package/components/ProductDetails/index.vue +90 -230
  52. package/components/Products/index.vue +78 -16
  53. package/components/TermsConditions/index.vue +6 -110
  54. package/components/Wishlist/index.vue +62 -88
  55. package/composables/useCart.ts +133 -81
  56. package/composables/useCategories.ts +67 -31
  57. package/composables/useCategoryImages.ts +45 -0
  58. package/composables/useCheckout.ts +302 -97
  59. package/composables/useContactForm.ts +57 -0
  60. package/composables/useHomeContent.ts +220 -0
  61. package/composables/useI18n.ts +12 -24
  62. package/composables/useJsonLd.ts +162 -0
  63. package/composables/useProducts.ts +244 -83
  64. package/composables/useRecent.ts +30 -0
  65. package/composables/useSanitize.ts +76 -0
  66. package/composables/useSiteConfig.ts +51 -47
  67. package/composables/useStaticPages.ts +48 -0
  68. package/composables/useStoreOrigin.ts +32 -0
  69. package/composables/useTemplateSections.ts +51 -3
  70. package/composables/useThemeVars.ts +113 -0
  71. package/composables/useWishlist.ts +72 -0
  72. package/layouts/default.vue +80 -19
  73. package/locales/en.json +255 -86
  74. package/locales/uk.json +251 -82
  75. package/modules/template-schema.ts +35 -0
  76. package/nuxt.config.ts +8 -11
  77. package/package.json +1 -1
  78. package/pages/about-us.vue +9 -9
  79. package/pages/cart.vue +0 -1
  80. package/pages/categories.vue +0 -1
  81. package/pages/category/[slug].vue +84 -0
  82. package/pages/checkout.vue +0 -1
  83. package/pages/contact.vue +6 -6
  84. package/pages/delivery.vue +12 -0
  85. package/pages/faq.vue +6 -6
  86. package/pages/order-success.vue +113 -0
  87. package/pages/privacy-policy.vue +6 -6
  88. package/pages/product/[slug].vue +82 -0
  89. package/pages/product-details.vue +14 -6
  90. package/pages/products.vue +12 -1
  91. package/pages/returns.vue +12 -0
  92. package/pages/terms-conditions.vue +6 -6
  93. package/pages/wishlist.vue +2 -2
  94. package/utils/image.ts +0 -1
  95. package/utils/seo-urls.ts +70 -0
  96. package/utils/store-origin.ts +36 -0
  97. package/components/AboutUs/AboutUsTuan.vue +0 -25
  98. package/components/AboutUs/Statistics.vue +0 -42
  99. package/components/AboutUs/SubscribeToTheNewsletter.vue +0 -57
  100. package/components/AddAddress/index.vue +0 -68
  101. package/components/BestSellers/Products.vue +0 -1562
  102. package/components/BestSellers/RecentlyViewed.vue +0 -304
  103. package/components/ChangePassword/index.vue +0 -69
  104. package/components/Common/DashboardNavigation.vue +0 -35
  105. package/components/Dashboard/RecentOrder.vue +0 -173
  106. package/components/Dashboard/index.vue +0 -77
  107. package/components/EditAddress/index.vue +0 -117
  108. package/components/EditProfile/index.vue +0 -95
  109. package/components/FeaturedProduct/FeaturedProducts.vue +0 -304
  110. package/components/FeaturedProduct/Products.vue +0 -1562
  111. package/components/ForgotPassword/index.vue +0 -49
  112. package/components/Layout/FooterTwo.vue +0 -159
  113. package/components/Layout/LocationOption.vue +0 -178
  114. package/components/Layout/RTLSwitchBtn.vue +0 -40
  115. package/components/Login/index.vue +0 -89
  116. package/components/MyAccount/index.vue +0 -154
  117. package/components/NewArrivals/Products.vue +0 -1969
  118. package/components/NewArrivals/RecentlyViewed.vue +0 -304
  119. package/components/OrderDetails/index.vue +0 -75
  120. package/components/OrderHistory/index.vue +0 -195
  121. package/components/Products/RecentlyViewed.vue +0 -302
  122. package/components/Register/index.vue +0 -83
  123. package/components/TrendingProducts/FeaturedProducts.vue +0 -304
  124. package/components/TrendingProducts/Products.vue +0 -1564
  125. package/components/Wishlist/ProductQuantity.vue +0 -29
  126. package/layouts/inner.vue +0 -70
  127. package/locales/ar.json +0 -234
  128. package/locales/ru.json +0 -234
  129. package/pages/address.vue +0 -11
  130. package/pages/change-password.vue +0 -11
  131. package/pages/dashboard.vue +0 -11
  132. package/pages/edit-address.vue +0 -11
  133. package/pages/edit-profile.vue +0 -11
  134. package/pages/forgot-password.vue +0 -11
  135. package/pages/login.vue +0 -11
  136. package/pages/my-account.vue +0 -11
  137. package/pages/order-details.vue +0 -11
  138. package/pages/order-history.vue +0 -11
  139. package/pages/register.vue +0 -11
@@ -1,230 +1,3 @@
1
1
  <template>
2
- <div class="middle-header-area ptb-20">
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
- <div class="middle-header-area border-bottom ptb-20">
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
- <div class="middle-header-area ptb-20">
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>