@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,601 @@
1
+ {% layout 'layout/theme' %}
2
+
3
+ <section class="account-page">
4
+ <div class="container">
5
+
6
+ <!-- Page Header -->
7
+ <header class="account-header">
8
+ <h1 class="account-title">My Subscriptions</h1>
9
+ <p class="account-subtitle">Manage your active and stopped subscriptions</p>
10
+ </header>
11
+
12
+ <div class="account-layout">
13
+
14
+ <!-- Sidebar -->
15
+ <aside class="account-sidebar">
16
+ {% render 'snippets/account-sidebar' %}
17
+ </aside>
18
+
19
+ <!-- Subscriptions Content -->
20
+ <main class="account-content">
21
+ <div class="account-section-header">
22
+ <h2 class="account-section-title">Subscription History</h2>
23
+ </div>
24
+
25
+ <div class="orders-list">
26
+ {% assign subscriptions = orders.subscriptions | default: subscriptions %}
27
+
28
+ {% if subscriptions and subscriptions.size > 0 %}
29
+ {% for sub in subscriptions %}
30
+ <article class="order-card">
31
+
32
+ <!-- LEFT -->
33
+ <div class="order-card-left">
34
+ <h3 class="order-number">
35
+ {{ sub.productName }}
36
+ </h3>
37
+
38
+ <div class="order-meta">
39
+ <span>
40
+ {{ sub.createdOn | date: "%d-%m-%Y" }}
41
+ </span>
42
+ </div>
43
+ </div>
44
+
45
+ <!-- CENTER -->
46
+ <div class="order-card-center">
47
+ <span class="status-badge status-{{ sub.status | downcase }}">
48
+ {{ sub.status }}
49
+ </span>
50
+ </div>
51
+
52
+ <!-- RIGHT -->
53
+ <div class="order-card-right">
54
+ <button
55
+ class="btn btn-sm btn-outline"
56
+ data-frequency="{{ sub.frequency | escape }}"
57
+ data-product-name="{{ sub.productName | escape }}"
58
+ onclick="openFrequencyModal(this)"
59
+ >
60
+ View Details
61
+ </button>
62
+ </div>
63
+
64
+ </article>
65
+ {% endfor %}
66
+ {% else %}
67
+ <div class="empty-state">
68
+ <h3>No subscriptions found</h3>
69
+ <p>You don't have any subscriptions yet.</p>
70
+ </div>
71
+ {% endif %}
72
+ <!-- Pagination -->
73
+ {% include 'snippets/pagination', pagination: pagination %}
74
+ </div>
75
+
76
+ </main>
77
+
78
+ </div>
79
+ </div>
80
+ </section>
81
+
82
+ <!-- Frequency Modal -->
83
+ <div id="frequencyModal" class="modal">
84
+ <div class="modal-overlay" onclick="closeFrequencyModal()"></div>
85
+ <div class="modal-content">
86
+ <div class="modal-header">
87
+ <h2 class="modal-title">Subscription Frequency Details</h2>
88
+ <button class="modal-close" onclick="closeFrequencyModal()">&times;</button>
89
+ </div>
90
+ <div class="modal-body">
91
+ <h3 id="modalProductName" class="product-name"></h3>
92
+ <div class="frequency-grid">
93
+ <div class="frequency-item">
94
+ <span class="frequency-label">Frequency Type:</span>
95
+ <span id="freqType" class="frequency-value">-</span>
96
+ </div>
97
+ <div class="frequency-item">
98
+ <span class="frequency-label">Start Date:</span>
99
+ <span id="startDate" class="frequency-value">-</span>
100
+ </div>
101
+ <div class="frequency-item">
102
+ <span class="frequency-label">End Date:</span>
103
+ <span id="endDate" class="frequency-value">-</span>
104
+ </div>
105
+ <div class="frequency-item">
106
+ <span class="frequency-label">Time:</span>
107
+ <span id="timeFre" class="frequency-value">-</span>
108
+ </div>
109
+ <div class="frequency-item">
110
+ <span class="frequency-label">Orders Count:</span>
111
+ <span id="ordersCount" class="frequency-value">-</span>
112
+ </div>
113
+ <div class="frequency-item" id="dayFreItem" style="display: none;">
114
+ <span class="frequency-label">Day Frequency:</span>
115
+ <span id="dayFre" class="frequency-value">-</span>
116
+ </div>
117
+ <div class="frequency-item" id="weeklyItem" style="display: none;">
118
+ <span class="frequency-label">Weekly Days:</span>
119
+ <span id="weeklyDays" class="frequency-value">-</span>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <style>
127
+ /* Account subscriptions page uses theme.css variables - no local :root needed */
128
+
129
+ .account-page {
130
+ background: var(--bg);
131
+ padding: 3rem 1rem;
132
+ min-height: 100vh;
133
+ }
134
+ .container {
135
+ max-width: var(--container-width);
136
+ margin: 0 auto;
137
+ padding: 0 var(--spacing-small);
138
+ }
139
+ .pagination {
140
+ display: flex;
141
+ justify-content: flex-end;
142
+ align-items: center;
143
+ }
144
+ .account-header {
145
+ text-align: center;
146
+ margin-bottom: 3rem;
147
+ }
148
+
149
+ .account-title {
150
+ font-size: 2.5rem;
151
+ font-weight: 700;
152
+ margin-bottom: 0.5rem;
153
+ }
154
+
155
+ .account-subtitle {
156
+ color: var(--muted);
157
+ font-size: 1rem;
158
+ }
159
+
160
+ .account-layout {
161
+ display: grid;
162
+ grid-template-columns: 280px 1fr;
163
+ gap: 2rem;
164
+ }
165
+
166
+ .account-sidebar,
167
+ .account-content {
168
+ background: var(--card);
169
+ border-radius: var(--radius);
170
+ border: 1px solid var(--border);
171
+ box-shadow: var(--shadow);
172
+ }
173
+
174
+ .account-content {
175
+ padding: 2rem;
176
+ }
177
+
178
+ .account-section-title {
179
+ font-size: 1.8rem;
180
+ font-weight: 600;
181
+ margin-bottom: 0;
182
+ }
183
+
184
+ .orders-list {
185
+ display: flex;
186
+ flex-direction: column;
187
+ gap: 1.2rem;
188
+ margin-top: 1.5rem;
189
+ }
190
+
191
+ .order-card {
192
+ display: grid;
193
+ grid-template-columns: 2fr 1fr 1fr;
194
+ gap: 1.5rem;
195
+ align-items: center;
196
+ padding: 1.4rem 1.6rem;
197
+ border-radius: var(--radius);
198
+ border: 1px solid var(--border);
199
+ transition: all .25s ease;
200
+ }
201
+
202
+ .order-card:hover {
203
+ transform: translateY(-2px);
204
+ box-shadow: var(--shadow);
205
+ }
206
+
207
+ .order-card-left {
208
+ min-width: 0;
209
+ }
210
+
211
+ .order-number {
212
+ font-size: 1.4rem;
213
+ margin-bottom: .3rem;
214
+ font-weight: 600;
215
+ overflow: hidden;
216
+ text-overflow: ellipsis;
217
+ white-space: nowrap;
218
+ }
219
+
220
+ .order-meta {
221
+ font-size: .9rem;
222
+ color: var(--muted);
223
+ display: flex;
224
+ gap: 1rem;
225
+ flex-wrap: wrap;
226
+ }
227
+
228
+ .order-card-center {
229
+ display: flex;
230
+ justify-content: center;
231
+ }
232
+
233
+ .status-badge {
234
+ padding: .4rem .9rem;
235
+ border-radius: 999px;
236
+ font-size: 1.4rem;
237
+ font-weight: 600;
238
+ white-space: nowrap;
239
+ display: inline-block;
240
+ }
241
+
242
+ .status-active,
243
+ .status-completed {
244
+ background: var(--success-bg);
245
+ color: var(--success-text);
246
+ }
247
+
248
+ .status-pending {
249
+ background: var(--warning-bg);
250
+ color: var(--warning-text);
251
+ }
252
+
253
+ .status-cancelled,
254
+ .status-failed,
255
+ .status-stopped {
256
+ background: var(--danger-bg);
257
+ color: var(--danger-text);
258
+ }
259
+
260
+ .order-card-right {
261
+ display: flex;
262
+ justify-content: flex-end;
263
+ }
264
+
265
+ .btn {
266
+ padding: .5rem 1rem;
267
+ border-radius: 8px;
268
+ border: 1px solid var(--border);
269
+ background: white;
270
+ color: var(--text);
271
+ text-decoration: none;
272
+ font-size: 1.4rem;
273
+ cursor: pointer;
274
+ transition: all .2s ease;
275
+ white-space: nowrap;
276
+ }
277
+
278
+ .btn-outline:hover {
279
+ background: var(--primary);
280
+ color: #fff;
281
+ border-color: var(--primary);
282
+ }
283
+
284
+ .empty-state {
285
+ text-align: center;
286
+ padding: 4rem 1rem;
287
+ }
288
+
289
+ .empty-state h3 {
290
+ font-size: 1.5rem;
291
+ margin-bottom: 0.5rem;
292
+ }
293
+
294
+ .empty-state p {
295
+ color: var(--muted);
296
+ }
297
+
298
+ /* Modal Styles */
299
+ .modal {
300
+ display: none;
301
+ position: fixed;
302
+ top: 0;
303
+ left: 0;
304
+ right: 0;
305
+ bottom: 0;
306
+ z-index: 1000;
307
+ align-items: center;
308
+ justify-content: center;
309
+ padding: 1rem;
310
+ }
311
+
312
+ .modal.active {
313
+ display: flex;
314
+ }
315
+
316
+ .modal-overlay {
317
+ position: fixed;
318
+ top: 0;
319
+ left: 0;
320
+ right: 0;
321
+ bottom: 0;
322
+ background: rgba(0, 0, 0, 0.5);
323
+ backdrop-filter: blur(4px);
324
+ }
325
+
326
+ .modal-content {
327
+ position: relative;
328
+ background: var(--card);
329
+ border-radius: var(--radius);
330
+ box-shadow: 0 20px 60px rgba(0,0,0,.3);
331
+ max-width: 600px;
332
+ width: 100%;
333
+ max-height: 90vh;
334
+ overflow-y: auto;
335
+ animation: modalSlideIn .3s ease;
336
+ }
337
+
338
+ @keyframes modalSlideIn {
339
+ from {
340
+ opacity: 0;
341
+ transform: translateY(-20px);
342
+ }
343
+ to {
344
+ opacity: 1;
345
+ transform: translateY(0);
346
+ }
347
+ }
348
+
349
+ .modal-header {
350
+ display: flex;
351
+ justify-content: space-between;
352
+ align-items: center;
353
+ padding: 1.5rem;
354
+ border-bottom: 1px solid var(--border);
355
+ }
356
+
357
+ .modal-title {
358
+ font-size: 1.5rem;
359
+ font-weight: 600;
360
+ margin: 0;
361
+ }
362
+
363
+ .modal-close {
364
+ background: none;
365
+ border: none;
366
+ font-size: 2rem;
367
+ color: var(--muted);
368
+ cursor: pointer;
369
+ padding: 0;
370
+ width: 2rem;
371
+ height: 2rem;
372
+ display: flex;
373
+ align-items: center;
374
+ justify-content: center;
375
+ border-radius: 4px;
376
+ transition: all .2s ease;
377
+ }
378
+
379
+ .modal-close:hover {
380
+ background: var(--border);
381
+ color: var(--text);
382
+ }
383
+
384
+ .modal-body {
385
+ padding: 1.5rem;
386
+ }
387
+
388
+ .product-name {
389
+ font-size: 1.2rem;
390
+ font-weight: 600;
391
+ margin-bottom: 1.5rem;
392
+ color: var(--primary);
393
+ }
394
+
395
+ .frequency-grid {
396
+ display: grid;
397
+ gap: 1rem;
398
+ }
399
+
400
+ .frequency-item {
401
+ display: grid;
402
+ grid-template-columns: 140px 1fr;
403
+ gap: 1rem;
404
+ padding: 0.75rem;
405
+ background: var(--bg);
406
+ border-radius: 8px;
407
+ align-items: center;
408
+ }
409
+
410
+ .frequency-label {
411
+ font-weight: 600;
412
+ color: var(--text);
413
+ font-size: 1.4rem;
414
+ }
415
+
416
+ .frequency-value {
417
+ color: var(--muted);
418
+ font-size: 1.4rem;
419
+ }
420
+
421
+ /* Tablet Styles */
422
+ @media (max-width: 1024px) {
423
+ .account-layout {
424
+ grid-template-columns: 1fr;
425
+ }
426
+
427
+
428
+
429
+ .account-content {
430
+ order: 1;
431
+ }
432
+ }
433
+
434
+ /* Mobile Styles */
435
+ @media (max-width: 768px) {
436
+ .account-page {
437
+ padding: 2rem 1rem;
438
+ }
439
+
440
+ .account-title {
441
+ font-size: 2rem;
442
+ }
443
+
444
+ .account-content {
445
+ padding: 1.5rem;
446
+ }
447
+
448
+ .order-card {
449
+ padding: 1.2rem;
450
+ }
451
+
452
+ .order-card-center {
453
+ justify-content: flex-start;
454
+ }
455
+
456
+ .order-card-right {
457
+ justify-content: flex-start;
458
+ }
459
+
460
+ .btn {
461
+ width: 100%;
462
+ text-align: center;
463
+ }
464
+
465
+ .modal-content {
466
+ max-height: 85vh;
467
+ }
468
+
469
+ .modal-header {
470
+ padding: 1.25rem;
471
+ }
472
+
473
+ .modal-body {
474
+ padding: 1.25rem;
475
+ }
476
+
477
+ .frequency-item {
478
+ grid-template-columns: 1fr;
479
+ gap: 0.5rem;
480
+ }
481
+
482
+ .frequency-label {
483
+ font-size: 1.4rem;
484
+ }
485
+
486
+ .frequency-value {
487
+ font-size: 1.4rem;
488
+ font-weight: 500;
489
+ }
490
+ }
491
+
492
+ @media (max-width: 480px) {
493
+ .account-title {
494
+ font-size: 1.75rem;
495
+ }
496
+
497
+ .account-subtitle {
498
+ font-size: 0.9rem;
499
+ }
500
+
501
+ .account-section-title {
502
+ font-size: 1.5rem;
503
+ }
504
+
505
+ .order-number {
506
+ font-size: 1.4rem;
507
+ }
508
+
509
+ .order-meta {
510
+ font-size: 1.3rem;
511
+ }
512
+
513
+ .modal-title {
514
+ font-size: 1.25rem;
515
+ }
516
+
517
+ .product-name {
518
+ font-size: 1.5rem;
519
+ }
520
+ }
521
+ </style>
522
+
523
+ <script>
524
+ function openFrequencyModal(button) {
525
+ const modal = document.getElementById('frequencyModal');
526
+ const productNameEl = document.getElementById('modalProductName');
527
+
528
+ const frequencyStr = button.getAttribute('data-frequency');
529
+ const productName = button.getAttribute('data-product-name');
530
+
531
+ productNameEl.textContent = productName;
532
+
533
+ try {
534
+ const freq = JSON.parse(frequencyStr);
535
+
536
+ // Determine frequency type
537
+ let freqType = 'Unknown';
538
+ if (freq.isDailyFrequency) freqType = 'Daily';
539
+ else if (freq.isWeeklyFrequency) freqType = 'Weekly';
540
+ else if (freq.isMonthlyFrequency) freqType = 'Monthly';
541
+ else if (freq.isYearlyFrequency) freqType = 'Yearly';
542
+ else if (freq.isAlterNativeFrequency) freqType = 'Alternative';
543
+
544
+ document.getElementById('freqType').textContent = freqType;
545
+
546
+ // Format dates
547
+ const startDate = freq.startDate ? new Date(freq.startDate).toLocaleDateString() : 'Not set';
548
+ const endDate = freq.endDate ? new Date(freq.endDate).toLocaleDateString() : 'Not set';
549
+
550
+ document.getElementById('startDate').textContent = startDate;
551
+ document.getElementById('endDate').textContent = endDate;
552
+
553
+ // Format time
554
+ const time = freq.timeFre ? new Date(freq.timeFre).toLocaleTimeString() : 'Not set';
555
+ document.getElementById('timeFre').textContent = time;
556
+
557
+ // Orders count
558
+ document.getElementById('ordersCount').textContent = freq.ordersCount || 0;
559
+
560
+ // Day frequency
561
+ const dayFreItem = document.getElementById('dayFreItem');
562
+ if (freq.dayFre && freq.dayFre > 0) {
563
+ dayFreItem.style.display = 'grid';
564
+ document.getElementById('dayFre').textContent = `Every ${freq.dayFre} day(s)`;
565
+ } else {
566
+ dayFreItem.style.display = 'none';
567
+ }
568
+
569
+ // Weekly days
570
+ const weeklyItem = document.getElementById('weeklyItem');
571
+ if (freq.weeklyFreVals && freq.weeklyFreVals.length > 0) {
572
+ weeklyItem.style.display = 'grid';
573
+ const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
574
+ const selectedDays = freq.weeklyFreVals.map(d => days[d] || d).join(', ');
575
+ document.getElementById('weeklyDays').textContent = selectedDays;
576
+ } else {
577
+ weeklyItem.style.display = 'none';
578
+ }
579
+
580
+ } catch (e) {
581
+ console.error('Error parsing frequency:', e);
582
+ document.getElementById('freqType').textContent = 'Error loading data';
583
+ }
584
+
585
+ modal.classList.add('active');
586
+ document.body.style.overflow = 'hidden';
587
+ }
588
+
589
+ function closeFrequencyModal() {
590
+ const modal = document.getElementById('frequencyModal');
591
+ modal.classList.remove('active');
592
+ document.body.style.overflow = '';
593
+ }
594
+
595
+ // Close modal on Escape key
596
+ document.addEventListener('keydown', function(e) {
597
+ if (e.key === 'Escape') {
598
+ closeFrequencyModal();
599
+ }
600
+ });
601
+ </script>