@o2vend/theme-cli 1.0.36 → 1.0.37

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 CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  The O2VEND Theme CLI is a complete development environment for creating, testing, and packaging O2VEND themes. It works independently and doesn't require access to the main O2VEND webstore solution.
6
6
 
7
+ ## Prerequisites
8
+
9
+ - **Node.js 24.0 or later** is required. Download from [nodejs.org](https://nodejs.org/).
10
+
7
11
  ## Installation
8
12
 
9
13
  Install globally via npm:
@@ -137,7 +137,7 @@ class DevServer {
137
137
  // Only process if it contains actual Liquid variables, not just comments
138
138
  if (cssContent.includes('{{') && cssContent.includes('settings.')) {
139
139
  try {
140
- const settings = this.loadThemeSettings();
140
+ const settings = { ...this.loadThemeSettings(), ...(this._realStoreSettings || {}) };
141
141
  const processedCss = await this.liquid.parseAndRender(cssContent, { settings });
142
142
  res.setHeader('Content-Type', 'text/css; charset=utf-8');
143
143
  res.setHeader('Cache-Control', 'no-cache');
@@ -2079,6 +2079,9 @@ class DevServer {
2079
2079
  const favicon = (storeInfo && storeInfo.favouriteIconUrl) ? storeInfo.favouriteIconUrl : '/favicon.ico';
2080
2080
  const storeName = (storeInfo && storeInfo.name) ? storeInfo.name : 'Store';
2081
2081
  const storeSettings = (storeInfo && storeInfo.settings) || {};
2082
+ if (Object.keys(storeSettings).length > 0) {
2083
+ this._realStoreSettings = storeSettings;
2084
+ }
2082
2085
  try {
2083
2086
  context.shop = {
2084
2087
  name: storeName,
@@ -2118,7 +2121,8 @@ class DevServer {
2118
2121
  context.settings.layout_style = 'full-width';
2119
2122
  }
2120
2123
 
2121
- const page = pageType === 'home' ? 'home' : (pageType === 'products' ? 'products' : 'home');
2124
+ const pageIdMap = { home: 'home', product: 'product', collection: 'category', category: 'category', products: 'products', categories: 'categories', brand: 'brand', checkout: 'checkout', page: 'home' };
2125
+ const page = pageIdMap[pageType] || 'home';
2122
2126
  context.widgets = await webstoreApi.fetchWidgetsBySections(page, webstoreApi.DEFAULT_SECTIONS, opts);
2123
2127
  context.widgets = context.widgets || { hero: [], products: [], footer: [], content: [], header: [] };
2124
2128
 
@@ -2467,35 +2471,58 @@ class DevServer {
2467
2471
  normalizeProductForRealMode(p) {
2468
2472
  if (!p || typeof p !== 'object') return p;
2469
2473
  const n = { ...p };
2474
+ const apiBase = (process.env.O2VEND_API_BASE_URL || '').replace(/\/$/, '');
2475
+
2470
2476
  if (n.Description != null && n.description == null) n.description = n.Description;
2471
2477
  if (n.HtmlContent != null && n.htmlContent == null) n.htmlContent = n.HtmlContent;
2472
2478
  if (n.ShortDescription != null && n.shortDescription == null) n.shortDescription = n.ShortDescription;
2473
2479
  if (n.Name != null && n.name == null) n.name = n.Name;
2474
2480
  if (n.Title != null && n.title == null) n.title = n.Title;
2475
2481
  if (n.Attributes != null && n.attributes == null) n.attributes = n.Attributes;
2482
+ if (n.Variations != null && n.variations == null) n.variations = n.Variations;
2483
+ if (n.Combinations != null && n.combinations == null) n.combinations = n.Combinations;
2484
+ if (n.Subscriptions != null && n.subscriptions == null) n.subscriptions = n.Subscriptions;
2485
+ if (n.ProductType != null && n.productType == null) n.productType = n.ProductType;
2486
+
2487
+ const resolveImageUrl = (u) => {
2488
+ if (!u || typeof u !== 'string') return u;
2489
+ if (u.startsWith('http://') || u.startsWith('https://') || u.startsWith('//')) return u;
2490
+ if (u.startsWith('/') && apiBase) return apiBase + u;
2491
+ return u;
2492
+ };
2476
2493
 
2477
- const t1 = n.ThumbnailImage1 || n.thumbnailImage || n.thumbnailImage;
2494
+ const extractUrl = (obj) => {
2495
+ if (!obj) return null;
2496
+ if (typeof obj === 'string') return obj;
2497
+ return obj.url || obj.Url || obj.imageUrl || obj.ImageUrl || obj.fileName || obj.FileName || obj.filePath || obj.FilePath || obj.imagePath || obj.ImagePath || null;
2498
+ };
2499
+
2500
+ const t1 = n.ThumbnailImage1 || n.thumbnailImage1 || n.thumbnailImage;
2478
2501
  if (t1 != null) {
2479
- const u = typeof t1 === 'string' ? t1 : (t1.url || t1.Url || t1.imageUrl || t1.ImageUrl);
2502
+ const u = resolveImageUrl(extractUrl(t1));
2480
2503
  if (u) {
2481
2504
  n.thumbnailImage = u;
2482
2505
  if (!n.imageUrl) n.imageUrl = u;
2483
2506
  }
2484
2507
  }
2485
2508
 
2486
- let imgs = n.images || n.Images;
2509
+ let imgs = n.images || n.Images || n.ProductImages || n.productImages;
2487
2510
  if (Array.isArray(imgs) && imgs.length > 0) {
2488
2511
  n.images = imgs.map((img) => {
2489
- if (typeof img === 'string') return { url: img, altText: n.name || n.title };
2490
- const u = img.url || img.Url || img.imageUrl || img.ImageUrl;
2491
- const a = img.altText || img.AltText || n.name || n.title;
2512
+ const u = resolveImageUrl(typeof img === 'string' ? img : extractUrl(img));
2513
+ const a = (typeof img === 'object' ? (img.altText || img.AltText) : null) || n.name || n.title;
2492
2514
  return { url: u || '', altText: a };
2493
2515
  });
2494
2516
  } else {
2495
- const single = n.imageUrl || n.ImageUrl;
2517
+ const single = resolveImageUrl(n.imageUrl || n.ImageUrl);
2496
2518
  if (single) n.images = [{ url: single, altText: n.name || n.title }];
2497
2519
  }
2498
2520
 
2521
+ if (n.images && n.images.length > 0) {
2522
+ n.featured_image = n.images[0];
2523
+ if (!n.imageUrl) n.imageUrl = n.images[0].url;
2524
+ }
2525
+
2499
2526
  const handle = (n.handle || n.slug || n.id || '').toString().trim();
2500
2527
  const h = handle && handle !== '#' ? handle.toLowerCase() : (n.productId ? String(n.productId) : null);
2501
2528
  if (h) {
@@ -374,6 +374,222 @@ function generateMockProducts(count = 20) {
374
374
  });
375
375
  }
376
376
 
377
+ // Variation product with production-style options structure
378
+ const variationProductId = products.length + 1;
379
+ const variationVariants = [
380
+ {
381
+ id: `variant-var-1`, productId: variationProductId * 1000 + 1, name: 'Wireless Headphones - Black / Standard',
382
+ sku: 'WH-BLK-STD', title: 'Black / Standard',
383
+ prices: { price: 7999, mrp: 9999 }, price: 7999, compareAtPrice: 9999,
384
+ options: [
385
+ { id: 1, optionId: 1, optionName: 'Color', value: 'Black', displayType: 'color', displayValue: '#000000', sortIndex: 1 },
386
+ { id: 2, optionId: 2, optionName: 'Edition', value: 'Standard', displayType: 'text', displayValue: '', sortIndex: 1 }
387
+ ],
388
+ images: [{ url: 'https://picsum.photos/seed/wh-black/800/800', altText: 'Wireless Headphones Black' }],
389
+ inStock: true, available: true, stockQuantity: 25
390
+ },
391
+ {
392
+ id: `variant-var-2`, productId: variationProductId * 1000 + 2, name: 'Wireless Headphones - Black / Pro',
393
+ sku: 'WH-BLK-PRO', title: 'Black / Pro',
394
+ prices: { price: 11999, mrp: 14999 }, price: 11999, compareAtPrice: 14999,
395
+ options: [
396
+ { id: 3, optionId: 1, optionName: 'Color', value: 'Black', displayType: 'color', displayValue: '#000000', sortIndex: 1 },
397
+ { id: 4, optionId: 2, optionName: 'Edition', value: 'Pro', displayType: 'text', displayValue: '', sortIndex: 2 }
398
+ ],
399
+ images: [{ url: 'https://picsum.photos/seed/wh-black-pro/800/800', altText: 'Wireless Headphones Black Pro' }],
400
+ inStock: true, available: true, stockQuantity: 15
401
+ },
402
+ {
403
+ id: `variant-var-3`, productId: variationProductId * 1000 + 3, name: 'Wireless Headphones - White / Standard',
404
+ sku: 'WH-WHT-STD', title: 'White / Standard',
405
+ prices: { price: 7999, mrp: 9999 }, price: 7999, compareAtPrice: 9999,
406
+ options: [
407
+ { id: 5, optionId: 1, optionName: 'Color', value: 'White', displayType: 'color', displayValue: '#ffffff', sortIndex: 2 },
408
+ { id: 6, optionId: 2, optionName: 'Edition', value: 'Standard', displayType: 'text', displayValue: '', sortIndex: 1 }
409
+ ],
410
+ images: [{ url: 'https://picsum.photos/seed/wh-white/800/800', altText: 'Wireless Headphones White' }],
411
+ inStock: true, available: true, stockQuantity: 20
412
+ },
413
+ {
414
+ id: `variant-var-4`, productId: variationProductId * 1000 + 4, name: 'Wireless Headphones - Silver / Pro',
415
+ sku: 'WH-SLV-PRO', title: 'Silver / Pro',
416
+ prices: { price: 12999, mrp: 15999 }, price: 12999, compareAtPrice: 15999,
417
+ options: [
418
+ { id: 7, optionId: 1, optionName: 'Color', value: 'Silver', displayType: 'color', displayValue: '#c0c0c0', sortIndex: 3 },
419
+ { id: 8, optionId: 2, optionName: 'Edition', value: 'Pro', displayType: 'text', displayValue: '', sortIndex: 2 }
420
+ ],
421
+ images: [{ url: 'https://picsum.photos/seed/wh-silver-pro/800/800', altText: 'Wireless Headphones Silver Pro' }],
422
+ inStock: false, available: false, stockQuantity: 0
423
+ }
424
+ ];
425
+ products.push({
426
+ id: variationProductId, productId: variationProductId,
427
+ title: 'Wireless Noise-Cancelling Headphones', name: 'Wireless Noise-Cancelling Headphones',
428
+ handle: 'wireless-noise-cancelling-headphones', slug: 'wireless-noise-cancelling-headphones',
429
+ url: 'wireless-noise-cancelling-headphones', link: 'wireless-noise-cancelling-headphones',
430
+ description: 'Premium wireless headphones with active noise cancellation. Available in multiple colors and editions.',
431
+ price: 7999, compareAtPrice: 9999, prices: { price: 7999, mrp: 9999 },
432
+ inStock: true, available: true, stockQuantity: 60, stockTrackingIsEnabled: true, isAllowToOrder: false,
433
+ sku: 'WH-MAIN', categoryId: 1, category: { id: 1, name: 'Electronics' }, brandId: 1,
434
+ thumbnailImage: 'https://picsum.photos/seed/wh-main/800/800',
435
+ imageUrl: 'https://picsum.photos/seed/wh-main/800/800',
436
+ images: [
437
+ { id: 'img-var-1', url: 'https://picsum.photos/seed/wh-main/800/800', altText: 'Wireless Headphones' },
438
+ { id: 'img-var-2', url: 'https://picsum.photos/seed/wh-side/800/800', altText: 'Wireless Headphones Side View' },
439
+ { id: 'img-var-3', url: 'https://picsum.photos/seed/wh-case/800/800', altText: 'Wireless Headphones with Case' }
440
+ ],
441
+ variants: variationVariants, variations: variationVariants,
442
+ options: [
443
+ { name: 'Color', values: ['Black', 'White', 'Silver'] },
444
+ { name: 'Edition', values: ['Standard', 'Pro'] }
445
+ ],
446
+ tags: ['featured', 'electronics', 'audio'], productType: 0, additionalData: 'null',
447
+ combinations: [], subscriptions: [], shippingMethods: [],
448
+ createdAt: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString()
449
+ });
450
+
451
+ // Combination product with group-based add-ons
452
+ const comboProductId = products.length + 1;
453
+ products.push({
454
+ id: comboProductId, productId: comboProductId,
455
+ title: 'Gaming Console Bundle', name: 'Gaming Console Bundle',
456
+ handle: 'gaming-console-bundle', slug: 'gaming-console-bundle',
457
+ url: 'gaming-console-bundle', link: 'gaming-console-bundle',
458
+ description: 'Next-gen gaming console with customizable accessories bundle. Choose your controller, headset, and games.',
459
+ price: 49999, compareAtPrice: 59999, prices: { price: 49999, mrp: 59999 },
460
+ inStock: true, available: true, stockQuantity: 30, stockTrackingIsEnabled: true, isAllowToOrder: false,
461
+ sku: 'GCB-MAIN', categoryId: 1, category: { id: 1, name: 'Electronics' }, brandId: 2,
462
+ thumbnailImage: 'https://picsum.photos/seed/gcb-main/800/800',
463
+ imageUrl: 'https://picsum.photos/seed/gcb-main/800/800',
464
+ images: [
465
+ { id: 'img-combo-1', url: 'https://picsum.photos/seed/gcb-main/800/800', altText: 'Gaming Console Bundle' },
466
+ { id: 'img-combo-2', url: 'https://picsum.photos/seed/gcb-box/800/800', altText: 'Gaming Console Box Contents' }
467
+ ],
468
+ variants: [{ id: 'variant-combo-1', productId: comboProductId * 1000 + 1, title: 'Default', price: 49999, compareAtPrice: 59999, prices: { price: 49999, mrp: 59999 }, sku: 'GCB-DEF', inStock: true, available: true, stockQuantity: 30 }],
469
+ variations: [],
470
+ options: [],
471
+ combinations: [
472
+ {
473
+ productId: comboProductId * 100 + 1, name: 'Extra Wireless Controller', sku: 'GCB-CTRL',
474
+ prices: { price: 5999, mrp: 6999 }, quantity: 1,
475
+ group: { groupDetail: { groupName: 'Controllers', groupType: 1, minimumSelectable: 0, maximumSelectable: 2, isOptional: true } },
476
+ thumbnailImage1: { url: 'https://picsum.photos/seed/gcb-ctrl/200/200' },
477
+ images: [{ url: 'https://picsum.photos/seed/gcb-ctrl/400/400' }],
478
+ additionalData: null
479
+ },
480
+ {
481
+ productId: comboProductId * 100 + 2, name: 'Pro Controller (Elite)', sku: 'GCB-CTRL-PRO',
482
+ prices: { price: 12999, mrp: 14999 }, quantity: 1,
483
+ group: { groupDetail: { groupName: 'Controllers', groupType: 1, minimumSelectable: 0, maximumSelectable: 2, isOptional: true } },
484
+ thumbnailImage1: { url: 'https://picsum.photos/seed/gcb-ctrl-pro/200/200' },
485
+ images: [{ url: 'https://picsum.photos/seed/gcb-ctrl-pro/400/400' }],
486
+ additionalData: null
487
+ },
488
+ {
489
+ productId: comboProductId * 100 + 3, name: 'Gaming Headset 7.1', sku: 'GCB-HS',
490
+ prices: { price: 7999, mrp: 9999 }, quantity: 1,
491
+ group: { groupDetail: { groupName: 'Audio', groupType: 1, minimumSelectable: 1, maximumSelectable: 1, isOptional: false } },
492
+ thumbnailImage1: { url: 'https://picsum.photos/seed/gcb-headset/200/200' },
493
+ images: [{ url: 'https://picsum.photos/seed/gcb-headset/400/400' }],
494
+ additionalData: null
495
+ },
496
+ {
497
+ productId: comboProductId * 100 + 4, name: 'Racing Game Deluxe', sku: 'GCB-GAME1',
498
+ prices: { price: 3999, mrp: 4999 }, quantity: 1,
499
+ group: { groupDetail: { groupName: 'Games', groupType: 1, minimumSelectable: 1, maximumSelectable: 3, isOptional: false } },
500
+ thumbnailImage1: { url: 'https://picsum.photos/seed/gcb-game1/200/200' },
501
+ images: [{ url: 'https://picsum.photos/seed/gcb-game1/400/400' }],
502
+ additionalData: null
503
+ },
504
+ {
505
+ productId: comboProductId * 100 + 5, name: 'Adventure Quest RPG', sku: 'GCB-GAME2',
506
+ prices: { price: 4999, mrp: 5999 }, quantity: 1,
507
+ group: { groupDetail: { groupName: 'Games', groupType: 1, minimumSelectable: 1, maximumSelectable: 3, isOptional: false } },
508
+ thumbnailImage1: { url: 'https://picsum.photos/seed/gcb-game2/200/200' },
509
+ images: [{ url: 'https://picsum.photos/seed/gcb-game2/400/400' }],
510
+ additionalData: null
511
+ }
512
+ ],
513
+ subscriptions: [],
514
+ tags: ['featured', 'electronics', 'gaming', 'bundle'], productType: 0,
515
+ additionalData: 'null', shippingMethods: [],
516
+ createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString()
517
+ });
518
+
519
+ // Subscription product
520
+ const subProductId = products.length + 1;
521
+ const subscriptionAdditionalData = JSON.stringify({
522
+ settings: {
523
+ isScheduleByCustomer: true, typeOfOrder: 10, shippingClassId: 1,
524
+ perOrderPrice: 1999, startDate: new Date().toISOString(),
525
+ endDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
526
+ isProductChoiceEnabled: false, isQuantityChangeAllowed: true,
527
+ minSubscriptionProducts: 1, maxSubscriptionProducts: 5
528
+ },
529
+ subscriptionDetails: {
530
+ shippingFeeAmount: 0, paymentFeeAmount: 0, roundOff: 0,
531
+ discountAmount: 500, subscriptionCoupon: null, orderTotal: '1999'
532
+ },
533
+ frequency: { selectedOption: 'monthly', timeFre: '', ordersCount: 12 },
534
+ frequencyData: {
535
+ selectedOption: 'monthly', ordersCount: 12,
536
+ startDate: new Date().toISOString(),
537
+ endDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
538
+ isDailyFrequency: true, isWeeklyFrequency: true,
539
+ isAlterNativeFrequency: false, isMonthlyFrequency: true, isYearlyFrequency: false
540
+ },
541
+ IsSubscriptionPrice: true,
542
+ items: [
543
+ { Id: 1, Name: 'Organic Coffee Blend - 250g', Price: 1999, Quantity: 1 },
544
+ { Id: 2, Name: 'Single Origin Ethiopian - 250g', Price: 2499, Quantity: 1 },
545
+ { Id: 3, Name: 'Dark Roast Espresso - 250g', Price: 1799, Quantity: 1 }
546
+ ]
547
+ });
548
+ products.push({
549
+ id: subProductId, productId: subProductId,
550
+ title: 'Premium Coffee Subscription Box', name: 'Premium Coffee Subscription Box',
551
+ handle: 'premium-coffee-subscription', slug: 'premium-coffee-subscription',
552
+ url: 'premium-coffee-subscription', link: 'premium-coffee-subscription',
553
+ description: 'Get freshly roasted premium coffee delivered to your door. Choose your frequency and customize your selection.',
554
+ price: 1999, compareAtPrice: 2499, prices: { price: 1999, mrp: 2499 },
555
+ inStock: true, available: true, stockQuantity: 999, stockTrackingIsEnabled: false, isAllowToOrder: true,
556
+ sku: 'SUB-COFFEE', categoryId: 10, category: { id: 10, name: 'Food & Beverages' }, brandId: 5,
557
+ thumbnailImage: 'https://picsum.photos/seed/sub-coffee/800/800',
558
+ imageUrl: 'https://picsum.photos/seed/sub-coffee/800/800',
559
+ images: [
560
+ { id: 'img-sub-1', url: 'https://picsum.photos/seed/sub-coffee/800/800', altText: 'Coffee Subscription Box' },
561
+ { id: 'img-sub-2', url: 'https://picsum.photos/seed/sub-beans/800/800', altText: 'Premium Coffee Beans' },
562
+ { id: 'img-sub-3', url: 'https://picsum.photos/seed/sub-cup/800/800', altText: 'Fresh Brewed Coffee' }
563
+ ],
564
+ variants: [{ id: 'variant-sub-1', productId: subProductId * 1000 + 1, title: 'Monthly Box', price: 1999, compareAtPrice: 2499, prices: { price: 1999, mrp: 2499 }, sku: 'SUB-COFFEE-M', inStock: true, available: true, stockQuantity: 999 }],
565
+ variations: [],
566
+ options: [],
567
+ combinations: [],
568
+ subscriptions: [
569
+ {
570
+ productId: subProductId * 100 + 1, name: 'Organic Coffee Blend - 250g', sku: 'SUB-BLEND',
571
+ prices: { price: 1999, mrp: 2499 }, quantity: 1,
572
+ specification: 'Premium organic blend, medium roast',
573
+ images: [{ url: 'https://picsum.photos/seed/sub-blend/400/400' }], additionalData: null
574
+ },
575
+ {
576
+ productId: subProductId * 100 + 2, name: 'Single Origin Ethiopian - 250g', sku: 'SUB-ETHIOP',
577
+ prices: { price: 2499, mrp: 2999 }, quantity: 1,
578
+ specification: 'Light roast, fruity notes',
579
+ images: [{ url: 'https://picsum.photos/seed/sub-ethiop/400/400' }], additionalData: null
580
+ },
581
+ {
582
+ productId: subProductId * 100 + 3, name: 'Dark Roast Espresso - 250g', sku: 'SUB-ESPRESSO',
583
+ prices: { price: 1799, mrp: 2199 }, quantity: 1,
584
+ specification: 'Bold and intense espresso blend',
585
+ images: [{ url: 'https://picsum.photos/seed/sub-espresso/400/400' }], additionalData: null
586
+ }
587
+ ],
588
+ tags: ['subscription', 'coffee', 'food'], productType: 90,
589
+ additionalData: subscriptionAdditionalData, shippingMethods: [],
590
+ createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString()
591
+ });
592
+
377
593
  // Log summary
378
594
  const productsWithVariations = products.filter(p => (p.variants?.length || 0) > 1).length;
379
595
  const productsWithOptions = products.filter(p => (p.options?.length || 0) > 0).length;
@@ -1120,7 +1336,8 @@ function generateMockWidgets() {
1120
1336
  Limit: 12,
1121
1337
  Columns: 4,
1122
1338
  Products: []
1123
- }
1339
+ },
1340
+ products: []
1124
1341
  },
1125
1342
  content: JSON.stringify({
1126
1343
  NumberOfProducts: 12,
@@ -1157,7 +1374,8 @@ function generateMockWidgets() {
1157
1374
  Columns: 3,
1158
1375
  IsFeatured: true,
1159
1376
  Products: []
1160
- }
1377
+ },
1378
+ products: []
1161
1379
  },
1162
1380
  content: JSON.stringify({
1163
1381
  NumberOfProducts: 6,
@@ -1271,7 +1489,8 @@ function generateMockWidgets() {
1271
1489
  show_add_to_cart: false
1272
1490
  },
1273
1491
  data: {
1274
- products: [] // Will be enriched by dev server
1492
+ products: [],
1493
+ content: { products: [], Products: [] }
1275
1494
  }
1276
1495
  },
1277
1496
 
@@ -1381,71 +1600,294 @@ function generateMockWidgets() {
1381
1600
  hideDot: false
1382
1601
  },
1383
1602
  data: {
1384
- content: [
1385
- {
1386
- Title: 'Amazing Quality!',
1387
- title: 'Amazing Quality!',
1388
- Description: 'I\'ve been shopping here for years and the quality never disappoints. Fast shipping and excellent customer service too!',
1389
- description: 'I\'ve been shopping here for years and the quality never disappoints. Fast shipping and excellent customer service too!',
1390
- PersonName: 'Sarah Johnson',
1391
- personName: 'Sarah Johnson',
1392
- CompanyName: 'Verified Buyer',
1393
- companyName: 'Verified Buyer',
1394
- Rating: 5,
1395
- rating: 5,
1396
- ImageUrl: 'https://picsum.photos/seed/user1/100/100',
1397
- imageUrl: 'https://picsum.photos/seed/user1/100/100'
1398
- },
1399
- {
1400
- Title: 'Great Experience',
1401
- title: 'Great Experience',
1402
- Description: 'The customer service team went above and beyond to help me find exactly what I needed. Highly recommend!',
1403
- description: 'The customer service team went above and beyond to help me find exactly what I needed. Highly recommend!',
1404
- PersonName: 'Michael Chen',
1405
- personName: 'Michael Chen',
1406
- CompanyName: 'Regular Customer',
1407
- companyName: 'Regular Customer',
1408
- Rating: 5,
1409
- rating: 5,
1410
- ImageUrl: 'https://picsum.photos/seed/user2/100/100',
1411
- imageUrl: 'https://picsum.photos/seed/user2/100/100'
1412
- },
1413
- {
1414
- Title: 'Will Shop Again',
1415
- title: 'Will Shop Again',
1416
- Description: 'Love the variety of products and the prices are very competitive. The website is easy to navigate too.',
1417
- description: 'Love the variety of products and the prices are very competitive. The website is easy to navigate too.',
1418
- PersonName: 'Emily Davis',
1419
- personName: 'Emily Davis',
1420
- CompanyName: 'Fashion Enthusiast',
1421
- companyName: 'Fashion Enthusiast',
1422
- Rating: 5,
1423
- rating: 5,
1424
- ImageUrl: 'https://picsum.photos/seed/user3/100/100',
1425
- imageUrl: 'https://picsum.photos/seed/user3/100/100'
1426
- },
1427
- {
1428
- Title: 'Fast Delivery',
1429
- title: 'Fast Delivery',
1430
- Description: 'Ordered on Monday, received on Wednesday! The packaging was perfect and the product exceeded expectations.',
1431
- description: 'Ordered on Monday, received on Wednesday! The packaging was perfect and the product exceeded expectations.',
1432
- PersonName: 'David Wilson',
1433
- personName: 'David Wilson',
1434
- CompanyName: 'Tech Reviewer',
1435
- companyName: 'Tech Reviewer',
1436
- Rating: 4,
1437
- rating: 4,
1438
- ImageUrl: 'https://picsum.photos/seed/user4/100/100',
1439
- imageUrl: 'https://picsum.photos/seed/user4/100/100'
1440
- }
1603
+ content: {
1604
+ Items: [
1605
+ {
1606
+ Title: 'Amazing Quality!',
1607
+ title: 'Amazing Quality!',
1608
+ Description: 'I\'ve been shopping here for years and the quality never disappoints. Fast shipping and excellent customer service too!',
1609
+ description: 'I\'ve been shopping here for years and the quality never disappoints. Fast shipping and excellent customer service too!',
1610
+ PersonName: 'Sarah Johnson',
1611
+ personName: 'Sarah Johnson',
1612
+ CompanyName: 'Verified Buyer',
1613
+ companyName: 'Verified Buyer',
1614
+ Rating: 5,
1615
+ rating: 5,
1616
+ ImageUrl: 'https://picsum.photos/seed/user1/100/100',
1617
+ imageUrl: 'https://picsum.photos/seed/user1/100/100'
1618
+ },
1619
+ {
1620
+ Title: 'Great Experience',
1621
+ title: 'Great Experience',
1622
+ Description: 'The customer service team went above and beyond to help me find exactly what I needed. Highly recommend!',
1623
+ description: 'The customer service team went above and beyond to help me find exactly what I needed. Highly recommend!',
1624
+ PersonName: 'Michael Chen',
1625
+ personName: 'Michael Chen',
1626
+ CompanyName: 'Regular Customer',
1627
+ companyName: 'Regular Customer',
1628
+ Rating: 5,
1629
+ rating: 5,
1630
+ ImageUrl: 'https://picsum.photos/seed/user2/100/100',
1631
+ imageUrl: 'https://picsum.photos/seed/user2/100/100'
1632
+ },
1633
+ {
1634
+ Title: 'Will Shop Again',
1635
+ title: 'Will Shop Again',
1636
+ Description: 'Love the variety of products and the prices are very competitive. The website is easy to navigate too.',
1637
+ description: 'Love the variety of products and the prices are very competitive. The website is easy to navigate too.',
1638
+ PersonName: 'Emily Davis',
1639
+ personName: 'Emily Davis',
1640
+ CompanyName: 'Fashion Enthusiast',
1641
+ companyName: 'Fashion Enthusiast',
1642
+ Rating: 5,
1643
+ rating: 5,
1644
+ ImageUrl: 'https://picsum.photos/seed/user3/100/100',
1645
+ imageUrl: 'https://picsum.photos/seed/user3/100/100'
1646
+ },
1647
+ {
1648
+ Title: 'Fast Delivery',
1649
+ title: 'Fast Delivery',
1650
+ Description: 'Ordered on Monday, received on Wednesday! The packaging was perfect and the product exceeded expectations.',
1651
+ description: 'Ordered on Monday, received on Wednesday! The packaging was perfect and the product exceeded expectations.',
1652
+ PersonName: 'David Wilson',
1653
+ personName: 'David Wilson',
1654
+ CompanyName: 'Tech Reviewer',
1655
+ companyName: 'Tech Reviewer',
1656
+ Rating: 4,
1657
+ rating: 4,
1658
+ ImageUrl: 'https://picsum.photos/seed/user4/100/100',
1659
+ imageUrl: 'https://picsum.photos/seed/user4/100/100'
1660
+ }
1661
+ ]
1662
+ }
1663
+ },
1664
+ content: JSON.stringify({
1665
+ Items: [
1666
+ { Title: 'Amazing Quality!', Description: 'The quality never disappoints.', PersonName: 'Sarah Johnson', CompanyName: 'Verified Buyer', Rating: 5, ImageUrl: 'https://picsum.photos/seed/user1/100/100' },
1667
+ { Title: 'Great Experience', Description: 'Excellent customer service.', PersonName: 'Michael Chen', CompanyName: 'Regular Customer', Rating: 5, ImageUrl: 'https://picsum.photos/seed/user2/100/100' },
1668
+ { Title: 'Will Shop Again', Description: 'Love the variety.', PersonName: 'Emily Davis', CompanyName: 'Fashion Enthusiast', Rating: 5, ImageUrl: 'https://picsum.photos/seed/user3/100/100' },
1669
+ { Title: 'Fast Delivery', Description: 'Quick and perfect packaging.', PersonName: 'David Wilson', CompanyName: 'Tech Reviewer', Rating: 4, ImageUrl: 'https://picsum.photos/seed/user4/100/100' }
1441
1670
  ]
1671
+ })
1672
+ },
1673
+
1674
+ // DiscountTime Widget
1675
+ {
1676
+ id: 'widget-discount-time-1',
1677
+ type: 'DiscountTime',
1678
+ section: 'content',
1679
+ sectionName: 'content',
1680
+ pageId: 'home',
1681
+ status: 'active',
1682
+ Position: 14,
1683
+ Title: 'Limited Time Offer',
1684
+ settings: {
1685
+ title: 'Limited Time Offer',
1686
+ textColor: '#ffffff',
1687
+ backgroundColor: '#1f2937',
1688
+ background_from: '#1f2937',
1689
+ background_to: '#111827',
1690
+ cta_label: 'Shop Now',
1691
+ cta_link: '/products',
1692
+ cta_background: '#ef4444',
1693
+ cta_text: '#ffffff'
1442
1694
  },
1443
- content: JSON.stringify([
1444
- { Title: 'Amazing Quality!', Description: 'The quality never disappoints.', PersonName: 'Sarah Johnson', CompanyName: 'Verified Buyer', Rating: 5, ImageUrl: 'https://picsum.photos/seed/user1/100/100' },
1445
- { Title: 'Great Experience', Description: 'Excellent customer service.', PersonName: 'Michael Chen', CompanyName: 'Regular Customer', Rating: 5, ImageUrl: 'https://picsum.photos/seed/user2/100/100' },
1446
- { Title: 'Will Shop Again', Description: 'Love the variety.', PersonName: 'Emily Davis', CompanyName: 'Fashion Enthusiast', Rating: 5, ImageUrl: 'https://picsum.photos/seed/user3/100/100' },
1447
- { Title: 'Fast Delivery', Description: 'Quick and perfect packaging.', PersonName: 'David Wilson', CompanyName: 'Tech Reviewer', Rating: 4, ImageUrl: 'https://picsum.photos/seed/user4/100/100' }
1448
- ])
1695
+ data: {
1696
+ content: {
1697
+ couponValid: true,
1698
+ coupon: {
1699
+ discountAmount: 25,
1700
+ couponCode: 'SAVE25',
1701
+ description: 'Get 25% off on all products! Limited time only.',
1702
+ endOn: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
1703
+ startOn: new Date().toISOString(),
1704
+ ruleToApply: 'by_percent',
1705
+ fileName: '',
1706
+ imageUrl: 'https://picsum.photos/seed/discount-banner/1200/400'
1707
+ }
1708
+ }
1709
+ }
1710
+ },
1711
+
1712
+ // Product Widget (uses product-grid shared template)
1713
+ {
1714
+ id: 'widget-product-1',
1715
+ type: 'Product',
1716
+ section: 'content',
1717
+ sectionName: 'content',
1718
+ pageId: 'home',
1719
+ status: 'active',
1720
+ Position: 15,
1721
+ Title: 'Our Products',
1722
+ settings: {
1723
+ title: 'Our Products',
1724
+ subtitle: 'Top picks for you',
1725
+ columns: 4,
1726
+ showWidgetTitle: 'Yes',
1727
+ widgetTitleAlignment: 'center',
1728
+ show_add_to_cart: true
1729
+ },
1730
+ data: {
1731
+ content: {
1732
+ products: [],
1733
+ Products: []
1734
+ },
1735
+ products: []
1736
+ }
1737
+ },
1738
+
1739
+ // ProductCanvas Widget
1740
+ {
1741
+ id: 'widget-product-canvas-1',
1742
+ type: 'ProductCanvas',
1743
+ section: 'content',
1744
+ sectionName: 'content',
1745
+ pageId: 'home',
1746
+ status: 'active',
1747
+ Position: 16,
1748
+ Title: 'Shop the Look',
1749
+ settings: {
1750
+ title: 'Shop the Look',
1751
+ showContainer: 'Yes',
1752
+ showWidgetBottomMargin: 'Yes',
1753
+ backgroundColor: '#f9fafb'
1754
+ },
1755
+ data: {
1756
+ content: {
1757
+ ImageUrl: 'https://picsum.photos/seed/canvas-main/1200/600',
1758
+ imageUrl: 'https://picsum.photos/seed/canvas-main/1200/600',
1759
+ ShowContainer: 'Yes',
1760
+ ShowWidgetBottomMargin: 'Yes',
1761
+ Items: [
1762
+ { X: 25, Y: 30, x: 25, y: 30, TargetUrl: '/products', targetUrl: '/products', Url: '/products', url: '/products' },
1763
+ { X: 55, Y: 45, x: 55, y: 45, TargetUrl: '/products', targetUrl: '/products', Url: '/products', url: '/products' },
1764
+ { X: 75, Y: 60, x: 75, y: 60, TargetUrl: '/products', targetUrl: '/products', Url: '/products', url: '/products' }
1765
+ ]
1766
+ }
1767
+ }
1768
+ },
1769
+
1770
+ // Splash Widget
1771
+ {
1772
+ id: 'widget-splash-1',
1773
+ type: 'Splash',
1774
+ section: 'content',
1775
+ sectionName: 'content',
1776
+ pageId: 'home',
1777
+ status: 'active',
1778
+ Position: 17,
1779
+ Title: 'Welcome Offer',
1780
+ settings: {
1781
+ backgroundColor: '#ffffff',
1782
+ textColor: '#111111',
1783
+ seconds: 3,
1784
+ showOnce: true,
1785
+ overlayColor: 'rgba(0,0,0,0.6)',
1786
+ eventType: 'Onload'
1787
+ },
1788
+ data: {
1789
+ content: {
1790
+ ImageUrl: 'https://picsum.photos/seed/splash-promo/600/400',
1791
+ imageUrl: 'https://picsum.photos/seed/splash-promo/600/400',
1792
+ Title: 'Welcome to Our Store!',
1793
+ title: 'Welcome to Our Store!',
1794
+ Description: 'Sign up and get 15% off your first order. Use code WELCOME15 at checkout.',
1795
+ description: 'Sign up and get 15% off your first order. Use code WELCOME15 at checkout.',
1796
+ LinkText: 'Shop Now',
1797
+ linkText: 'Shop Now',
1798
+ ButtonText: 'Shop Now',
1799
+ buttonText: 'Shop Now',
1800
+ TargetUrl: '/products',
1801
+ targetUrl: '/products',
1802
+ Link: '/products',
1803
+ link: '/products',
1804
+ BackgroundColor: '#ffffff',
1805
+ backgroundColor: '#ffffff',
1806
+ TextColor: '#111111',
1807
+ textColor: '#111111',
1808
+ Seconds: 3,
1809
+ seconds: 3,
1810
+ DelaySeconds: 3,
1811
+ delaySeconds: 3,
1812
+ ShowOnce: true,
1813
+ showOnce: true,
1814
+ OverlayColor: 'rgba(0,0,0,0.6)',
1815
+ overlayColor: 'rgba(0,0,0,0.6)',
1816
+ EventType: 'Onload',
1817
+ eventType: 'Onload'
1818
+ }
1819
+ }
1820
+ },
1821
+
1822
+ // SpaceBarCarousel Widget
1823
+ {
1824
+ id: 'widget-spacebar-carousel-1',
1825
+ type: 'SpaceBarCarousel',
1826
+ section: 'content',
1827
+ sectionName: 'content',
1828
+ pageId: 'home',
1829
+ status: 'active',
1830
+ Position: 18,
1831
+ Title: 'Why Shop With Us',
1832
+ settings: {
1833
+ title: 'Why Shop With Us',
1834
+ subtitle: 'We deliver excellence',
1835
+ showWidgetTitle: 'Yes',
1836
+ widgetTitleAlignment: 'center',
1837
+ backgroundColor: '#f8f9fa',
1838
+ textColor: '#111',
1839
+ hideDot: false,
1840
+ hideArrow: false,
1841
+ priorityCount: 4
1842
+ },
1843
+ data: {
1844
+ content: {
1845
+ Items: [
1846
+ {
1847
+ Title: 'Free Shipping', title: 'Free Shipping',
1848
+ Description: 'On orders over $50', description: 'On orders over $50',
1849
+ IconHtml: '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="1" y="3" width="15" height="13"></rect><polygon points="16 8 20 8 23 11 23 16 16 16 16 8"></polygon><circle cx="5.5" cy="18.5" r="2.5"></circle><circle cx="18.5" cy="18.5" r="2.5"></circle></svg>',
1850
+ ImageUrl: 'https://picsum.photos/seed/feat-ship/100/100', imageUrl: 'https://picsum.photos/seed/feat-ship/100/100',
1851
+ Link: '/shipping-info', link: '/shipping-info'
1852
+ },
1853
+ {
1854
+ Title: '24/7 Support', title: '24/7 Support',
1855
+ Description: 'Dedicated support team', description: 'Dedicated support team',
1856
+ IconHtml: '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72"></path></svg>',
1857
+ ImageUrl: 'https://picsum.photos/seed/feat-support/100/100', imageUrl: 'https://picsum.photos/seed/feat-support/100/100',
1858
+ Link: '/contact', link: '/contact'
1859
+ },
1860
+ {
1861
+ Title: 'Secure Payment', title: 'Secure Payment',
1862
+ Description: '100% secure checkout', description: '100% secure checkout',
1863
+ IconHtml: '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>',
1864
+ ImageUrl: 'https://picsum.photos/seed/feat-secure/100/100', imageUrl: 'https://picsum.photos/seed/feat-secure/100/100',
1865
+ Link: '/security', link: '/security'
1866
+ },
1867
+ {
1868
+ Title: 'Easy Returns', title: 'Easy Returns',
1869
+ Description: '30-day return policy', description: '30-day return policy',
1870
+ IconHtml: '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="1 4 1 10 7 10"></polyline><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path></svg>',
1871
+ ImageUrl: 'https://picsum.photos/seed/feat-return/100/100', imageUrl: 'https://picsum.photos/seed/feat-return/100/100',
1872
+ Link: '/returns', link: '/returns'
1873
+ },
1874
+ {
1875
+ Title: 'Loyalty Rewards', title: 'Loyalty Rewards',
1876
+ Description: 'Earn points on every purchase', description: 'Earn points on every purchase',
1877
+ IconHtml: '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="8" r="7"></circle><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"></polyline></svg>',
1878
+ ImageUrl: 'https://picsum.photos/seed/feat-loyalty/100/100', imageUrl: 'https://picsum.photos/seed/feat-loyalty/100/100',
1879
+ Link: '/loyalty', link: '/loyalty'
1880
+ },
1881
+ {
1882
+ Title: 'Quality Assured', title: 'Quality Assured',
1883
+ Description: 'Premium products guaranteed', description: 'Premium products guaranteed',
1884
+ IconHtml: '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>',
1885
+ ImageUrl: 'https://picsum.photos/seed/feat-quality/100/100', imageUrl: 'https://picsum.photos/seed/feat-quality/100/100',
1886
+ Link: '/about', link: '/about'
1887
+ }
1888
+ ]
1889
+ }
1890
+ }
1449
1891
  },
1450
1892
 
1451
1893
  // ==================== FOOTER SECTION ====================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o2vend/theme-cli",
3
- "version": "1.0.36",
3
+ "version": "1.0.37",
4
4
  "description": "O2VEND Theme Development CLI - Standalone tool for local theme development",
5
5
  "bin": {
6
6
  "o2vend": "./bin/o2vend"
@@ -46,7 +46,7 @@
46
46
  "table": "^6.8.3"
47
47
  },
48
48
  "engines": {
49
- "node": ">=18.0.0"
49
+ "node": ">=24.0.0"
50
50
  },
51
51
  "files": [
52
52
  "bin/**/*",