Spaces:
Running
Running
File size: 5,236 Bytes
3105a9a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | document.addEventListener('DOMContentLoaded', () => {
const productGrid = document.getElementById('product-grid');
const loader = document.getElementById('loader');
let products = [];
// Cart State
let cartCount = 0;
// --- Event Listeners for Filters ---
document.getElementById('filter-all').addEventListener('click', () => filterProducts('all'));
document.getElementById('filter-tech').addEventListener('click', () => filterProducts('tech'));
document.getElementById('filter-design').addEventListener('click', () => filterProducts('design'));
// --- Function: Fetch Data ---
async function loadProducts() {
// Show Loader
loader.style.display = 'flex';
productGrid.innerHTML = '';
try {
// Attempt to fetch from local data.json file
const response = await fetch('data.json');
if (!response.ok) throw new Error("HTTP error");
products = await response.json();
} catch (error) {
console.warn('Could not load data.json (likely due to CORS on local file system). Using fallback data.', error);
// Fallback Data if JSON fetch fails
products = [
{ id: 1, name: "Wireless Headphones", price: 299, category: "tech", image: "http://static.photos/technology/640x360/1", rating: 4.8 },
{ id: 2, name: "Mechanical Keyboard", price: 149, category: "tech", image: "http://static.photos/workspace/640x360/2", rating: 4.7 },
{ id: 3, name: "Modern Lamp", price: 89, category: "design", image: "http://static.photos/interior/640x360/3", rating: 4.5 },
{ id: 4, name: "Smart Watch", price: 399, category: "tech", image: "http://static.photos/technology/640x360/6", rating: 4.6 }
];
} finally {
// Hide Loader
loader.style.display = 'none';
renderProducts(products);
}
}
// --- Function: Render Products ---
function renderProducts(items) {
productGrid.innerHTML = '';
items.forEach(product => {
const card = document.createElement('shop-card');
// Set attributes for the web component
card.setAttribute('name', product.name);
card.setAttribute('price', product.price);
card.setAttribute('category', product.category);
card.setAttribute('image', product.image);
card.setAttribute('rating', product.rating);
productGrid.appendChild(card);
});
}
// --- Function: Filter Products ---
function filterProducts(category) {
// Update active button styles
const buttons = document.querySelectorAll('button[id^="filter-"]');
buttons.forEach(btn => {
if (btn.id === `filter-${category}`) {
btn.classList.remove('bg-white', 'text-gray-600');
btn.classList.add('bg-primary', 'text-white');
} else {
btn.classList.remove('bg-primary', 'text-white');
btn.classList.add('bg-white', 'text-gray-600');
}
});
if (category === 'all') {
renderProducts(products);
} else {
const filtered = products.filter(p => p.category === category);
renderProducts(filtered);
}
}
// --- Global Event Listener: Add to Cart ---
// We listen for a custom event dispatched from inside the Shadow DOM of the Web Component
window.addEventListener('add-to-cart', (e) => {
cartCount++;
updateCartDisplay();
showToast(`Added ${e.detail.productName} to cart!`);
});
// --- Global Event Listener: Remove Product ---
window.addEventListener('remove-product', (e) => {
const card = e.detail.element;
card.style.opacity = '0';
card.style.transform = 'scale(0.9)';
setTimeout(() => {
card.remove();
}, 300);
showToast('Product removed.');
});
function updateCartDisplay() {
// We dispatch an event to the navbar since we can't easily access its shadow DOM internals directly
window.dispatchEvent(new CustomEvent('update-cart-count', {
detail: { count: cartCount }
}));
}
// --- Function: Show Toast Notification ---
function showToast(message) {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
toast.className = 'toast-enter bg-dark text-white px-6 py-3 rounded-lg shadow-xl flex items-center gap-3';
toast.innerHTML = `
<i data-feather="check-circle" class="text-green-400"></i>
<span class="font-medium">${message}</span>
`;
container.appendChild(toast);
feather.replace(); // Refresh icons in new element
// Remove after 3 seconds
setTimeout(() => {
toast.classList.remove('toast-enter');
toast.classList.add('toast-exit');
setTimeout(() => {
toast.remove();
}, 300);
}, 3000);
}
// Initialize
loadProducts();
}); |