Download index.html from bala41/kitchen: direct link, hf CLI and curl.
- Browser
- Download file 19.7 kB
-
https://huggingface.co/spaces/bala41/kitchen/resolve/main/index.html
- Command line
-
hf download hf://spaces/bala41/kitchen/index.html
-
curl -L -o index.html https://huggingface.co/spaces/bala41/kitchen/resolve/main/index.html
19.7 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Kitchen Stock - Track Out-of-Stock Items</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); | |
| body { | |
| font-family: 'Poppins', sans-serif; | |
| background-color: #f8fafc; | |
| } | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); | |
| } | |
| .item-card { | |
| transition: all 0.3s ease; | |
| } | |
| .item-card:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
| } | |
| .pulse { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { | |
| transform: scale(0.95); | |
| box-shadow: 0 0 0 0 rgba(74, 222, 128, 0.7); | |
| } | |
| 70% { | |
| transform: scale(1); | |
| box-shadow: 0 0 0 10px rgba(74, 222, 128, 0); | |
| } | |
| 100% { | |
| transform: scale(0.95); | |
| box-shadow: 0 0 0 0 rgba(74, 222, 128, 0); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen gradient-bg"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="flex justify-between items-center mb-8"> | |
| <div class="flex items-center"> | |
| <div class="w-12 h-12 rounded-full bg-white shadow-md flex items-center justify-center mr-4"> | |
| <i class="fas fa-utensils text-2xl text-emerald-500"></i> | |
| </div> | |
| <h1 class="text-3xl font-bold text-gray-800">Kitchen Stock</h1> | |
| </div> | |
| <button id="addItemBtn" class="bg-emerald-500 hover:bg-emerald-600 text-white px-6 py-2 rounded-full shadow-md flex items-center transition-all"> | |
| <i class="fas fa-plus mr-2"></i> Add Item | |
| </button> | |
| </header> | |
| <!-- Stats Cards --> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8"> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-emerald-100 text-emerald-600 mr-4"> | |
| <i class="fas fa-box-open text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500 text-sm">Out of Stock</p> | |
| <h3 class="text-2xl font-bold" id="outOfStockCount">0</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4"> | |
| <i class="fas fa-list text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500 text-sm">Total Items</p> | |
| <h3 class="text-2xl font-bold" id="totalItemsCount">0</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-purple-100 text-purple-600 mr-4"> | |
| <i class="fas fa-history text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500 text-sm">Recently Added</p> | |
| <h3 class="text-2xl font-bold" id="recentItemsCount">0</h3> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="p-4 border-b border-gray-200 flex justify-between items-center"> | |
| <h2 class="text-xl font-semibold text-gray-800">Out of Stock Items</h2> | |
| <div class="relative"> | |
| <input type="text" id="searchInput" placeholder="Search items..." class="pl-10 pr-4 py-2 border border-gray-300 rounded-full focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-transparent"> | |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> | |
| </div> | |
| </div> | |
| <div class="p-4" id="itemsContainer"> | |
| <!-- Empty state --> | |
| <div id="emptyState" class="text-center py-12"> | |
| <div class="w-24 h-24 mx-auto mb-4 rounded-full bg-gray-100 flex items-center justify-center"> | |
| <i class="fas fa-box-open text-3xl text-gray-400"></i> | |
| </div> | |
| <h3 class="text-xl font-medium text-gray-700 mb-2">No out-of-stock items</h3> | |
| <p class="text-gray-500 mb-6">Add items that are out of stock to keep track</p> | |
| <button id="addFirstItemBtn" class="bg-emerald-500 hover:bg-emerald-600 text-white px-6 py-2 rounded-full shadow-md inline-flex items-center transition-all"> | |
| <i class="fas fa-plus mr-2"></i> Add Your First Item | |
| </button> | |
| </div> | |
| <!-- Items will be added here dynamically --> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Add Item Modal --> | |
| <div id="addItemModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-md mx-4"> | |
| <div class="p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-bold text-gray-800">Add Out-of-Stock Item</h3> | |
| <button id="closeModalBtn" class="text-gray-500 hover:text-gray-700"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <form id="addItemForm"> | |
| <div class="mb-4"> | |
| <label for="itemName" class="block text-sm font-medium text-gray-700 mb-1">Item Name</label> | |
| <input type="text" id="itemName" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-transparent" placeholder="e.g. Milk, Eggs, Bread" required> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="itemCategory" class="block text-sm font-medium text-gray-700 mb-1">Category</label> | |
| <select id="itemCategory" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-transparent"> | |
| <option value="Dairy">Dairy</option> | |
| <option value="Produce">Produce</option> | |
| <option value="Pantry">Pantry</option> | |
| <option value="Meat">Meat</option> | |
| <option value="Beverages">Beverages</option> | |
| <option value="Frozen">Frozen</option> | |
| <option value="Other">Other</option> | |
| </select> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="itemNotes" class="block text-sm font-medium text-gray-700 mb-1">Notes (Optional)</label> | |
| <textarea id="itemNotes" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-transparent" placeholder="Any specific details..."></textarea> | |
| </div> | |
| <div class="flex justify-end space-x-3"> | |
| <button type="button" id="cancelAddBtn" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition-all"> | |
| Cancel | |
| </button> | |
| <button type="submit" class="px-6 py-2 bg-emerald-500 hover:bg-emerald-600 text-white rounded-lg shadow-md transition-all flex items-center"> | |
| <i class="fas fa-save mr-2"></i> Save Item | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Restock Confirmation Modal --> | |
| <div id="restockModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-md mx-4"> | |
| <div class="p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-bold text-gray-800">Item Restocked</h3> | |
| <button id="closeRestockModalBtn" class="text-gray-500 hover:text-gray-700"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <p class="mb-6 text-gray-700">Are you sure you want to mark <span id="restockItemName" class="font-semibold"></span> as restocked? This will remove it from your out-of-stock list.</p> | |
| <input type="hidden" id="restockItemId"> | |
| <div class="flex justify-end space-x-3"> | |
| <button type="button" id="cancelRestockBtn" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition-all"> | |
| Cancel | |
| </button> | |
| <button type="button" id="confirmRestockBtn" class="px-6 py-2 bg-emerald-500 hover:bg-emerald-600 text-white rounded-lg shadow-md transition-all flex items-center"> | |
| <i class="fas fa-check mr-2"></i> Confirm Restock | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Initialize with empty arrays if localStorage is empty | |
| let items = JSON.parse(localStorage.getItem('kitchenStockItems')) || []; | |
| let recentItems = JSON.parse(localStorage.getItem('recentKitchenItems')) || []; | |
| // Clear recent items if no items exist | |
| if (items.length === 0) { | |
| recentItems = []; | |
| localStorage.setItem('recentKitchenItems', JSON.stringify(recentItems)); | |
| } | |
| // DOM Elements | |
| const itemsContainer = document.getElementById('itemsContainer'); | |
| const emptyState = document.getElementById('emptyState'); | |
| const addItemBtn = document.getElementById('addItemBtn'); | |
| const addFirstItemBtn = document.getElementById('addFirstItemBtn'); | |
| const addItemModal = document.getElementById('addItemModal'); | |
| const closeModalBtn = document.getElementById('closeModalBtn'); | |
| const cancelAddBtn = document.getElementById('cancelAddBtn'); | |
| const addItemForm = document.getElementById('addItemForm'); | |
| const searchInput = document.getElementById('searchInput'); | |
| const restockModal = document.getElementById('restockModal'); | |
| const closeRestockModalBtn = document.getElementById('closeRestockModalBtn'); | |
| const cancelRestockBtn = document.getElementById('cancelRestockBtn'); | |
| const confirmRestockBtn = document.getElementById('confirmRestockBtn'); | |
| const restockItemName = document.getElementById('restockItemName'); | |
| const restockItemId = document.getElementById('restockItemId'); | |
| const outOfStockCount = document.getElementById('outOfStockCount'); | |
| const totalItemsCount = document.getElementById('totalItemsCount'); | |
| const recentItemsCount = document.getElementById('recentItemsCount'); | |
| // Event Listeners | |
| addItemBtn.addEventListener('click', openAddItemModal); | |
| addFirstItemBtn.addEventListener('click', openAddItemModal); | |
| closeModalBtn.addEventListener('click', closeAddItemModal); | |
| cancelAddBtn.addEventListener('click', closeAddItemModal); | |
| addItemForm.addEventListener('submit', handleAddItem); | |
| searchInput.addEventListener('input', filterItems); | |
| closeRestockModalBtn.addEventListener('click', closeRestockModal); | |
| cancelRestockBtn.addEventListener('click', closeRestockModal); | |
| confirmRestockBtn.addEventListener('click', handleRestock); | |
| // Initialize the app | |
| document.addEventListener('DOMContentLoaded', init); | |
| function init() { | |
| renderItems(); | |
| updateStats(); | |
| } | |
| // Render all items | |
| function renderItems(filteredItems = null) { | |
| const itemsToRender = filteredItems || items; | |
| if (itemsToRender.length === 0) { | |
| emptyState.classList.remove('hidden'); | |
| itemsContainer.innerHTML = ''; | |
| itemsContainer.appendChild(emptyState); | |
| return; | |
| } | |
| emptyState.classList.add('hidden'); | |
| itemsContainer.innerHTML = ''; | |
| itemsToRender.forEach((item, index) => { | |
| const itemCard = document.createElement('div'); | |
| itemCard.className = 'item-card bg-white rounded-lg shadow-sm p-4 mb-3 border-l-4 border-red-500 hover:shadow-md'; | |
| itemCard.innerHTML = ` | |
| <div class="flex justify-between items-start"> | |
| <div> | |
| <h3 class="font-semibold text-lg text-gray-800">${item.name}</h3> | |
| <div class="flex items-center mt-1"> | |
| <span class="text-xs px-2 py-1 rounded-full ${getCategoryColor(item.category)} mr-2">${item.category}</span> | |
| <span class="text-xs text-gray-500"><i class="far fa-clock mr-1"></i> ${formatDate(item.dateAdded)}</span> | |
| </div> | |
| ${item.notes ? `<p class="text-sm text-gray-600 mt-2">${item.notes}</p>` : ''} | |
| </div> | |
| <button class="restock-btn px-3 py-1 bg-emerald-500 hover:bg-emerald-600 text-white text-sm rounded-full transition-all" data-id="${index}"> | |
| <i class="fas fa-check mr-1"></i> Restocked | |
| </button> | |
| </div> | |
| `; | |
| itemsContainer.appendChild(itemCard); | |
| }); | |
| // Add event listeners to all restock buttons | |
| document.querySelectorAll('.restock-btn').forEach(btn => { | |
| btn.addEventListener('click', (e) => { | |
| const itemId = e.currentTarget.getAttribute('data-id'); | |
| openRestockModal(itemId); | |
| }); | |
| }); | |
| } | |
| // Get category color class | |
| function getCategoryColor(category) { | |
| const colors = { | |
| 'Dairy': 'bg-blue-100 text-blue-800', | |
| 'Produce': 'bg-green-100 text-green-800', | |
| 'Pantry': 'bg-yellow-100 text-yellow-800', | |
| 'Meat': 'bg-red-100 text-red-800', | |
| 'Beverages': 'bg-indigo-100 text-indigo-800', | |
| 'Frozen': 'bg-purple-100 text-purple-800', | |
| 'Other': 'bg-gray-100 text-gray-800' | |
| }; | |
| return colors[category] || 'bg-gray-100 text-gray-800'; | |
| } | |
| // Format date | |
| function formatDate(dateString) { | |
| const date = new Date(dateString); | |
| return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); | |
| } | |
| // Open Add Item Modal | |
| function openAddItemModal() { | |
| addItemModal.classList.remove('hidden'); | |
| document.getElementById('itemName').focus(); | |
| } | |
| // Close Add Item Modal | |
| function closeAddItemModal() { | |
| addItemModal.classList.add('hidden'); | |
| addItemForm.reset(); | |
| } | |
| // Open Restock Modal | |
| function openRestockModal(itemId) { | |
| const item = items[itemId]; | |
| restockItemName.textContent = item.name; | |
| restockItemId.value = itemId; | |
| restockModal.classList.remove('hidden'); | |
| } | |
| // Close Restock Modal | |
| function closeRestockModal() { | |
| restockModal.classList.add('hidden'); | |
| } | |
| // Handle Add Item Form Submission | |
| function handleAddItem(e) { | |
| e.preventDefault(); | |
| const name = document.getElementById('itemName').value.trim(); | |
| const category = document.getElementById('itemCategory').value; | |
| const notes = document.getElementById('itemNotes').value.trim(); | |
| const newItem = { | |
| name, | |
| category, | |
| notes, | |
| dateAdded: new Date().toISOString() | |
| }; | |
| // Add to items list | |
| items.unshift(newItem); | |
| // Add to recent items (only if not already there) | |
| if (!recentItems.some(item => item.name === newItem.name && item.dateAdded === newItem.dateAdded)) { | |
| recentItems.unshift(newItem); | |
| // Keep only the 5 most recent items | |
| if (recentItems.length > 5) { | |
| recentItems = recentItems.slice(0, 5); | |
| } | |
| } | |
| saveItems(); | |
| renderItems(); | |
| updateStats(); | |
| closeAddItemModal(); | |
| // Show success animation | |
| const successIcon = document.createElement('div'); | |
| successIcon.className = 'fixed bottom-6 right-6 w-16 h-16 rounded-full bg-emerald-500 flex items-center justify-center text-white text-2xl shadow-lg pulse'; | |
| successIcon.innerHTML = '<i class="fas fa-check"></i>'; | |
| document.body.appendChild(successIcon); | |
| setTimeout(() => { | |
| successIcon.classList.remove('pulse'); | |
| setTimeout(() => { | |
| successIcon.remove(); | |
| }, 300); | |
| }, 2000); | |
| } | |
| // Handle Restock | |
| function handleRestock() { | |
| const itemId = restockItemId.value; | |
| const restockedItem = items[itemId]; | |
| // Remove from items list | |
| items.splice(itemId, 1); | |
| // Add to recent items (only if not already there) | |
| if (!recentItems.some(item => item.name === restockedItem.name && item.dateAdded === restockedItem.dateAdded)) { | |
| recentItems.unshift(restockedItem); | |
| // Keep only the 5 most recent items | |
| if (recentItems.length > 5) { | |
| recentItems = recentItems.slice(0, 5); | |
| } | |
| } | |
| saveItems(); | |
| renderItems(); | |
| updateStats(); | |
| closeRestock | |
| </html> |