1import { DOM, html } from "./DOM.js"; 2import { initTilt } from "./tilt.js"; 3 4/** 5 * Fetches notebook products from the JSON file. 6 * @returns {Promise<Array>} Array of product objects. 7 */ 8async function fetchNotebooks() { 9 try { 10 const jsonUrl = new URL('../json/notebook-products.json', import.meta.url).href; 11 const response = await fetch(jsonUrl); 12 if (!response.ok) { 13 throw new Error('Failed to fetch products'); 14 } 15 const notebooks = await response.json(); 16 // Store in localStorage 17 localStorage.setItem('notebookProducts', JSON.stringify(notebooks)); 18 return notebooks; 19 } catch (error) { 20 console.error('Fetch failed:', error); 21 // Try to get from localStorage 22 const cached = localStorage.getItem('notebookProducts'); 23 if (cached) { 24 return JSON.parse(cached); 25 } 26 throw error; 27 } 28} 29 30/** 31 * Creates a product card element. 32 * @param {Object} product - The product object. 33 * @param {string} product.title - Product title. 34 * @param {string} product.price - Product price. 35 * @param {string} product.link - Checkout link. 36 * @param {string} product.description - Product description. 37 * @param {string} product.id - Product ID. 38 * @returns {HTMLElement} The card element. 39 */ 40function createProductCard(product) { 41 const imageUrl = new URL(`../images/products/${product.id}.jpg`, import.meta.url).href; 42 const cardHtml = html` 43 <div class="product-card"> 44 <img 45 src="${imageUrl}" 46 alt="${product.title}" 47 class="product-image" 48 > 49 <div class="product-info"> 50 <h3 class="product-title">${product.title}</h3> 51 <p class="product-price">${product.price}</p> 52 <p class="product-description">${product.description || 'No description available.'}</p> 53 <a href="${product.link}" target="_blank" class="checkout-button">Checkout</a> 54 </div> 55 </div> 56 `; 57 58 return DOM.createDomElement(cardHtml); 59} 60 61/** 62 * Renders the products to the page. 63 * @param {Array} products - Array of product objects. 64 */ 65function renderProducts(products) { 66 const container = document.getElementById('products-container'); 67 container.innerHTML = ''; // Clear existing 68 products.forEach(product => { 69 const card = createProductCard(product); 70 container.appendChild(card); 71 }); 72} 73 74/** 75 * Displays an error message. 76 * @param {string} message - The error message. 77 */ 78function showError(message) { 79 const container = document.getElementById('products-container'); 80 container.innerHTML = `<p class="error-message">${message}</p>`; 81} 82 83/** 84 * Initializes the product loading. 85 */ 86async function initProducts() { 87 try { 88 const products = await fetchNotebooks(); 89 renderProducts(products); 90 // init tilt on freshly rendered images 91 initTilt(); 92 } catch (error) { 93 showError('Failed to load products. Please try again later.'); 94 } 95} 96 97// Load products on page load 98document.addEventListener('DOMContentLoaded', initProducts);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.