@o2vend/theme-cli 1.0.32
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/README.md +425 -0
- package/assets/Logo_o2vend.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/logo-white.png +0 -0
- package/bin/o2vend +42 -0
- package/config/widget-map.json +50 -0
- package/lib/commands/check.js +201 -0
- package/lib/commands/generate.js +33 -0
- package/lib/commands/init.js +214 -0
- package/lib/commands/optimize.js +216 -0
- package/lib/commands/package.js +208 -0
- package/lib/commands/serve.js +105 -0
- package/lib/commands/validate.js +191 -0
- package/lib/lib/api-client.js +357 -0
- package/lib/lib/dev-server.js +2618 -0
- package/lib/lib/file-watcher.js +80 -0
- package/lib/lib/hot-reload.js +106 -0
- package/lib/lib/liquid-engine.js +822 -0
- package/lib/lib/liquid-filters.js +671 -0
- package/lib/lib/mock-api-server.js +989 -0
- package/lib/lib/mock-data.js +1468 -0
- package/lib/lib/widget-service.js +321 -0
- package/package.json +70 -0
- package/test-theme/README.md +27 -0
- package/test-theme/assets/async-sections.js +446 -0
- package/test-theme/assets/cart-drawer.js +463 -0
- package/test-theme/assets/cart-manager.js +223 -0
- package/test-theme/assets/checkout-price-handler.js +368 -0
- package/test-theme/assets/components.css +4629 -0
- package/test-theme/assets/delivery-zone.css +299 -0
- package/test-theme/assets/delivery-zone.js +396 -0
- package/test-theme/assets/logo.png +0 -0
- package/test-theme/assets/sections.css +48 -0
- package/test-theme/assets/theme.css +3500 -0
- package/test-theme/assets/theme.js +3745 -0
- package/test-theme/config/settings_data.json +292 -0
- package/test-theme/config/settings_schema.json +1050 -0
- package/test-theme/layout/theme.liquid +195 -0
- package/test-theme/locales/en.default.json +260 -0
- package/test-theme/sections/content-fallback.liquid +53 -0
- package/test-theme/sections/content.liquid +57 -0
- package/test-theme/sections/footer-fallback.liquid +328 -0
- package/test-theme/sections/footer.liquid +278 -0
- package/test-theme/sections/header-fallback.liquid +1805 -0
- package/test-theme/sections/header.liquid +1145 -0
- package/test-theme/sections/hero-fallback.liquid +212 -0
- package/test-theme/sections/hero.liquid +136 -0
- package/test-theme/snippets/account-sidebar.liquid +200 -0
- package/test-theme/snippets/add-to-cart-modal.liquid +484 -0
- package/test-theme/snippets/breadcrumbs.liquid +134 -0
- package/test-theme/snippets/cart-drawer.liquid +467 -0
- package/test-theme/snippets/delivery-zone-city-selector.liquid +79 -0
- package/test-theme/snippets/delivery-zone-modal.liquid +337 -0
- package/test-theme/snippets/delivery-zone-search.liquid +78 -0
- package/test-theme/snippets/icon.liquid +105 -0
- package/test-theme/snippets/login-modal.liquid +346 -0
- package/test-theme/snippets/mega-menu.liquid +812 -0
- package/test-theme/snippets/news-thumbnail.liquid +187 -0
- package/test-theme/snippets/pagination.liquid +120 -0
- package/test-theme/snippets/price.liquid +92 -0
- package/test-theme/snippets/product-card-related.liquid +78 -0
- package/test-theme/snippets/product-card-simple.liquid +41 -0
- package/test-theme/snippets/product-card.liquid +697 -0
- package/test-theme/snippets/rating.liquid +85 -0
- package/test-theme/snippets/skeleton-collection-grid.liquid +114 -0
- package/test-theme/snippets/skeleton-product-card.liquid +124 -0
- package/test-theme/snippets/skeleton-product-grid.liquid +34 -0
- package/test-theme/snippets/social-sharing.liquid +185 -0
- package/test-theme/templates/account/dashboard.liquid +401 -0
- package/test-theme/templates/account/loyalty-redemption.liquid +405 -0
- package/test-theme/templates/account/loyalty.liquid +588 -0
- package/test-theme/templates/account/order-detail.liquid +230 -0
- package/test-theme/templates/account/orders.liquid +349 -0
- package/test-theme/templates/account/profile.liquid +758 -0
- package/test-theme/templates/account/register.liquid +232 -0
- package/test-theme/templates/account/return-orders.liquid +348 -0
- package/test-theme/templates/account/store-credit.liquid +464 -0
- package/test-theme/templates/account/subscriptions.liquid +601 -0
- package/test-theme/templates/account/wishlist.liquid +419 -0
- package/test-theme/templates/address-book.liquid +1092 -0
- package/test-theme/templates/categories.liquid +452 -0
- package/test-theme/templates/checkout.liquid +4511 -0
- package/test-theme/templates/error.liquid +384 -0
- package/test-theme/templates/index.liquid +11 -0
- package/test-theme/templates/login.liquid +185 -0
- package/test-theme/templates/order-confirmation.liquid +720 -0
- package/test-theme/templates/page.liquid +297 -0
- package/test-theme/templates/product-detail.liquid +4363 -0
- package/test-theme/templates/products.liquid +518 -0
- package/test-theme/templates/search.liquid +922 -0
- package/test-theme/theme.json.example +19 -0
- package/test-theme/widgets/brand-carousel.liquid +676 -0
- package/test-theme/widgets/brand.liquid +245 -0
- package/test-theme/widgets/carousel.liquid +843 -0
- package/test-theme/widgets/category-list-carousel.liquid +656 -0
- package/test-theme/widgets/category-list.liquid +340 -0
- package/test-theme/widgets/category.liquid +475 -0
- package/test-theme/widgets/discount-time.liquid +176 -0
- package/test-theme/widgets/footer-menu.liquid +695 -0
- package/test-theme/widgets/footer.liquid +179 -0
- package/test-theme/widgets/gallery.liquid +271 -0
- package/test-theme/widgets/header-menu.liquid +932 -0
- package/test-theme/widgets/header.liquid +159 -0
- package/test-theme/widgets/html.liquid +214 -0
- package/test-theme/widgets/news.liquid +217 -0
- package/test-theme/widgets/product-canvas.liquid +235 -0
- package/test-theme/widgets/product-carousel.liquid +502 -0
- package/test-theme/widgets/product.liquid +45 -0
- package/test-theme/widgets/recently-viewed.liquid +26 -0
- package/test-theme/widgets/shared/product-grid.liquid +339 -0
- package/test-theme/widgets/simple-product.liquid +42 -0
- package/test-theme/widgets/single-product.liquid +610 -0
- package/test-theme/widgets/spacebar-carousel.liquid +663 -0
- package/test-theme/widgets/spacebar.liquid +279 -0
- package/test-theme/widgets/splash.liquid +378 -0
- package/test-theme/widgets/testimonial-carousel.liquid +709 -0
|
@@ -0,0 +1,1145 @@
|
|
|
1
|
+
{% comment %}
|
|
2
|
+
Header Section - Fixed Layout Issues
|
|
3
|
+
|
|
4
|
+
Key fixes:
|
|
5
|
+
1. Hamburger menu now properly visible on mobile
|
|
6
|
+
2. Improved responsive layout
|
|
7
|
+
3. Better cart button styling
|
|
8
|
+
4. Fixed search bar positioning
|
|
9
|
+
5. Proper mobile/desktop breakpoints
|
|
10
|
+
{% endcomment %}
|
|
11
|
+
|
|
12
|
+
{% assign header_widgets = widgets.header %}
|
|
13
|
+
{% assign header_menu_widget = null %}
|
|
14
|
+
{% if header_widgets and header_widgets.size > 0 %}
|
|
15
|
+
{% for widget in header_widgets %}
|
|
16
|
+
{% assign widget_type = widget.type | default: '' | strip %}
|
|
17
|
+
{% if widget_type == 'HeaderMenu' %}
|
|
18
|
+
{% assign header_menu_widget = widget %}
|
|
19
|
+
{% break %}
|
|
20
|
+
{% endif %}
|
|
21
|
+
{% endfor %}
|
|
22
|
+
{% endif %}
|
|
23
|
+
|
|
24
|
+
{% liquid
|
|
25
|
+
assign widget_settings = header_menu_widget.settings | default: section.settings
|
|
26
|
+
assign widget_data = header_menu_widget.data | default: null
|
|
27
|
+
|
|
28
|
+
assign content_data = widget_data.content | default: null
|
|
29
|
+
if content_data and content_data.size > 0
|
|
30
|
+
assign header_config = content_data.first
|
|
31
|
+
else
|
|
32
|
+
assign header_config = content_data
|
|
33
|
+
endif
|
|
34
|
+
|
|
35
|
+
assign logo_url = nil
|
|
36
|
+
if widget_settings.logo and widget_settings.logo != blank
|
|
37
|
+
assign logo_url = widget_settings.logo
|
|
38
|
+
elsif shop.logo and shop.logo != blank
|
|
39
|
+
assign logo_url = shop.logo
|
|
40
|
+
else
|
|
41
|
+
assign logo_url = '/themes/default/assets/logo.png'
|
|
42
|
+
endif
|
|
43
|
+
assign logo_alt = widget_settings.logoAlt | default: shop.name
|
|
44
|
+
assign logo_link = widget_settings.logoLink | default: '/'
|
|
45
|
+
|
|
46
|
+
assign show_search = widget_settings.showSearch
|
|
47
|
+
if show_search == nil and header_config and header_config.ShowSearch != nil
|
|
48
|
+
assign show_search = header_config.ShowSearch
|
|
49
|
+
endif
|
|
50
|
+
if show_search == nil
|
|
51
|
+
assign show_search = true
|
|
52
|
+
endif
|
|
53
|
+
|
|
54
|
+
assign show_cart = widget_settings.showCart
|
|
55
|
+
if show_cart == nil and header_config and header_config.ShowCart != nil
|
|
56
|
+
assign show_cart = header_config.ShowCart
|
|
57
|
+
endif
|
|
58
|
+
if show_cart == nil
|
|
59
|
+
assign show_cart = true
|
|
60
|
+
endif
|
|
61
|
+
|
|
62
|
+
assign show_account = widget_settings.showAccount
|
|
63
|
+
if show_account == nil and header_config and header_config.ShowAccount != nil
|
|
64
|
+
assign show_account = header_config.ShowAccount
|
|
65
|
+
endif
|
|
66
|
+
if show_account == nil
|
|
67
|
+
assign show_account = true
|
|
68
|
+
endif
|
|
69
|
+
%}
|
|
70
|
+
|
|
71
|
+
<header class="site-header" data-section-id="{{ section.id }}">
|
|
72
|
+
<div class="site-header__container">
|
|
73
|
+
{% comment %}HeaderWidget widgets (announcement bar, etc.){% endcomment %}
|
|
74
|
+
{% if header_widgets and header_widgets.size > 0 %}
|
|
75
|
+
{% for widget in header_widgets %}
|
|
76
|
+
{% assign widget_type = widget.type | default: '' | downcase %}
|
|
77
|
+
{% assign widget_type_normalized = widget_type | strip %}
|
|
78
|
+
{% if widget_type_normalized == 'headerwidget' or widget_type_normalized == 'header' %}
|
|
79
|
+
<div class="theme-widget-wrapper theme-widget-wrapper--header-widget"
|
|
80
|
+
data-widget-id="{{ widget.id }}"
|
|
81
|
+
data-widget-type="{{ widget.type }}"
|
|
82
|
+
data-widget-position="{{ widget.Position | default: widget.position | default: forloop.index }}">
|
|
83
|
+
{% if widget and widget.template_path %}
|
|
84
|
+
{% render widget.template_path, widget: widget, settings: settings %}
|
|
85
|
+
{% else %}
|
|
86
|
+
<div class="widget-error" data-widget-error>
|
|
87
|
+
<p>Widget template not found: {{ widget.template_path | default: 'unknown' }}</p>
|
|
88
|
+
</div>
|
|
89
|
+
{% endif %}
|
|
90
|
+
</div>
|
|
91
|
+
{% endif %}
|
|
92
|
+
{% endfor %}
|
|
93
|
+
{% endif %}
|
|
94
|
+
|
|
95
|
+
{% comment %}Top Row: Logo, Search, Account/Cart{% endcomment %}
|
|
96
|
+
<div class="site-header__top-row">
|
|
97
|
+
{% comment %}Hamburger Menu - Mobile Only{% endcomment %}
|
|
98
|
+
<button class="site-header__toggle" aria-label="Toggle navigation" data-header-menu-toggle type="button">
|
|
99
|
+
<span></span>
|
|
100
|
+
<span></span>
|
|
101
|
+
<span></span>
|
|
102
|
+
</button>
|
|
103
|
+
|
|
104
|
+
<div class="site-header__logo">
|
|
105
|
+
<a href="{{ logo_link }}" aria-label="{{ logo_alt }}">
|
|
106
|
+
{% if logo_url %}
|
|
107
|
+
<img src="{{ logo_url }}" alt="{{ logo_alt }}" width="200" height="28" class="site-header__logo-image">
|
|
108
|
+
{% else %}
|
|
109
|
+
<span class="site-header__brand">{{ shop.name }}</span>
|
|
110
|
+
{% endif %}
|
|
111
|
+
</a>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
{% comment %}Desktop Search{% endcomment %}
|
|
115
|
+
<div class="site-header__search-wrapper">
|
|
116
|
+
{% if show_search %}
|
|
117
|
+
<div class="site-header__search-container" data-search-container>
|
|
118
|
+
<form class="site-header__search-form" action="/search" method="get" role="search">
|
|
119
|
+
<div class="site-header__search-input-wrapper">
|
|
120
|
+
<svg class="site-header__search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
121
|
+
<circle cx="11" cy="11" r="8"></circle>
|
|
122
|
+
<path d="m21 21-4.35-4.35"></path>
|
|
123
|
+
</svg>
|
|
124
|
+
<input
|
|
125
|
+
type="search"
|
|
126
|
+
name="q"
|
|
127
|
+
class="site-header__search-input"
|
|
128
|
+
placeholder="{{ widget_settings.search_placeholder | default: 'Search for...' }}"
|
|
129
|
+
aria-label="Search products"
|
|
130
|
+
autocomplete="off"
|
|
131
|
+
data-search-input>
|
|
132
|
+
<button type="button" class="site-header__search-clear" aria-label="Clear search" data-search-clear style="display: none;">
|
|
133
|
+
<svg class="site-header__search-clear-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
134
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
135
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
136
|
+
</svg>
|
|
137
|
+
</button>
|
|
138
|
+
</div>
|
|
139
|
+
</form>
|
|
140
|
+
<div class="site-header__search-dropdown" data-search-dropdown style="display: none;">
|
|
141
|
+
<div class="site-header__search-loading" data-search-loading style="display: none;">
|
|
142
|
+
<div class="site-header__search-spinner"></div>
|
|
143
|
+
<span>Searching...</span>
|
|
144
|
+
</div>
|
|
145
|
+
<div class="site-header__search-results" data-search-results></div>
|
|
146
|
+
<div class="site-header__search-empty" data-search-empty style="display: none;">
|
|
147
|
+
<p>No products found</p>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
{% endif %}
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div class="site-header__actions">
|
|
155
|
+
{% if show_account %}
|
|
156
|
+
{% comment %}Debug: customer={{ customer | json }}{% endcomment %}
|
|
157
|
+
{% if customer and customer.isAuthenticated %}
|
|
158
|
+
<a href="/account" class="site-header__action site-header__action--account" aria-label="Account">
|
|
159
|
+
<svg class="site-header__account-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
160
|
+
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
|
161
|
+
<circle cx="12" cy="7" r="4"></circle>
|
|
162
|
+
</svg>
|
|
163
|
+
</a>
|
|
164
|
+
<form method="post" action="/webstoreapi/customer/logout" class="site-header__logout-form">
|
|
165
|
+
<button type="submit" class="site-header__action site-header__action--logout" aria-label="Logout">
|
|
166
|
+
<svg class="site-header__logout-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
167
|
+
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
|
168
|
+
<polyline points="16 17 21 12 16 7"></polyline>
|
|
169
|
+
<line x1="21" y1="12" x2="9" y2="12"></line>
|
|
170
|
+
</svg>
|
|
171
|
+
</button>
|
|
172
|
+
</form>
|
|
173
|
+
{% else %}
|
|
174
|
+
<a href="#" class="site-header__action site-header__action--login" aria-label="Login" data-login-modal-trigger>
|
|
175
|
+
<svg class="site-header__login-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
176
|
+
<circle cx="12" cy="8" r="4"></circle>
|
|
177
|
+
<path d="M6 20a6 6 0 0 1 12 0"></path>
|
|
178
|
+
</svg>
|
|
179
|
+
</a>
|
|
180
|
+
{% endif %}
|
|
181
|
+
{% endif %}
|
|
182
|
+
|
|
183
|
+
{% if show_cart %}
|
|
184
|
+
<button class="site-header__action site-header__action--cart" aria-label="Shopping cart" data-cart-toggle type="button">
|
|
185
|
+
<svg class="site-header__cart-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
186
|
+
<circle cx="9" cy="21" r="1"></circle>
|
|
187
|
+
<circle cx="20" cy="21" r="1"></circle>
|
|
188
|
+
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
|
|
189
|
+
</svg>
|
|
190
|
+
<span class="site-header__cart-text" style="display: none;"></span>
|
|
191
|
+
<span class="site-header__cart-count" data-cart-count="{% if cart.itemCount and cart.itemCount > 0 %}{{ cart.itemCount }}{% else %}0{% endif %}" {% unless cart.itemCount and cart.itemCount > 0 %}style="display: none;"{% endunless %}>{% if cart.itemCount and cart.itemCount > 0 %}{{ cart.itemCount }}{% else %}0{% endif %}</span>
|
|
192
|
+
</button>
|
|
193
|
+
{% endif %}
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
{% comment %}Mobile Search Row{% endcomment %}
|
|
198
|
+
{% if show_search %}
|
|
199
|
+
<div class="site-header__mobile-search-row">
|
|
200
|
+
<div class="site-header__mobile-search">
|
|
201
|
+
<form class="site-header__mobile-search-form" action="/search" method="get" role="search">
|
|
202
|
+
<div class="site-header__mobile-search-input-wrapper">
|
|
203
|
+
<svg class="site-header__mobile-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
204
|
+
<circle cx="11" cy="11" r="8"></circle>
|
|
205
|
+
<path d="m21 21-4.35-4.35"></path>
|
|
206
|
+
</svg>
|
|
207
|
+
<input
|
|
208
|
+
type="search"
|
|
209
|
+
name="q"
|
|
210
|
+
class="site-header__mobile-search-input"
|
|
211
|
+
placeholder="{{ widget_settings.search_placeholder | default: 'Search for...' }}"
|
|
212
|
+
aria-label="Search products"
|
|
213
|
+
autocomplete="off"
|
|
214
|
+
data-mobile-search-input>
|
|
215
|
+
</div>
|
|
216
|
+
</form>
|
|
217
|
+
<div class="site-header__mobile-search-dropdown" data-mobile-search-dropdown style="display: none;">
|
|
218
|
+
<div class="site-header__mobile-search-loading" data-mobile-search-loading style="display: none;">
|
|
219
|
+
<div class="site-header__mobile-search-spinner"></div>
|
|
220
|
+
<span>Searching...</span>
|
|
221
|
+
</div>
|
|
222
|
+
<div class="site-header__mobile-search-results" data-mobile-search-results></div>
|
|
223
|
+
<div class="site-header__mobile-search-empty" data-mobile-search-empty style="display: none;">
|
|
224
|
+
<p>No products found</p>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
{% endif %}
|
|
230
|
+
|
|
231
|
+
{% comment %}Bottom Row: Navigation Menu{% endcomment %}
|
|
232
|
+
<div class="site-header__bottom-row">
|
|
233
|
+
{% if header_menu_widget %}
|
|
234
|
+
<div class="theme-widget-wrapper theme-widget-wrapper--header-menu"
|
|
235
|
+
data-widget-id="{{ header_menu_widget.id }}"
|
|
236
|
+
data-widget-type="{{ header_menu_widget.type }}">
|
|
237
|
+
{% if header_menu_widget and header_menu_widget.template_path %}
|
|
238
|
+
{% render header_menu_widget.template_path, widget: header_menu_widget, settings: settings %}
|
|
239
|
+
{% else %}
|
|
240
|
+
<div class="widget-error">
|
|
241
|
+
<p>Widget template not found</p>
|
|
242
|
+
</div>
|
|
243
|
+
{% endif %}
|
|
244
|
+
</div>
|
|
245
|
+
{% else %}
|
|
246
|
+
{% render 'snippets/mega-menu', %}
|
|
247
|
+
{% endif %}
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
</header>
|
|
251
|
+
|
|
252
|
+
<style>
|
|
253
|
+
:root {
|
|
254
|
+
--header-bg: #ffffff;
|
|
255
|
+
--header-text: #000000;
|
|
256
|
+
--header-border: rgba(0, 0, 0, 0.1);
|
|
257
|
+
--cart-bg: #2c2c2c;
|
|
258
|
+
--cart-text: #ffffff;
|
|
259
|
+
--cart-hover: #1a1a1a;
|
|
260
|
+
--breakpoint-mobile: 768px;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Header Container */
|
|
264
|
+
.site-header {
|
|
265
|
+
background: var(--header-bg);
|
|
266
|
+
border-bottom: 1px solid var(--header-border);
|
|
267
|
+
position: sticky;
|
|
268
|
+
top: 0;
|
|
269
|
+
z-index: 1030;
|
|
270
|
+
width: 100%;
|
|
271
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.site-header__container {
|
|
275
|
+
max-width: {{ settings.container_width | default: 1200 }}px;
|
|
276
|
+
margin: 0 auto;
|
|
277
|
+
padding: 0 20px;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* Top Row Layout */
|
|
281
|
+
.site-header__top-row {
|
|
282
|
+
display: grid;
|
|
283
|
+
grid-template-columns: auto 1fr auto;
|
|
284
|
+
align-items: center;
|
|
285
|
+
gap: 20px;
|
|
286
|
+
padding: 16px 0;
|
|
287
|
+
min-height: 70px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* Hamburger Menu - Hidden on desktop, visible on mobile */
|
|
291
|
+
.site-header__toggle {
|
|
292
|
+
display: none;
|
|
293
|
+
flex-direction: column;
|
|
294
|
+
justify-content: space-between;
|
|
295
|
+
width: 24px;
|
|
296
|
+
height: 20px;
|
|
297
|
+
border: none;
|
|
298
|
+
background: transparent;
|
|
299
|
+
cursor: pointer;
|
|
300
|
+
padding: 0;
|
|
301
|
+
grid-column: 1;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.site-header__toggle span {
|
|
305
|
+
display: block;
|
|
306
|
+
width: 100%;
|
|
307
|
+
height: 2px;
|
|
308
|
+
background-color: var(--header-text);
|
|
309
|
+
transition: all 0.3s ease;
|
|
310
|
+
border-radius: 2px;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.site-header__toggle.is-open span:nth-child(1) {
|
|
314
|
+
transform: rotate(45deg) translate(6px, 6px);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.site-header__toggle.is-open span:nth-child(2) {
|
|
318
|
+
opacity: 0;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.site-header__toggle.is-open span:nth-child(3) {
|
|
322
|
+
transform: rotate(-45deg) translate(7px, -7px);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* Logo */
|
|
326
|
+
.site-header__logo {
|
|
327
|
+
grid-column: 1;
|
|
328
|
+
display: flex;
|
|
329
|
+
align-items: center;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.site-header__logo a {
|
|
333
|
+
display: flex;
|
|
334
|
+
align-items: center;
|
|
335
|
+
text-decoration: none;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.site-header__logo-image {
|
|
339
|
+
max-height: 40px;
|
|
340
|
+
width: auto;
|
|
341
|
+
display: block;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.site-header__brand {
|
|
345
|
+
font-size: 24px;
|
|
346
|
+
font-weight: 700;
|
|
347
|
+
color: var(--header-text);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* Search Wrapper - Desktop */
|
|
351
|
+
.site-header__search-wrapper {
|
|
352
|
+
grid-column: 2;
|
|
353
|
+
display: flex;
|
|
354
|
+
justify-content: center;
|
|
355
|
+
width: 100%;
|
|
356
|
+
max-width: 600px;
|
|
357
|
+
margin: 0 auto;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.site-header__search-container {
|
|
361
|
+
width: 100%;
|
|
362
|
+
position: relative;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.site-header__search-form {
|
|
366
|
+
width: 100%;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.site-header__search-input-wrapper {
|
|
370
|
+
position: relative;
|
|
371
|
+
display: flex;
|
|
372
|
+
align-items: center;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.site-header__search-icon {
|
|
376
|
+
position: absolute;
|
|
377
|
+
left: 16px;
|
|
378
|
+
width: 20px;
|
|
379
|
+
height: 20px;
|
|
380
|
+
color: rgba(0, 0, 0, 0.5);
|
|
381
|
+
pointer-events: none;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.site-header__search-input {
|
|
385
|
+
width: 100%;
|
|
386
|
+
height: 48px;
|
|
387
|
+
padding: 0 50px 0 48px;
|
|
388
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
389
|
+
border-radius: 24px;
|
|
390
|
+
font-size: 15px;
|
|
391
|
+
background: var(--header-bg);
|
|
392
|
+
transition: all 0.2s ease;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.site-header__search-input:focus {
|
|
396
|
+
outline: none;
|
|
397
|
+
border-color: var(--header-text);
|
|
398
|
+
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.site-header__search-clear {
|
|
402
|
+
position: absolute;
|
|
403
|
+
right: 12px;
|
|
404
|
+
width: 32px;
|
|
405
|
+
height: 32px;
|
|
406
|
+
display: flex;
|
|
407
|
+
align-items: center;
|
|
408
|
+
justify-content: center;
|
|
409
|
+
border: none;
|
|
410
|
+
background: transparent;
|
|
411
|
+
cursor: pointer;
|
|
412
|
+
border-radius: 50%;
|
|
413
|
+
transition: background 0.2s ease;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.site-header__search-clear:hover {
|
|
417
|
+
background: rgba(0, 0, 0, 0.05);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.site-header__search-clear-icon {
|
|
421
|
+
width: 16px;
|
|
422
|
+
height: 16px;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* Search Dropdown */
|
|
426
|
+
.site-header__search-dropdown {
|
|
427
|
+
position: absolute;
|
|
428
|
+
top: calc(100% + 8px);
|
|
429
|
+
left: 0;
|
|
430
|
+
right: 0;
|
|
431
|
+
background: white;
|
|
432
|
+
border-radius: 12px;
|
|
433
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
|
434
|
+
max-height: 400px;
|
|
435
|
+
overflow-y: auto;
|
|
436
|
+
z-index: 1000;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.site-header__search-loading {
|
|
440
|
+
display: flex;
|
|
441
|
+
align-items: center;
|
|
442
|
+
justify-content: center;
|
|
443
|
+
gap: 12px;
|
|
444
|
+
padding: 24px;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.site-header__search-spinner {
|
|
448
|
+
width: 20px;
|
|
449
|
+
height: 20px;
|
|
450
|
+
border: 2px solid rgba(0, 0, 0, 0.1);
|
|
451
|
+
border-top-color: var(--header-text);
|
|
452
|
+
border-radius: 50%;
|
|
453
|
+
animation: spin 0.6s linear infinite;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@keyframes spin {
|
|
457
|
+
to { transform: rotate(360deg); }
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.site-header__search-results {
|
|
461
|
+
padding: 8px 0;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.site-header__search-result {
|
|
465
|
+
display: flex;
|
|
466
|
+
align-items: center;
|
|
467
|
+
gap: 12px;
|
|
468
|
+
padding: 12px 16px;
|
|
469
|
+
text-decoration: none;
|
|
470
|
+
color: var(--header-text);
|
|
471
|
+
transition: background 0.2s ease;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.site-header__search-result:hover {
|
|
475
|
+
background: rgba(0, 0, 0, 0.04);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.site-header__search-result-image {
|
|
479
|
+
width: 60px;
|
|
480
|
+
height: 60px;
|
|
481
|
+
object-fit: cover;
|
|
482
|
+
border-radius: 8px;
|
|
483
|
+
background: rgba(0, 0, 0, 0.05);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.site-header__search-result-info {
|
|
487
|
+
flex: 1;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.site-header__search-result-name {
|
|
491
|
+
font-weight: 600;
|
|
492
|
+
font-size: 14px;
|
|
493
|
+
margin-bottom: 4px;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.site-header__search-result-price {
|
|
497
|
+
font-size: 14px;
|
|
498
|
+
color: rgba(0, 0, 0, 0.6);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.site-header__search-empty {
|
|
502
|
+
padding: 24px;
|
|
503
|
+
text-align: center;
|
|
504
|
+
color: rgba(0, 0, 0, 0.5);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/* Actions */
|
|
508
|
+
.site-header__actions {
|
|
509
|
+
grid-column: 3;
|
|
510
|
+
display: flex;
|
|
511
|
+
align-items: center;
|
|
512
|
+
gap: 12px;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.site-header__action {
|
|
516
|
+
display: inline-flex;
|
|
517
|
+
align-items: center;
|
|
518
|
+
gap: 8px;
|
|
519
|
+
padding: 10px 16px;
|
|
520
|
+
border: none;
|
|
521
|
+
background: transparent;
|
|
522
|
+
color: var(--header-text);
|
|
523
|
+
text-decoration: none;
|
|
524
|
+
cursor: pointer;
|
|
525
|
+
border-radius: 12px;
|
|
526
|
+
transition: all 0.2s ease;
|
|
527
|
+
white-space: nowrap;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.site-header__action:hover {
|
|
531
|
+
background: rgba(0, 0, 0, 0.04);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.site-header__action--account {
|
|
535
|
+
border: 1px solid var(--header-border);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.site-header__action--cart {
|
|
539
|
+
background: var(--cart-bg);
|
|
540
|
+
color: var(--cart-text);
|
|
541
|
+
padding: 10px 20px;
|
|
542
|
+
border-radius: 24px;
|
|
543
|
+
position: relative;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.site-header__action--cart:hover {
|
|
547
|
+
background: var(--cart-hover);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.site-header__account-icon,
|
|
551
|
+
.site-header__login-icon,
|
|
552
|
+
.site-header__logout-icon,
|
|
553
|
+
.site-header__cart-icon {
|
|
554
|
+
width: 20px;
|
|
555
|
+
height: 20px;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.site-header__cart-text {
|
|
559
|
+
display: none;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.site-header__cart-count {
|
|
563
|
+
position: absolute;
|
|
564
|
+
top: -4px;
|
|
565
|
+
right: -4px;
|
|
566
|
+
min-width: 20px;
|
|
567
|
+
height: 20px;
|
|
568
|
+
padding: 0 6px;
|
|
569
|
+
background: #ff4444;
|
|
570
|
+
color: white;
|
|
571
|
+
border-radius: 10px;
|
|
572
|
+
font-size: 11px;
|
|
573
|
+
font-weight: 600;
|
|
574
|
+
display: flex;
|
|
575
|
+
align-items: center;
|
|
576
|
+
justify-content: center;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.site-header__logout-form {
|
|
580
|
+
margin: 0;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/* Mobile Search Row - Hidden on desktop */
|
|
584
|
+
.site-header__mobile-search-row {
|
|
585
|
+
display: none;
|
|
586
|
+
padding: 12px 0;
|
|
587
|
+
border-top: 1px solid var(--header-border);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.site-header__mobile-search {
|
|
591
|
+
position: relative;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.site-header__mobile-search-input-wrapper {
|
|
595
|
+
position: relative;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.site-header__mobile-search-icon {
|
|
599
|
+
position: absolute;
|
|
600
|
+
left: 16px;
|
|
601
|
+
top: 50%;
|
|
602
|
+
transform: translateY(-50%);
|
|
603
|
+
width: 20px;
|
|
604
|
+
height: 20px;
|
|
605
|
+
color: rgba(0, 0, 0, 0.5);
|
|
606
|
+
pointer-events: none;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
.site-header__mobile-search-input {
|
|
610
|
+
width: 100%;
|
|
611
|
+
height: 44px;
|
|
612
|
+
padding: 0 16px 0 48px;
|
|
613
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
614
|
+
border-radius: 22px;
|
|
615
|
+
font-size: 15px;
|
|
616
|
+
background: var(--header-bg);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.site-header__mobile-search-input:focus {
|
|
620
|
+
outline: none;
|
|
621
|
+
border-color: var(--header-text);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.site-header__mobile-search-dropdown {
|
|
625
|
+
position: absolute;
|
|
626
|
+
top: calc(100% + 8px);
|
|
627
|
+
left: 0;
|
|
628
|
+
right: 0;
|
|
629
|
+
background: white;
|
|
630
|
+
border-radius: 12px;
|
|
631
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
|
632
|
+
max-height: 400px;
|
|
633
|
+
overflow-y: auto;
|
|
634
|
+
z-index: 1000;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.site-header__mobile-search-loading {
|
|
638
|
+
display: flex;
|
|
639
|
+
align-items: center;
|
|
640
|
+
justify-content: center;
|
|
641
|
+
gap: 12px;
|
|
642
|
+
padding: 24px;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.site-header__mobile-search-spinner {
|
|
646
|
+
width: 20px;
|
|
647
|
+
height: 20px;
|
|
648
|
+
border: 2px solid rgba(0, 0, 0, 0.1);
|
|
649
|
+
border-top-color: var(--header-text);
|
|
650
|
+
border-radius: 50%;
|
|
651
|
+
animation: spin 0.6s linear infinite;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.site-header__mobile-search-results {
|
|
655
|
+
padding: 8px 0;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.site-header__mobile-search-result {
|
|
659
|
+
display: flex;
|
|
660
|
+
align-items: center;
|
|
661
|
+
gap: 12px;
|
|
662
|
+
padding: 12px 16px;
|
|
663
|
+
text-decoration: none;
|
|
664
|
+
color: var(--header-text);
|
|
665
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.site-header__mobile-search-result:hover {
|
|
669
|
+
background: rgba(0, 0, 0, 0.04);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
.site-header__mobile-search-result-image {
|
|
673
|
+
width: 60px;
|
|
674
|
+
height: 60px;
|
|
675
|
+
object-fit: cover;
|
|
676
|
+
border-radius: 8px;
|
|
677
|
+
background: rgba(0, 0, 0, 0.05);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.site-header__mobile-search-result-info {
|
|
681
|
+
flex: 1;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.site-header__mobile-search-result-name {
|
|
685
|
+
font-weight: 600;
|
|
686
|
+
font-size: 14px;
|
|
687
|
+
margin-bottom: 4px;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.site-header__mobile-search-result-price {
|
|
691
|
+
font-size: 14px;
|
|
692
|
+
color: rgba(0, 0, 0, 0.6);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.site-header__mobile-search-empty {
|
|
696
|
+
padding: 24px;
|
|
697
|
+
text-align: center;
|
|
698
|
+
color: rgba(0, 0, 0, 0.5);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/* Bottom Row */
|
|
702
|
+
.site-header__bottom-row {
|
|
703
|
+
border-top: 1px solid var(--header-border);
|
|
704
|
+
padding: 12px 0;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/* Mobile Responsive */
|
|
708
|
+
@media (max-width: 768px) {
|
|
709
|
+
.site-header__container {
|
|
710
|
+
padding: 0 16px;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.site-header__top-row {
|
|
714
|
+
grid-template-columns: auto 1fr auto;
|
|
715
|
+
gap: 12px;
|
|
716
|
+
padding: 12px 0;
|
|
717
|
+
min-height: 60px;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/* Show hamburger on mobile */
|
|
721
|
+
.site-header__toggle {
|
|
722
|
+
display: flex !important;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/* Logo moves to center on mobile */
|
|
726
|
+
.site-header__logo {
|
|
727
|
+
grid-column: 2;
|
|
728
|
+
justify-content: center;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.site-header__logo-image {
|
|
732
|
+
max-height: 32px;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
.site-header__brand {
|
|
736
|
+
font-size: 18px;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/* Hide desktop search on mobile */
|
|
740
|
+
.site-header__search-wrapper {
|
|
741
|
+
display: none !important;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/* Show mobile search */
|
|
745
|
+
.site-header__mobile-search-row {
|
|
746
|
+
display: block;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/* Actions on mobile */
|
|
750
|
+
.site-header__actions {
|
|
751
|
+
grid-column: 3;
|
|
752
|
+
gap: 8px;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/* Hide cart text on mobile, show icon only */
|
|
756
|
+
.site-header__cart-text {
|
|
757
|
+
display: none;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.site-header__action--cart {
|
|
761
|
+
padding: 10px;
|
|
762
|
+
min-width: 44px;
|
|
763
|
+
justify-content: center;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/* Reduce action padding on mobile */
|
|
767
|
+
.site-header__action {
|
|
768
|
+
padding: 10px;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
.site-header__action--account {
|
|
772
|
+
padding: 8px;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/* Hide bottom row (navigation) on mobile */
|
|
776
|
+
.site-header__bottom-row {
|
|
777
|
+
display: none;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/* Tablet adjustments */
|
|
782
|
+
@media (min-width: 769px) and (max-width: 1024px) {
|
|
783
|
+
.site-header__search-wrapper {
|
|
784
|
+
max-width: 400px;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
.site-header__cart-text {
|
|
788
|
+
display: none;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
</style>
|
|
792
|
+
|
|
793
|
+
<script>
|
|
794
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
795
|
+
// Desktop Search
|
|
796
|
+
const searchContainer = document.querySelector('[data-search-container]');
|
|
797
|
+
if (searchContainer) {
|
|
798
|
+
const searchInput = searchContainer.querySelector('[data-search-input]');
|
|
799
|
+
const searchClear = searchContainer.querySelector('[data-search-clear]');
|
|
800
|
+
const searchDropdown = searchContainer.querySelector('[data-search-dropdown]');
|
|
801
|
+
const searchResults = searchContainer.querySelector('[data-search-results]');
|
|
802
|
+
const searchLoading = searchContainer.querySelector('[data-search-loading]');
|
|
803
|
+
const searchEmpty = searchContainer.querySelector('[data-search-empty]');
|
|
804
|
+
|
|
805
|
+
let searchTimeout;
|
|
806
|
+
|
|
807
|
+
if (searchInput) {
|
|
808
|
+
searchInput.addEventListener('input', function() {
|
|
809
|
+
const query = this.value.trim();
|
|
810
|
+
|
|
811
|
+
if (searchClear) {
|
|
812
|
+
searchClear.style.display = query ? 'flex' : 'none';
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
if (query.length >= 2) {
|
|
816
|
+
clearTimeout(searchTimeout);
|
|
817
|
+
searchTimeout = setTimeout(() => performSearch(query), 300);
|
|
818
|
+
} else {
|
|
819
|
+
searchDropdown.style.display = 'none';
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (searchClear) {
|
|
825
|
+
searchClear.addEventListener('click', function() {
|
|
826
|
+
searchInput.value = '';
|
|
827
|
+
searchClear.style.display = 'none';
|
|
828
|
+
searchDropdown.style.display = 'none';
|
|
829
|
+
searchInput.focus();
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
async function performSearch(query) {
|
|
834
|
+
searchLoading.style.display = 'flex';
|
|
835
|
+
searchResults.innerHTML = '';
|
|
836
|
+
searchEmpty.style.display = 'none';
|
|
837
|
+
searchDropdown.style.display = 'block';
|
|
838
|
+
|
|
839
|
+
try {
|
|
840
|
+
const response = await fetch(`/webstoreapi/search/autocomplete?q=${encodeURIComponent(query)}`);
|
|
841
|
+
const data = await response.json();
|
|
842
|
+
|
|
843
|
+
searchLoading.style.display = 'none';
|
|
844
|
+
|
|
845
|
+
if (data.success && data.products && data.products.length > 0) {
|
|
846
|
+
displayResults(data.products);
|
|
847
|
+
} else {
|
|
848
|
+
searchEmpty.style.display = 'block';
|
|
849
|
+
}
|
|
850
|
+
} catch (error) {
|
|
851
|
+
console.error('Search error:', error);
|
|
852
|
+
searchLoading.style.display = 'none';
|
|
853
|
+
searchEmpty.style.display = 'block';
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function displayResults(products) {
|
|
858
|
+
searchResults.innerHTML = '';
|
|
859
|
+
products.forEach(product => {
|
|
860
|
+
const resultItem = document.createElement('a');
|
|
861
|
+
const productSlug = product.slug || product.id;
|
|
862
|
+
resultItem.href = productSlug ? `/${productSlug}` : '#';
|
|
863
|
+
resultItem.className = 'site-header__search-result';
|
|
864
|
+
|
|
865
|
+
const imageHtml = product.thumbnailUrl
|
|
866
|
+
? `<img src="${product.thumbnailUrl}" alt="${product.name}" class="site-header__search-result-image" loading="lazy">`
|
|
867
|
+
: `<div class="site-header__search-result-image" style="background-color: rgba(0,0,0,0.05); display: flex; align-items: center; justify-content: center; color: rgba(0,0,0,0.3); font-size: 0.75rem;">No image</div>`;
|
|
868
|
+
|
|
869
|
+
resultItem.innerHTML = `
|
|
870
|
+
${imageHtml}
|
|
871
|
+
<div class="site-header__search-result-info">
|
|
872
|
+
<div class="site-header__search-result-name">${escapeHtml(product.name)}</div>
|
|
873
|
+
<div class="site-header__search-result-price">${product.prices.priceString || 'Price not available'}</div>
|
|
874
|
+
</div>
|
|
875
|
+
`;
|
|
876
|
+
|
|
877
|
+
searchResults.appendChild(resultItem);
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function escapeHtml(text) {
|
|
882
|
+
const div = document.createElement('div');
|
|
883
|
+
div.textContent = text;
|
|
884
|
+
return div.innerHTML;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
document.addEventListener('click', function(e) {
|
|
888
|
+
if (searchContainer && !searchContainer.contains(e.target)) {
|
|
889
|
+
searchDropdown.style.display = 'none';
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// Mobile Search
|
|
895
|
+
const mobileSearch = document.querySelector('.site-header__mobile-search');
|
|
896
|
+
if (mobileSearch) {
|
|
897
|
+
const mobileSearchInput = mobileSearch.querySelector('[data-mobile-search-input]');
|
|
898
|
+
const mobileSearchDropdown = mobileSearch.querySelector('[data-mobile-search-dropdown]');
|
|
899
|
+
const mobileSearchResults = mobileSearch.querySelector('[data-mobile-search-results]');
|
|
900
|
+
const mobileSearchLoading = mobileSearch.querySelector('[data-mobile-search-loading]');
|
|
901
|
+
const mobileSearchEmpty = mobileSearch.querySelector('[data-mobile-search-empty]');
|
|
902
|
+
const mobileSearchForm = mobileSearch.querySelector('.site-header__mobile-search-form');
|
|
903
|
+
|
|
904
|
+
let mobileSearchTimeout;
|
|
905
|
+
|
|
906
|
+
if (mobileSearchInput) {
|
|
907
|
+
mobileSearchInput.addEventListener('input', function() {
|
|
908
|
+
const query = this.value.trim();
|
|
909
|
+
|
|
910
|
+
if (query.length >= 2) {
|
|
911
|
+
clearTimeout(mobileSearchTimeout);
|
|
912
|
+
mobileSearchTimeout = setTimeout(() => performMobileSearch(query), 300);
|
|
913
|
+
} else {
|
|
914
|
+
mobileSearchDropdown.style.display = 'none';
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
if (mobileSearchForm) {
|
|
920
|
+
mobileSearchForm.addEventListener('submit', function(e) {
|
|
921
|
+
const query = mobileSearchInput.value.trim();
|
|
922
|
+
if (!query || query.length < 2) {
|
|
923
|
+
e.preventDefault();
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
async function performMobileSearch(query) {
|
|
929
|
+
mobileSearchLoading.style.display = 'flex';
|
|
930
|
+
mobileSearchResults.innerHTML = '';
|
|
931
|
+
mobileSearchEmpty.style.display = 'none';
|
|
932
|
+
mobileSearchDropdown.style.display = 'block';
|
|
933
|
+
|
|
934
|
+
try {
|
|
935
|
+
const response = await fetch(`/webstoreapi/search/autocomplete?q=${encodeURIComponent(query)}`);
|
|
936
|
+
const data = await response.json();
|
|
937
|
+
|
|
938
|
+
mobileSearchLoading.style.display = 'none';
|
|
939
|
+
|
|
940
|
+
if (data.success && data.products && data.products.length > 0) {
|
|
941
|
+
displayMobileResults(data.products);
|
|
942
|
+
} else {
|
|
943
|
+
mobileSearchEmpty.style.display = 'block';
|
|
944
|
+
}
|
|
945
|
+
} catch (error) {
|
|
946
|
+
console.error('Mobile search error:', error);
|
|
947
|
+
mobileSearchLoading.style.display = 'none';
|
|
948
|
+
mobileSearchEmpty.style.display = 'block';
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
function displayMobileResults(products) {
|
|
953
|
+
mobileSearchResults.innerHTML = '';
|
|
954
|
+
products.forEach(product => {
|
|
955
|
+
const resultItem = document.createElement('a');
|
|
956
|
+
const productSlug = product.slug || product.id;
|
|
957
|
+
resultItem.href = productSlug ? `/${productSlug}` : '#';
|
|
958
|
+
resultItem.className = 'site-header__mobile-search-result';
|
|
959
|
+
|
|
960
|
+
const imageHtml = product.thumbnailUrl
|
|
961
|
+
? `<img src="${product.thumbnailUrl}" alt="${product.name}" class="site-header__mobile-search-result-image" loading="lazy">`
|
|
962
|
+
: `<div class="site-header__mobile-search-result-image" style="background-color: rgba(0,0,0,0.05); display: flex; align-items: center; justify-content: center; color: rgba(0,0,0,0.3); font-size: 0.75rem;">No image</div>`;
|
|
963
|
+
|
|
964
|
+
resultItem.innerHTML = `
|
|
965
|
+
${imageHtml}
|
|
966
|
+
<div class="site-header__mobile-search-result-info">
|
|
967
|
+
<div class="site-header__mobile-search-result-name">${escapeHtml(product.name)}</div>
|
|
968
|
+
<div class="site-header__mobile-search-result-price">${product.prices.priceString || 'Price not available'}</div>
|
|
969
|
+
</div>
|
|
970
|
+
`;
|
|
971
|
+
|
|
972
|
+
mobileSearchResults.appendChild(resultItem);
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
function escapeHtml(text) {
|
|
977
|
+
const div = document.createElement('div');
|
|
978
|
+
div.textContent = text;
|
|
979
|
+
return div.innerHTML;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
document.addEventListener('click', function(e) {
|
|
983
|
+
if (mobileSearch && !mobileSearch.contains(e.target)) {
|
|
984
|
+
mobileSearchDropdown.style.display = 'none';
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Check authentication state - only check non-httpOnly cookie
|
|
990
|
+
function isAuthenticated() {
|
|
991
|
+
// O2VENDUserToken is httpOnly, so we check O2VENDIsUserLoggedin flag cookie
|
|
992
|
+
const cookies = document.cookie.split(';');
|
|
993
|
+
for (let cookie of cookies) {
|
|
994
|
+
const [name, value] = cookie.trim().split('=');
|
|
995
|
+
if (name === 'O2VENDIsUserLoggedin' && (value === 'true' || value === '1')) {
|
|
996
|
+
return true;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
return false;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// Update UI to show account/logout icons when authenticated
|
|
1003
|
+
function updateAuthUI() {
|
|
1004
|
+
const authenticated = isAuthenticated();
|
|
1005
|
+
const accountIcon = document.querySelector('.site-header__action--account');
|
|
1006
|
+
const logoutForm = document.querySelector('.site-header__logout-form');
|
|
1007
|
+
const loginIcon = document.querySelector('.site-header__action--login');
|
|
1008
|
+
|
|
1009
|
+
if (authenticated) {
|
|
1010
|
+
// User is authenticated - show account and logout icons
|
|
1011
|
+
// Create account icon if it doesn't exist
|
|
1012
|
+
if (!accountIcon && document.querySelector('.site-header__actions')) {
|
|
1013
|
+
const actionsContainer = document.querySelector('.site-header__actions');
|
|
1014
|
+
const accountLink = document.createElement('a');
|
|
1015
|
+
accountLink.href = '/account';
|
|
1016
|
+
accountLink.className = 'site-header__action site-header__action--account';
|
|
1017
|
+
accountLink.setAttribute('aria-label', 'Account');
|
|
1018
|
+
accountLink.innerHTML = '<svg class="site-header__account-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>';
|
|
1019
|
+
actionsContainer.insertBefore(accountLink, actionsContainer.firstChild);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Create logout form if it doesn't exist
|
|
1023
|
+
if (!logoutForm && document.querySelector('.site-header__actions')) {
|
|
1024
|
+
const actionsContainer = document.querySelector('.site-header__actions');
|
|
1025
|
+
const logoutFormEl = document.createElement('form');
|
|
1026
|
+
logoutFormEl.method = 'post';
|
|
1027
|
+
logoutFormEl.action = '/webstoreapi/customer/logout';
|
|
1028
|
+
logoutFormEl.className = 'site-header__logout-form';
|
|
1029
|
+
logoutFormEl.innerHTML = '<button type="submit" class="site-header__action site-header__action--logout" aria-label="Logout"><svg class="site-header__logout-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg></button>';
|
|
1030
|
+
const accountIconEl = document.querySelector('.site-header__action--account');
|
|
1031
|
+
if (accountIconEl) {
|
|
1032
|
+
accountIconEl.parentNode.insertBefore(logoutFormEl, accountIconEl.nextSibling);
|
|
1033
|
+
} else {
|
|
1034
|
+
actionsContainer.appendChild(logoutFormEl);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// Show existing elements if they're hidden
|
|
1039
|
+
const accountIconEl = document.querySelector('.site-header__action--account');
|
|
1040
|
+
const logoutFormEl = document.querySelector('.site-header__logout-form');
|
|
1041
|
+
if (accountIconEl && accountIconEl.offsetParent === null) {
|
|
1042
|
+
accountIconEl.style.display = '';
|
|
1043
|
+
}
|
|
1044
|
+
if (logoutFormEl && logoutFormEl.offsetParent === null) {
|
|
1045
|
+
logoutFormEl.style.display = '';
|
|
1046
|
+
}
|
|
1047
|
+
if (loginIcon && loginIcon.offsetParent !== null) {
|
|
1048
|
+
loginIcon.style.display = 'none';
|
|
1049
|
+
}
|
|
1050
|
+
} else {
|
|
1051
|
+
// User is not authenticated - hide account and logout icons
|
|
1052
|
+
if (accountIcon && accountIcon.offsetParent !== null) {
|
|
1053
|
+
accountIcon.style.display = 'none';
|
|
1054
|
+
}
|
|
1055
|
+
if (logoutForm && logoutForm.offsetParent !== null) {
|
|
1056
|
+
logoutForm.style.display = 'none';
|
|
1057
|
+
}
|
|
1058
|
+
if (loginIcon && loginIcon.offsetParent === null) {
|
|
1059
|
+
loginIcon.style.display = '';
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// Run check after a short delay to ensure DOM is ready
|
|
1065
|
+
setTimeout(updateAuthUI, 100);
|
|
1066
|
+
|
|
1067
|
+
// Also listen for login success events and update UI immediately
|
|
1068
|
+
// This handles cases where login happens without page refresh
|
|
1069
|
+
document.addEventListener('loginSuccess', function() {
|
|
1070
|
+
setTimeout(updateAuthUI, 200);
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
// Monitor for login modal success view being shown
|
|
1074
|
+
const observer = new MutationObserver(function(mutations) {
|
|
1075
|
+
const successView = document.querySelector('[data-login-view="success"]');
|
|
1076
|
+
if (successView && !successView.hidden) {
|
|
1077
|
+
// Login success detected - update UI
|
|
1078
|
+
setTimeout(updateAuthUI, 300);
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
const loginModal = document.getElementById('login-modal');
|
|
1083
|
+
if (loginModal) {
|
|
1084
|
+
observer.observe(loginModal, {
|
|
1085
|
+
attributes: true,
|
|
1086
|
+
attributeFilter: ['hidden'],
|
|
1087
|
+
childList: true,
|
|
1088
|
+
subtree: true
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// Also check periodically (every 2 seconds) if user becomes authenticated
|
|
1093
|
+
// This handles cases where cookies are set but UI hasn't updated
|
|
1094
|
+
setInterval(function() {
|
|
1095
|
+
const authenticated = isAuthenticated();
|
|
1096
|
+
const accountIcon = document.querySelector('.site-header__action--account');
|
|
1097
|
+
const logoutForm = document.querySelector('.site-header__logout-form');
|
|
1098
|
+
|
|
1099
|
+
// Only update if we detect a mismatch
|
|
1100
|
+
if (authenticated && (!accountIcon || accountIcon.offsetParent === null || !logoutForm || logoutForm.offsetParent === null)) {
|
|
1101
|
+
updateAuthUI();
|
|
1102
|
+
}
|
|
1103
|
+
}, 2000);
|
|
1104
|
+
|
|
1105
|
+
// Handle account icon click - check authentication and open login modal if needed
|
|
1106
|
+
const accountIcon = document.querySelector('.site-header__action--account');
|
|
1107
|
+
if (accountIcon) {
|
|
1108
|
+
accountIcon.addEventListener('click', function(e) {
|
|
1109
|
+
// If not authenticated, prevent navigation and open login modal
|
|
1110
|
+
if (!isAuthenticated()) {
|
|
1111
|
+
e.preventDefault();
|
|
1112
|
+
e.stopPropagation();
|
|
1113
|
+
|
|
1114
|
+
// Try to open login modal
|
|
1115
|
+
const loginTrigger = document.querySelector('[data-login-modal-trigger]');
|
|
1116
|
+
if (loginTrigger) {
|
|
1117
|
+
loginTrigger.click();
|
|
1118
|
+
} else if (window.Theme && typeof window.Theme.openLoginModal === 'function') {
|
|
1119
|
+
window.Theme.openLoginModal();
|
|
1120
|
+
} else {
|
|
1121
|
+
// Fallback: redirect to login page
|
|
1122
|
+
window.location.href = '/customers/login';
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
</script>
|
|
1129
|
+
|
|
1130
|
+
{% schema %}
|
|
1131
|
+
{
|
|
1132
|
+
"name": "Header",
|
|
1133
|
+
"settings": [
|
|
1134
|
+
{
|
|
1135
|
+
"type": "paragraph",
|
|
1136
|
+
"content": "This section displays widgets from the 'header' section. Widgets are automatically ordered by their Position field and can be reordered in the visual editor."
|
|
1137
|
+
}
|
|
1138
|
+
],
|
|
1139
|
+
"presets": [
|
|
1140
|
+
{
|
|
1141
|
+
"name": "Header"
|
|
1142
|
+
}
|
|
1143
|
+
]
|
|
1144
|
+
}
|
|
1145
|
+
{% endschema %}
|