Restaurant Logo
/* styles.css */ .dish-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem; } .dish-card { cursor: pointer; transition: transform 0.3s ease, box-shadow 0.3s ease; } .dish-card:hover { transform: scale(1.05); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .dish-card img { width: 100%; height: 200px; object-fit: cover; } .modal { display: none; position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0, 0, 0, 0.4); opacity: 0; transition: opacity 0.3s ease; } .modal.show { opacity: 1; } .modal-content { background-color: #fefefe; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 80%; max-width: 600px; transform: scale(0.8); transition: transform 0.3s ease; } .modal.show .modal-content { transform: scale(1); } .highlight { background-color: yellow; font-weight: bold; } // app.js // Dish data const dishes = [ { name: "Griot", image: "dish-1.jpg", description: "Griot is a popular Haitian dish made with marinated pork chunks that are deep-fried until crispy.", ingredients: ["Pork", "Citrus marinade", "Scotch bonnet peppers", "Garlic", "Thyme"], category: "main-courses" }, { name: "Pikliz", image: "dish-2.jpg", description: "Pikliz is a spicy Haitian condiment made with pickled cabbage, carrots, and peppers.", ingredients: ["Cabbage", "Carrots", "Bell peppers", "Scotch bonnet peppers", "Vinegar"], category: "appetizers" }, { name: "Akasan", image: "dish-3.jpg", description: "Akasan is a traditional Haitian breakfast drink made with cornmeal, milk, and spices.", ingredients: ["Cornmeal", "Milk", "Cinnamon", "Vanilla", "Sugar"], category: "desserts" }, // Add more dish objects here ]; // Get DOM elements const searchInput = document.getElementById("search-input"); const dishGrid = document.getElementById("dish-grid"); const dishModal = document.getElementById("dish-modal"); const modalImage = document.getElementById("modal-image"); const modalName = document.getElementById("modal-name"); const modalDescription = document.getElementById("modal-description"); const modalIngredients = document.getElementById("modal-ingredients"); const closeModal = document.getElementsByClassName("close")[0]; // Function to render dishes on the grid function renderDishes(dishes) { dishGrid.innerHTML = ""; if (dishes.length === 0) { dishGrid.innerHTML = '

No dishes found

'; return; } dishes.forEach(dish => { const dishCard = document.createElement("div"); dishCard.classList.add("dish-card", "bg-white", "rounded-md", "shadow-md", "overflow-hidden"); dishCard.innerHTML = ` ${dish.name}

${dish.name}

${dish.description}

`; dishCard.setAttribute('aria-label', `${dish.name}: ${dish.description}`); dishCard.addEventListener("click", () => openModal(dish)); dishGrid.appendChild(dishCard); }); } // Function to open the dish details modal function openModal(dish) { modalImage.src = dish.image; modalImage.alt = dish.name; modalName.textContent = dish.name; modalDescription.textContent = dish.description; modalIngredients.innerHTML = dish.ingredients.map(ingredient => `
  • ${ingredient}
  • `).join(""); dishModal.style.display = "block"; setTimeout(() => { dishModal.classList.add("show"); }, 10); dishModal.setAttribute('aria-hidden', 'false'); closeModal.focus(); } // Function to close the dish details modal function closeModal() { dishModal.classList.remove("show"); setTimeout(() => { dishModal.style.display = "none"; }, 300); dishModal.setAttribute('aria-hidden', 'true'); searchInput.focus(); } // Function to highlight search terms function highlightSearchTerm(text, term) { const regex = new RegExp(`(${term})`, 'gi'); return text.replace(regex, '$1'); } // Event listener for search input searchInput.addEventListener("input", () => { const searchTerm = searchInput.value.toLowerCase(); const filteredDishes = dishes.filter(dish => dish.name.toLowerCase().includes(searchTerm) || dish.ingredients.some(ingredient => ingredient.toLowerCase().includes(searchTerm)) ); renderDishes(filteredDishes); // Highlight search terms const dishCards = document.querySelectorAll('.dish-card'); dishCards.forEach(card => { const name = card.querySelector('h3'); const description = card.querySelector('p'); name.innerHTML = highlightSearchTerm(name.textContent, searchTerm); description.innerHTML = highlightSearchTerm(description.textContent, searchTerm); }); }); // Event listener for category navigation const categoryLinks = document.querySelectorAll("nav a"); categoryLinks.forEach(link => { link.addEventListener("click", (event) => { event.preventDefault(); const category = link.dataset.category; const filteredDishes = dishes.filter(dish => dish.category === category); renderDishes(filteredDishes); }); }); // Event listener for closing the modal closeModal.addEventListener("click", closeModal); window.addEventListener("click", (event) => { if (event.target === dishModal) { closeModal(); } }); // Keyboard navigation for modal dishModal.addEventListener('keydown', (event) => { if (event.key === 'Escape') { closeModal(); } }); // Service Worker Registration if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.log('Service Worker registered successfully:', registration.scope); }) .catch(error => { console.log('Service Worker registration failed:', error); }); }); } // Local Storage for Offline Functionality function saveDishesToLocalStorage() { try { localStorage.setItem('dishes', JSON.stringify(dishes)); } catch (error) { console.error('Error saving dishes to local storage:', error); } } function loadDishesFromLocalStorage() { try { const storedDishes = localStorage.getItem('dishes'); return storedDishes ? JSON.parse(storedDishes) : null; } catch (error) { console.error('Error loading dishes from local storage:', error); return null; } } // Save dishes to local storage on initial load saveDishesToLocalStorage(); // Load dishes from local storage if available const storedDishes = loadDishesFromLocalStorage(); if (storedDishes) { renderDishes(storedDishes); } else { renderDishes(dishes); } // Lazy Loading Images function lazyLoadImages() { const images = document.querySelectorAll('img[loading="lazy"]'); const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.src; // Trigger the image load img.removeAttribute('loading'); imageObserver.unobserve(img); } }); }); images.forEach(img => { imageObserver.observe(img); }); } // Error handling for image loading function handleImageError(img) { img.onerror = () => { img.src = 'placeholder.jpg'; img.alt = 'Image not available'; }; } // Call lazy loading function after initial render lazyLoadImages(); // Initial render of dishes renderDishes(dishes);