@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,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Watcher
|
|
3
|
+
* Watches theme files for changes and triggers reload
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chokidar = require('chokidar');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Setup file watcher for theme directory
|
|
11
|
+
* @param {string} themePath - Path to theme directory
|
|
12
|
+
* @param {Function} onChange - Callback when files change
|
|
13
|
+
* @returns {Object} Watcher instance
|
|
14
|
+
*/
|
|
15
|
+
function setupFileWatcher(themePath, onChange) {
|
|
16
|
+
const watcher = chokidar.watch(themePath, {
|
|
17
|
+
ignored: [
|
|
18
|
+
/(^|[\/\\])\../, // Ignore dotfiles
|
|
19
|
+
'**/node_modules/**',
|
|
20
|
+
'**/.git/**',
|
|
21
|
+
'**/.o2vend-cache/**',
|
|
22
|
+
'**/*.log',
|
|
23
|
+
'**/.DS_Store'
|
|
24
|
+
],
|
|
25
|
+
persistent: true,
|
|
26
|
+
ignoreInitial: true,
|
|
27
|
+
awaitWriteFinish: {
|
|
28
|
+
stabilityThreshold: 100,
|
|
29
|
+
pollInterval: 50
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
let changeTimeout = null;
|
|
34
|
+
const changedFiles = new Set();
|
|
35
|
+
|
|
36
|
+
watcher
|
|
37
|
+
.on('change', (filePath) => {
|
|
38
|
+
// Debounce multiple changes
|
|
39
|
+
changedFiles.add(filePath);
|
|
40
|
+
|
|
41
|
+
if (changeTimeout) {
|
|
42
|
+
clearTimeout(changeTimeout);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
changeTimeout = setTimeout(() => {
|
|
46
|
+
const files = Array.from(changedFiles);
|
|
47
|
+
changedFiles.clear();
|
|
48
|
+
|
|
49
|
+
if (onChange) {
|
|
50
|
+
onChange(files);
|
|
51
|
+
}
|
|
52
|
+
}, 100);
|
|
53
|
+
})
|
|
54
|
+
.on('add', (filePath) => {
|
|
55
|
+
// New file added
|
|
56
|
+
changedFiles.add(filePath);
|
|
57
|
+
|
|
58
|
+
if (changeTimeout) {
|
|
59
|
+
clearTimeout(changeTimeout);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
changeTimeout = setTimeout(() => {
|
|
63
|
+
const files = Array.from(changedFiles);
|
|
64
|
+
changedFiles.clear();
|
|
65
|
+
|
|
66
|
+
if (onChange) {
|
|
67
|
+
onChange(files);
|
|
68
|
+
}
|
|
69
|
+
}, 100);
|
|
70
|
+
})
|
|
71
|
+
.on('error', (error) => {
|
|
72
|
+
console.error('[FileWatcher] Error:', error);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return watcher;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
setupFileWatcher
|
|
80
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hot Reload
|
|
3
|
+
* WebSocket server for live reloading in browser
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { Server } = require('socket.io');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Setup hot reload WebSocket server
|
|
10
|
+
* @returns {Server} Socket.IO server
|
|
11
|
+
*/
|
|
12
|
+
function setupHotReload() {
|
|
13
|
+
const io = new Server({
|
|
14
|
+
path: '/socket.io',
|
|
15
|
+
serveClient: true,
|
|
16
|
+
cors: {
|
|
17
|
+
origin: '*',
|
|
18
|
+
methods: ['GET', 'POST']
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Handle connections (will be attached to HTTP server later)
|
|
23
|
+
io.on('connection', (socket) => {
|
|
24
|
+
// Client connected - will be used for hot reload
|
|
25
|
+
socket.on('disconnect', () => {
|
|
26
|
+
// Client disconnected
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return io;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Inject hot reload script into HTML
|
|
35
|
+
* @param {string} html - HTML content
|
|
36
|
+
* @param {string} host - Server host
|
|
37
|
+
* @param {number} port - Server port
|
|
38
|
+
* @returns {string} HTML with hot reload script
|
|
39
|
+
*/
|
|
40
|
+
function injectHotReloadScript(html, host = 'localhost', port = 3000) {
|
|
41
|
+
const script = `
|
|
42
|
+
<script src="/socket.io/socket.io.js"></script>
|
|
43
|
+
<script>
|
|
44
|
+
(function() {
|
|
45
|
+
if (typeof io !== 'undefined') {
|
|
46
|
+
const socket = io('http://${host}:${port}', {
|
|
47
|
+
path: '/socket.io',
|
|
48
|
+
transports: ['websocket', 'polling']
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
socket.on('connect', function() {
|
|
52
|
+
console.log('[Hot Reload] Connected');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
socket.on('file-changed', function(files) {
|
|
56
|
+
console.log('[Hot Reload] Files changed:', files);
|
|
57
|
+
|
|
58
|
+
// Determine reload strategy based on file type
|
|
59
|
+
const hasCss = files.some(f => f.endsWith('.css'));
|
|
60
|
+
const hasLiquid = files.some(f => f.endsWith('.liquid'));
|
|
61
|
+
const hasJs = files.some(f => f.endsWith('.js'));
|
|
62
|
+
|
|
63
|
+
if (hasCss && !hasLiquid && !hasJs) {
|
|
64
|
+
// CSS only - inject without reload
|
|
65
|
+
console.log('[Hot Reload] Injecting CSS...');
|
|
66
|
+
files.filter(f => f.endsWith('.css')).forEach(function(file) {
|
|
67
|
+
const fileName = file.split(/[/\\\\]/).pop();
|
|
68
|
+
const links = document.querySelectorAll('link[rel="stylesheet"]');
|
|
69
|
+
links.forEach(function(link) {
|
|
70
|
+
if (link.href.includes(fileName)) {
|
|
71
|
+
const newLink = document.createElement('link');
|
|
72
|
+
newLink.rel = 'stylesheet';
|
|
73
|
+
newLink.href = link.href.split('?')[0] + '?v=' + Date.now();
|
|
74
|
+
link.parentNode.replaceChild(newLink, link);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
} else {
|
|
79
|
+
// Full page reload
|
|
80
|
+
console.log('[Hot Reload] Reloading page...');
|
|
81
|
+
window.location.reload();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
socket.on('disconnect', function() {
|
|
86
|
+
console.log('[Hot Reload] Disconnected');
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
})();
|
|
90
|
+
</script>
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
// Inject before closing </body> tag
|
|
94
|
+
if (html.includes('</body>')) {
|
|
95
|
+
return html.replace('</body>', script + '</body>');
|
|
96
|
+
} else if (html.includes('</html>')) {
|
|
97
|
+
return html.replace('</html>', script + '</html>');
|
|
98
|
+
} else {
|
|
99
|
+
return html + script;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = {
|
|
104
|
+
setupHotReload,
|
|
105
|
+
injectHotReloadScript
|
|
106
|
+
};
|