@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.
Files changed (116) hide show
  1. package/README.md +425 -0
  2. package/assets/Logo_o2vend.png +0 -0
  3. package/assets/favicon.png +0 -0
  4. package/assets/logo-white.png +0 -0
  5. package/bin/o2vend +42 -0
  6. package/config/widget-map.json +50 -0
  7. package/lib/commands/check.js +201 -0
  8. package/lib/commands/generate.js +33 -0
  9. package/lib/commands/init.js +214 -0
  10. package/lib/commands/optimize.js +216 -0
  11. package/lib/commands/package.js +208 -0
  12. package/lib/commands/serve.js +105 -0
  13. package/lib/commands/validate.js +191 -0
  14. package/lib/lib/api-client.js +357 -0
  15. package/lib/lib/dev-server.js +2618 -0
  16. package/lib/lib/file-watcher.js +80 -0
  17. package/lib/lib/hot-reload.js +106 -0
  18. package/lib/lib/liquid-engine.js +822 -0
  19. package/lib/lib/liquid-filters.js +671 -0
  20. package/lib/lib/mock-api-server.js +989 -0
  21. package/lib/lib/mock-data.js +1468 -0
  22. package/lib/lib/widget-service.js +321 -0
  23. package/package.json +70 -0
  24. package/test-theme/README.md +27 -0
  25. package/test-theme/assets/async-sections.js +446 -0
  26. package/test-theme/assets/cart-drawer.js +463 -0
  27. package/test-theme/assets/cart-manager.js +223 -0
  28. package/test-theme/assets/checkout-price-handler.js +368 -0
  29. package/test-theme/assets/components.css +4629 -0
  30. package/test-theme/assets/delivery-zone.css +299 -0
  31. package/test-theme/assets/delivery-zone.js +396 -0
  32. package/test-theme/assets/logo.png +0 -0
  33. package/test-theme/assets/sections.css +48 -0
  34. package/test-theme/assets/theme.css +3500 -0
  35. package/test-theme/assets/theme.js +3745 -0
  36. package/test-theme/config/settings_data.json +292 -0
  37. package/test-theme/config/settings_schema.json +1050 -0
  38. package/test-theme/layout/theme.liquid +195 -0
  39. package/test-theme/locales/en.default.json +260 -0
  40. package/test-theme/sections/content-fallback.liquid +53 -0
  41. package/test-theme/sections/content.liquid +57 -0
  42. package/test-theme/sections/footer-fallback.liquid +328 -0
  43. package/test-theme/sections/footer.liquid +278 -0
  44. package/test-theme/sections/header-fallback.liquid +1805 -0
  45. package/test-theme/sections/header.liquid +1145 -0
  46. package/test-theme/sections/hero-fallback.liquid +212 -0
  47. package/test-theme/sections/hero.liquid +136 -0
  48. package/test-theme/snippets/account-sidebar.liquid +200 -0
  49. package/test-theme/snippets/add-to-cart-modal.liquid +484 -0
  50. package/test-theme/snippets/breadcrumbs.liquid +134 -0
  51. package/test-theme/snippets/cart-drawer.liquid +467 -0
  52. package/test-theme/snippets/delivery-zone-city-selector.liquid +79 -0
  53. package/test-theme/snippets/delivery-zone-modal.liquid +337 -0
  54. package/test-theme/snippets/delivery-zone-search.liquid +78 -0
  55. package/test-theme/snippets/icon.liquid +105 -0
  56. package/test-theme/snippets/login-modal.liquid +346 -0
  57. package/test-theme/snippets/mega-menu.liquid +812 -0
  58. package/test-theme/snippets/news-thumbnail.liquid +187 -0
  59. package/test-theme/snippets/pagination.liquid +120 -0
  60. package/test-theme/snippets/price.liquid +92 -0
  61. package/test-theme/snippets/product-card-related.liquid +78 -0
  62. package/test-theme/snippets/product-card-simple.liquid +41 -0
  63. package/test-theme/snippets/product-card.liquid +697 -0
  64. package/test-theme/snippets/rating.liquid +85 -0
  65. package/test-theme/snippets/skeleton-collection-grid.liquid +114 -0
  66. package/test-theme/snippets/skeleton-product-card.liquid +124 -0
  67. package/test-theme/snippets/skeleton-product-grid.liquid +34 -0
  68. package/test-theme/snippets/social-sharing.liquid +185 -0
  69. package/test-theme/templates/account/dashboard.liquid +401 -0
  70. package/test-theme/templates/account/loyalty-redemption.liquid +405 -0
  71. package/test-theme/templates/account/loyalty.liquid +588 -0
  72. package/test-theme/templates/account/order-detail.liquid +230 -0
  73. package/test-theme/templates/account/orders.liquid +349 -0
  74. package/test-theme/templates/account/profile.liquid +758 -0
  75. package/test-theme/templates/account/register.liquid +232 -0
  76. package/test-theme/templates/account/return-orders.liquid +348 -0
  77. package/test-theme/templates/account/store-credit.liquid +464 -0
  78. package/test-theme/templates/account/subscriptions.liquid +601 -0
  79. package/test-theme/templates/account/wishlist.liquid +419 -0
  80. package/test-theme/templates/address-book.liquid +1092 -0
  81. package/test-theme/templates/categories.liquid +452 -0
  82. package/test-theme/templates/checkout.liquid +4511 -0
  83. package/test-theme/templates/error.liquid +384 -0
  84. package/test-theme/templates/index.liquid +11 -0
  85. package/test-theme/templates/login.liquid +185 -0
  86. package/test-theme/templates/order-confirmation.liquid +720 -0
  87. package/test-theme/templates/page.liquid +297 -0
  88. package/test-theme/templates/product-detail.liquid +4363 -0
  89. package/test-theme/templates/products.liquid +518 -0
  90. package/test-theme/templates/search.liquid +922 -0
  91. package/test-theme/theme.json.example +19 -0
  92. package/test-theme/widgets/brand-carousel.liquid +676 -0
  93. package/test-theme/widgets/brand.liquid +245 -0
  94. package/test-theme/widgets/carousel.liquid +843 -0
  95. package/test-theme/widgets/category-list-carousel.liquid +656 -0
  96. package/test-theme/widgets/category-list.liquid +340 -0
  97. package/test-theme/widgets/category.liquid +475 -0
  98. package/test-theme/widgets/discount-time.liquid +176 -0
  99. package/test-theme/widgets/footer-menu.liquid +695 -0
  100. package/test-theme/widgets/footer.liquid +179 -0
  101. package/test-theme/widgets/gallery.liquid +271 -0
  102. package/test-theme/widgets/header-menu.liquid +932 -0
  103. package/test-theme/widgets/header.liquid +159 -0
  104. package/test-theme/widgets/html.liquid +214 -0
  105. package/test-theme/widgets/news.liquid +217 -0
  106. package/test-theme/widgets/product-canvas.liquid +235 -0
  107. package/test-theme/widgets/product-carousel.liquid +502 -0
  108. package/test-theme/widgets/product.liquid +45 -0
  109. package/test-theme/widgets/recently-viewed.liquid +26 -0
  110. package/test-theme/widgets/shared/product-grid.liquid +339 -0
  111. package/test-theme/widgets/simple-product.liquid +42 -0
  112. package/test-theme/widgets/single-product.liquid +610 -0
  113. package/test-theme/widgets/spacebar-carousel.liquid +663 -0
  114. package/test-theme/widgets/spacebar.liquid +279 -0
  115. package/test-theme/widgets/splash.liquid +378 -0
  116. package/test-theme/widgets/testimonial-carousel.liquid +709 -0
@@ -0,0 +1,452 @@
1
+ {% layout 'layout/theme' %}
2
+
3
+ <div class="collections-page">
4
+ <div class="collections-header">
5
+ <h1 class="page-title">Our Collections</h1>
6
+ <p class="page-description">Discover our curated collections of amazing products</p>
7
+ </div>
8
+ <div class="collections-content">
9
+ {% if collections.size > 0 %}
10
+ <div class="collections-grid">
11
+ {% for collection in collections %}
12
+ <div class="collection-card">
13
+ <a href="/{{ collection.slug }}" class="collection-link">
14
+ <div class="collection-image">
15
+ {% if collection.image %}
16
+ <img src="{{ collection.image }}"
17
+ alt="{{ collection.title | default: collection.name }}"
18
+ width="100%"
19
+ height="200"
20
+ loading="lazy">
21
+ {% else %}
22
+ <div class="collection-image-placeholder">
23
+ <div class="camera-icon">
24
+ {% raw %}<svg width="60" height="60" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
25
+ <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path>
26
+ <circle cx="12" cy="13" r="4"></circle>
27
+ </svg>{% endraw %}
28
+ </div>
29
+ <div class="image-not-available">
30
+ <span class="sorry-text">Sorry</span>
31
+ <span class="image-text">IMAGE</span>
32
+ <span class="not-available-text">Not Available</span>
33
+ </div>
34
+ </div>
35
+ {% endif %}
36
+ </div>
37
+ <div class="collection-info">
38
+ <h3 class="collection-title">{{ collection.title | default: collection.name }}</h3>
39
+ {% if collection.description %}
40
+ <p class="collection-description">{{ collection.description }}</p>
41
+ {% else %}
42
+ <p class="collection-description">Setup your products and images in Catalog - Category</p>
43
+ {% endif %}
44
+ </div>
45
+ </a>
46
+ </div>
47
+ {% endfor %}
48
+ </div>
49
+ {% else %}
50
+ <!-- No Collections -->
51
+ <div class="no-collections">
52
+ <div class="no-collections-content">
53
+ <div class="no-collections-icon">📂</div>
54
+ <h2>No Collections Available</h2>
55
+ <p>We're working on creating amazing collections for you. Check back soon!</p>
56
+ <a href="/products" class="btn btn-primary">Browse All Products</a>
57
+ </div>
58
+ </div>
59
+ {% endif %}
60
+
61
+ <!-- Pagination -->
62
+ {% if pagination and pagination.totalPages > 1 %}
63
+ {% include 'snippets/pagination', pagination: pagination %}
64
+ {% endif %}
65
+ </div>
66
+ </div>
67
+
68
+ <style>
69
+ /* Collection Toolbar Styles */
70
+ .collection-toolbar {
71
+ background-color: #fff;
72
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
73
+ padding: 1.5rem 0;
74
+ margin-bottom: 2rem;
75
+ }
76
+
77
+ .collections-page {
78
+ padding: 40px 0;
79
+ }
80
+
81
+ .collections-header {
82
+ text-align: center;
83
+ margin-bottom: 60px;
84
+ padding: 50px 20px;
85
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
86
+ color: white;
87
+ border-radius: 12px;
88
+ }
89
+
90
+ .page-title {
91
+ font-size: 3rem;
92
+ margin-bottom: 20px;
93
+ font-weight: 700;
94
+ }
95
+
96
+ .page-description {
97
+ font-size: 1.2rem;
98
+ opacity: 0.9;
99
+ max-width: 600px;
100
+ margin: 0 auto;
101
+ }
102
+
103
+ .collections-content {
104
+ margin-bottom: 80px;
105
+ }
106
+
107
+ .collections-grid {
108
+ display: grid;
109
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
110
+ gap: 24px;
111
+ margin-bottom: 60px;
112
+ align-items: stretch;
113
+ }
114
+
115
+ .collection-card {
116
+ background: white;
117
+ border-radius: 8px;
118
+ overflow: hidden;
119
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
120
+ transition: box-shadow 0.3s ease;
121
+ position: relative;
122
+ display: flex;
123
+ flex-direction: column;
124
+ height: 100%;
125
+ border: 1px solid rgba(0, 0, 0, 0.05);
126
+ }
127
+
128
+ .collection-card:hover {
129
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
130
+ }
131
+
132
+ .collection-link {
133
+ text-decoration: none;
134
+ color: inherit;
135
+ display: flex;
136
+ flex-direction: column;
137
+ height: 100%;
138
+ }
139
+
140
+ .collection-image {
141
+ position: relative;
142
+ overflow: hidden;
143
+ width: 100%;
144
+ height: 200px;
145
+ background: #f8f9fa;
146
+ flex-shrink: 0;
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ }
151
+
152
+ .collection-image img {
153
+ width: 100%;
154
+ height: 100%;
155
+ object-fit: cover;
156
+ }
157
+
158
+ .collection-image-placeholder {
159
+ display: flex;
160
+ flex-direction: column;
161
+ align-items: center;
162
+ justify-content: center;
163
+ width: 100%;
164
+ height: 100%;
165
+ background: #ffffff;
166
+ color: #000;
167
+ padding: 20px;
168
+ }
169
+
170
+ .camera-icon {
171
+ margin-bottom: 10px;
172
+ color: #000;
173
+ }
174
+
175
+ .camera-icon svg {
176
+ width: 60px;
177
+ height: 60px;
178
+ stroke-width: 1.5;
179
+ }
180
+
181
+ .image-not-available {
182
+ display: flex;
183
+ flex-direction: column;
184
+ align-items: center;
185
+ text-align: center;
186
+ gap: 2px;
187
+ }
188
+
189
+ .sorry-text {
190
+ font-size: 0.875rem;
191
+ color: #000;
192
+ font-weight: 400;
193
+ }
194
+
195
+ .image-text {
196
+ font-size: 1.5rem;
197
+ font-weight: 700;
198
+ color: #000;
199
+ letter-spacing: 0.5px;
200
+ }
201
+
202
+ .not-available-text {
203
+ font-size: 0.875rem;
204
+ color: #000;
205
+ font-weight: 400;
206
+ }
207
+
208
+ .collection-info {
209
+ padding: 20px;
210
+ display: flex;
211
+ flex-direction: column;
212
+ flex: 1;
213
+ background: #ffffff;
214
+ }
215
+
216
+ .collection-title {
217
+ font-size: 1rem;
218
+ margin-bottom: 8px;
219
+ color: #000;
220
+ font-weight: 700;
221
+ line-height: 1.4;
222
+ }
223
+
224
+ .collection-description {
225
+ color: #666;
226
+ font-size: 0.875rem;
227
+ line-height: 1.5;
228
+ margin-bottom: 0;
229
+ font-weight: 400;
230
+ display: -webkit-box;
231
+ -webkit-line-clamp: 2;
232
+ -webkit-box-orient: vertical;
233
+ overflow: hidden;
234
+ text-overflow: ellipsis;
235
+ margin-top: auto;
236
+ }
237
+
238
+ .updated-date {
239
+ color: #999;
240
+ }
241
+
242
+ .no-collections {
243
+ display: flex;
244
+ justify-content: center;
245
+ align-items: center;
246
+ min-height: 400px;
247
+ }
248
+
249
+ .no-collections-content {
250
+ text-align: center;
251
+ max-width: 400px;
252
+ }
253
+
254
+ .no-collections-icon {
255
+ font-size: 4rem;
256
+ margin-bottom: 20px;
257
+ }
258
+
259
+ .no-collections h2 {
260
+ font-size: 1.8rem;
261
+ margin-bottom: 15px;
262
+ color: #333;
263
+ }
264
+
265
+ .no-collections p {
266
+ color: #666;
267
+ margin-bottom: 30px;
268
+ line-height: 1.5;
269
+ }
270
+
271
+ /* Responsive Design */
272
+ @media (max-width: 1024px) {
273
+ .collections-grid {
274
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
275
+ gap: 25px;
276
+ }
277
+ }
278
+
279
+ @media (max-width: 768px) {
280
+ .collections-grid {
281
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
282
+ gap: 25px;
283
+ }
284
+
285
+ .page-title {
286
+ font-size: 2.5rem;
287
+ }
288
+
289
+ .collection-info {
290
+ padding: 20px;
291
+ }
292
+ }
293
+
294
+ @media (max-width: 480px) {
295
+ .collections-header {
296
+ padding: 30px 15px;
297
+ }
298
+
299
+ .collections-grid {
300
+ grid-template-columns: 1fr;
301
+ gap: 20px;
302
+ }
303
+
304
+ .collection-info {
305
+ padding: 18px;
306
+ }
307
+
308
+ .collection-title {
309
+ font-size: 1.2rem;
310
+ }
311
+
312
+ .collection-description {
313
+ font-size: 0.9rem;
314
+ }
315
+
316
+ .page-title {
317
+ font-size: 2rem;
318
+ }
319
+ }
320
+ </style>
321
+
322
+ <script>
323
+ document.addEventListener('DOMContentLoaded', function() {
324
+ // Parse URL parameters
325
+ const urlParams = new URLSearchParams(window.location.search);
326
+
327
+ // Initialize sort from URL parameters
328
+ function initializeSortFromURL() {
329
+ const sortToggleLabel = document.getElementById('sort-toggle-label');
330
+ const sortMenu = document.getElementById('sort-menu');
331
+
332
+ if (urlParams.has('sort')) {
333
+ const sortParam = urlParams.get('sort');
334
+ const orderParam = urlParams.get('order') || 'asc';
335
+ let sortLabel = 'Display Order, Asc';
336
+
337
+ if (sortParam === 'name' && orderParam === 'asc') {
338
+ sortLabel = 'Name, A-Z';
339
+ } else if (sortParam === 'name' && orderParam === 'desc') {
340
+ sortLabel = 'Name, Z-A';
341
+ } else if (sortParam === 'order' && orderParam === 'desc') {
342
+ sortLabel = 'Display Order, Desc';
343
+ }
344
+
345
+ if (sortToggleLabel) {
346
+ sortToggleLabel.textContent = `Sort: ${sortLabel}`;
347
+ }
348
+
349
+ // Mark the selected option as active
350
+ if (sortMenu) {
351
+ const sortOptions = sortMenu.querySelectorAll('.sort-option');
352
+ sortOptions.forEach(option => {
353
+ option.classList.remove('active', 'selected');
354
+ const optionSort = option.getAttribute('data-sort');
355
+ const optionOrder = option.getAttribute('data-order');
356
+ if (optionSort === sortParam && optionOrder === orderParam) {
357
+ option.classList.add('active', 'selected');
358
+ option.setAttribute('aria-selected', 'true');
359
+ } else {
360
+ option.setAttribute('aria-selected', 'false');
361
+ }
362
+ });
363
+ }
364
+ }
365
+ }
366
+
367
+ // Initialize sort on page load
368
+ initializeSortFromURL();
369
+
370
+ // Sorting functionality
371
+ const sortDropdown = document.getElementById('sort-dropdown');
372
+ const sortToggle = document.getElementById('sort-toggle');
373
+ const sortMenu = document.getElementById('sort-menu');
374
+ const sortLabel = document.getElementById('sort-toggle-label');
375
+
376
+ function applySort(sortValue, orderValue) {
377
+ const params = new URLSearchParams(window.location.search);
378
+ if (sortValue) {
379
+ params.set('sort', sortValue);
380
+ params.set('order', orderValue || 'asc');
381
+ } else {
382
+ params.delete('sort');
383
+ params.delete('order');
384
+ }
385
+ params.set('page', '1'); // Reset to page 1 when sorting changes
386
+
387
+ window.location.href = `${window.location.pathname}?${params.toString()}`;
388
+ }
389
+
390
+ // Toggle sort dropdown
391
+ if (sortToggle && sortMenu) {
392
+ sortToggle.addEventListener('click', function(e) {
393
+ e.stopPropagation();
394
+ sortMenu.classList.toggle('active');
395
+ sortToggle.setAttribute('aria-expanded', sortMenu.classList.contains('active'));
396
+ });
397
+ }
398
+
399
+ // Close sort dropdown when clicking outside
400
+ document.addEventListener('click', function(e) {
401
+ if (sortDropdown && !sortDropdown.contains(e.target)) {
402
+ sortMenu.classList.remove('active');
403
+ sortToggle.setAttribute('aria-expanded', 'false');
404
+ }
405
+ });
406
+
407
+ // Handle sort option selection
408
+ if (sortMenu) {
409
+ const sortOptions = sortMenu.querySelectorAll('.sort-option');
410
+ sortOptions.forEach(option => {
411
+ option.addEventListener('click', function() {
412
+ const sortValue = this.getAttribute('data-sort');
413
+ const orderValue = this.getAttribute('data-order');
414
+ const label = this.getAttribute('data-label');
415
+
416
+ if (sortLabel) {
417
+ sortLabel.textContent = `Sort: ${label}`;
418
+ }
419
+
420
+ // Update active state
421
+ sortOptions.forEach(opt => {
422
+ opt.classList.remove('active', 'selected');
423
+ opt.setAttribute('aria-selected', 'false');
424
+ });
425
+ this.classList.add('active', 'selected');
426
+ this.setAttribute('aria-selected', 'true');
427
+
428
+ // Close dropdown
429
+ sortMenu.classList.remove('active');
430
+ sortToggle.setAttribute('aria-expanded', 'false');
431
+
432
+ // Apply sort
433
+ applySort(sortValue, orderValue);
434
+ });
435
+ });
436
+ }
437
+
438
+ // Collection card hover effects
439
+ const collectionCards = document.querySelectorAll('.collection-card');
440
+
441
+ collectionCards.forEach(card => {
442
+ card.addEventListener('mouseenter', function() {
443
+ this.style.transform = 'translateY(-8px)';
444
+ });
445
+
446
+ card.addEventListener('mouseleave', function() {
447
+ this.style.transform = 'translateY(0)';
448
+ });
449
+ });
450
+ });
451
+ </script>
452
+