| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Newborn Baby Shopping List</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"> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=Playfair+Display:wght@400;500;600;700&display=swap'); |
| |
| body { |
| font-family: 'Poppins', sans-serif; |
| background-color: #fafafa; |
| } |
| |
| .title-font { |
| font-family: 'Playfair Display', serif; |
| } |
| |
| .category-card { |
| transition: all 0.3s ease; |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); |
| } |
| |
| .category-card:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 15px 25px rgba(0, 0, 0, 0.1); |
| } |
| |
| .checkmark { |
| display: inline-block; |
| width: 22px; |
| height: 22px; |
| border: 2px solid #e2e8f0; |
| border-radius: 6px; |
| position: relative; |
| cursor: pointer; |
| transition: all 0.2s ease; |
| } |
| |
| .checkmark.checked { |
| background-color: #10b981; |
| border-color: #10b981; |
| } |
| |
| .checkmark.checked:after { |
| content: ""; |
| position: absolute; |
| left: 6px; |
| top: 2px; |
| width: 5px; |
| height: 10px; |
| border: solid white; |
| border-width: 0 2px 2px 0; |
| transform: rotate(45deg); |
| } |
| |
| .progress-bar { |
| height: 10px; |
| border-radius: 10px; |
| background-color: #e2e8f0; |
| box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); |
| } |
| |
| .progress-fill { |
| height: 100%; |
| border-radius: 10px; |
| background: linear-gradient(90deg, #3b82f6, #8b5cf6); |
| transition: width 0.5s ease; |
| box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3); |
| } |
| |
| .print-area { |
| background-color: white; |
| padding: 24px; |
| border-radius: 12px; |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); |
| } |
| |
| .timeline-item { |
| position: relative; |
| padding-left: 32px; |
| margin-bottom: 24px; |
| } |
| |
| .timeline-item:before { |
| content: ''; |
| position: absolute; |
| left: 0; |
| top: 0; |
| width: 18px; |
| height: 18px; |
| border-radius: 50%; |
| background: linear-gradient(135deg, #8b5cf6, #3b82f6); |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| } |
| |
| .timeline-item:after { |
| content: ''; |
| position: absolute; |
| left: 8px; |
| top: 18px; |
| width: 2px; |
| height: 100%; |
| background-color: #e2e8f0; |
| } |
| |
| .timeline-item:last-child:after { |
| display: none; |
| } |
| |
| .category-icon { |
| width: 40px; |
| height: 40px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| border-radius: 10px; |
| margin-right: 12px; |
| color: white; |
| } |
| |
| .input-focus { |
| transition: all 0.3s ease; |
| } |
| |
| .input-focus:focus { |
| box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.2); |
| } |
| |
| .floating-btn { |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); |
| transition: all 0.3s ease; |
| } |
| |
| .floating-btn:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 15px 20px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); |
| } |
| |
| .suggestion-card { |
| transition: all 0.3s ease; |
| border: 1px solid #e2e8f0; |
| } |
| |
| .suggestion-card:hover { |
| transform: translateY(-3px); |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); |
| border-color: #8b5cf6; |
| } |
| |
| .gradient-text { |
| background: linear-gradient(90deg, #3b82f6, #8b5cf6); |
| -webkit-background-clip: text; |
| background-clip: text; |
| color: transparent; |
| } |
| |
| .custom-number-input::-webkit-inner-spin-button, |
| .custom-number-input::-webkit-outer-spin-button { |
| -webkit-appearance: none; |
| margin: 0; |
| } |
| |
| .custom-number-input { |
| -moz-appearance: textfield; |
| } |
| |
| .animate-pulse { |
| animation: pulse 2s infinite; |
| } |
| |
| @keyframes pulse { |
| 0% { |
| opacity: 0.6; |
| } |
| 50% { |
| opacity: 1; |
| } |
| 100% { |
| opacity: 0.6; |
| } |
| } |
| |
| .tooltip { |
| position: relative; |
| } |
| |
| .tooltip .tooltip-text { |
| visibility: hidden; |
| width: 120px; |
| background-color: #333; |
| color: #fff; |
| text-align: center; |
| border-radius: 6px; |
| padding: 5px; |
| position: absolute; |
| z-index: 1; |
| bottom: 125%; |
| left: 50%; |
| margin-left: -60px; |
| opacity: 0; |
| transition: opacity 0.3s; |
| } |
| |
| .tooltip .tooltip-text::after { |
| content: ""; |
| position: absolute; |
| top: 100%; |
| left: 50%; |
| margin-left: -5px; |
| border-width: 5px; |
| border-style: solid; |
| border-color: #333 transparent transparent transparent; |
| } |
| |
| .tooltip:hover .tooltip-text { |
| visibility: visible; |
| opacity: 1; |
| } |
| </style> |
| </head> |
| <body class="min-h-screen bg-gray-50"> |
| |
| <div class="relative overflow-hidden"> |
| <div class="absolute inset-0 bg-gradient-to-r from-blue-100 to-purple-100 opacity-20"></div> |
| <div class="container mx-auto px-4 py-12 relative"> |
| <div class="text-center mb-8"> |
| <h1 class="title-font text-5xl font-bold text-gray-900 mb-4">Newborn Baby Shopping List</h1> |
| <p class="text-lg text-gray-600 max-w-3xl mx-auto"> |
| Prepare everything you need for your little one's arrival with our comprehensive checklist |
| </p> |
| </div> |
| |
| |
| <div class="bg-white rounded-xl shadow-lg p-8 mb-8 relative overflow-hidden"> |
| <div class="absolute top-0 right-0 w-32 h-32 bg-blue-50 rounded-full -mr-10 -mt-10"></div> |
| <div class="absolute bottom-0 left-0 w-24 h-24 bg-purple-50 rounded-full -ml-8 -mb-8"></div> |
| |
| <div class="relative z-10"> |
| <div class="flex justify-between items-center mb-4"> |
| <h2 class="text-2xl font-semibold text-gray-800">Your Preparation Progress</h2> |
| <span class="text-2xl font-bold gradient-text" id="progress-percentage">0%</span> |
| </div> |
| <div class="progress-bar mb-6"> |
| <div class="progress-fill" id="progress-fill" style="width: 0%"></div> |
| </div> |
| <div class="flex justify-between text-sm text-gray-600"> |
| <span id="items-completed">0 items completed</span> |
| <span id="items-total">0 total items</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="container mx-auto px-4 pb-16"> |
| <div class="flex flex-col lg:flex-row gap-8"> |
| |
| <div class="lg:w-1/4"> |
| <div class="bg-white rounded-xl shadow-lg p-6 sticky top-4"> |
| <h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center"> |
| <i class="fas fa-list-check mr-3 text-purple-500"></i> |
| Categories |
| </h2> |
| <ul class="space-y-2"> |
| <li> |
| <button onclick="showCategory('nursery')" class="category-btn w-full text-left px-4 py-3 rounded-lg hover:bg-blue-50 hover:text-blue-600 transition flex items-center active-category" data-category="nursery"> |
| <div class="category-icon bg-blue-500"> |
| <i class="fas fa-baby-carriage"></i> |
| </div> |
| Nursery |
| </button> |
| </li> |
| <li> |
| <button onclick="showCategory('clothing')" class="category-btn w-full text-left px-4 py-3 rounded-lg hover:bg-pink-50 hover:text-pink-600 transition flex items-center" data-category="clothing"> |
| <div class="category-icon bg-pink-500"> |
| <i class="fas fa-tshirt"></i> |
| </div> |
| Clothing |
| </button> |
| </li> |
| <li> |
| <button onclick="showCategory('feeding')" class="category-btn w-full text-left px-4 py-3 rounded-lg hover:bg-yellow-50 hover:text-yellow-600 transition flex items-center" data-category="feeding"> |
| <div class="category-icon bg-yellow-500"> |
| <i class="fas fa-bottle-water"></i> |
| </div> |
| Feeding |
| </button> |
| </li> |
| <li> |
| <button onclick="showCategory('diapering')" class="category-btn w-full text-left px-4 py-3 rounded-lg hover:bg-green-50 hover:text-green-600 transition flex items-center" data-category="diapering"> |
| <div class="category-icon bg-green-500"> |
| <i class="fas fa-baby"></i> |
| </div> |
| Diapering |
| </button> |
| </li> |
| <li> |
| <button onclick="showCategory('bathing')" class="category-btn w-full text-left px-4 py-3 rounded-lg hover:bg-indigo-50 hover:text-indigo-600 transition flex items-center" data-category="bathing"> |
| <div class="category-icon bg-indigo-500"> |
| <i class="fas fa-bath"></i> |
| </div> |
| Bathing |
| </button> |
| </li> |
| <li> |
| <button onclick="showCategory('health')" class="category-btn w-full text-left px-4 py-3 rounded-lg hover:bg-red-50 hover:text-red-600 transition flex items-center" data-category="health"> |
| <div class="category-icon bg-red-500"> |
| <i class="fas fa-first-aid"></i> |
| </div> |
| Health & Safety |
| </button> |
| </li> |
| <li> |
| <button onclick="showCategory('travel')" class="category-btn w-full text-left px-4 py-3 rounded-lg hover:bg-purple-50 hover:text-purple-600 transition flex items-center" data-category="travel"> |
| <div class="category-icon bg-purple-500"> |
| <i class="fas fa-car"></i> |
| </div> |
| Travel |
| </button> |
| </li> |
| </ul> |
| |
| <div class="mt-10"> |
| <h3 class="text-lg font-medium text-gray-800 mb-4 flex items-center"> |
| <i class="fas fa-calendar-alt mr-3 text-purple-500"></i> |
| Preparation Timeline |
| </h3> |
| <div class="timeline pl-2"> |
| <div class="timeline-item"> |
| <h4 class="font-medium text-gray-800">3 Months Before</h4> |
| <p class="text-sm text-gray-600">Start researching and budgeting</p> |
| </div> |
| <div class="timeline-item"> |
| <h4 class="font-medium text-gray-800">2 Months Before</h4> |
| <p class="text-sm text-gray-600">Purchase nursery furniture</p> |
| </div> |
| <div class="timeline-item"> |
| <h4 class="font-medium text-gray-800">1 Month Before</h4> |
| <p class="text-sm text-gray-600">Buy essential clothing and diapers</p> |
| </div> |
| <div class="timeline-item"> |
| <h4 class="font-medium text-gray-800">2 Weeks Before</h4> |
| <p class="text-sm text-gray-600">Pack hospital bag</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="lg:w-3/4"> |
| <div class="bg-white rounded-xl shadow-lg p-8 mb-8"> |
| <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8 gap-4"> |
| <div> |
| <h2 class="text-3xl font-semibold text-gray-800" id="current-category">Nursery Items</h2> |
| <p class="text-gray-500 mt-1" id="category-description">Essential items for your baby's nursery</p> |
| </div> |
| <div class="flex gap-3"> |
| <button onclick="printList()" class="bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white px-5 py-2.5 rounded-lg flex items-center floating-btn"> |
| <i class="fas fa-print mr-2"></i> Print List |
| </button> |
| <button onclick="saveList()" class="bg-white border border-gray-200 hover:bg-gray-50 text-gray-800 px-5 py-2.5 rounded-lg flex items-center floating-btn"> |
| <i class="fas fa-save mr-2"></i> Save |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="mb-8"> |
| <div class="flex flex-col md:flex-row gap-4"> |
| <div class="relative flex-grow"> |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
| <i class="fas fa-search text-gray-400"></i> |
| </div> |
| <input type="text" id="search-items" placeholder="Search items..." class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg input-focus focus:ring-0 focus:border-purple-500"> |
| </div> |
| <div class="relative"> |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
| <i class="fas fa-filter text-gray-400"></i> |
| </div> |
| <select id="filter-timing" class="border border-gray-200 rounded-lg px-10 py-3 input-focus focus:ring-0 focus:border-purple-500 appearance-none"> |
| <option value="all">All Items</option> |
| <option value="before">Before Hospital</option> |
| <option value="after">After Hospital</option> |
| </select> |
| <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none"> |
| <i class="fas fa-chevron-down text-gray-400"></i> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="print-area" id="items-container"> |
| |
| </div> |
| |
| |
| <div class="mt-12"> |
| <div class="flex justify-between items-center mb-6"> |
| <h3 class="text-2xl font-semibold text-gray-800">Suggested Items</h3> |
| <div class="text-sm text-gray-500">Based on popular choices</div> |
| </div> |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" id="suggestions-container"> |
| |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <button onclick="addCustomItem()" class="fixed bottom-8 right-8 w-14 h-14 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full flex items-center justify-center shadow-xl floating-btn animate-pulse"> |
| <i class="fas fa-plus text-xl"></i> |
| </button> |
|
|
| <script> |
| |
| const shoppingList = { |
| nursery: [ |
| { name: "Crib or bassinet", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Mattress", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Mattress pad", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Crib sheets (2-3)", quantity: 3, purchased: false, timing: "before", priority: "high" }, |
| { name: "Waterproof mattress cover", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Rocking chair or glider", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Dresser or changing table", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Night light", quantity: 1, purchased: false, timing: "before", priority: "low" }, |
| { name: "Baby monitor", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Humidifier", quantity: 1, purchased: false, timing: "before", priority: "medium" } |
| ], |
| clothing: [ |
| { name: "Onesies (5-7)", quantity: 7, purchased: false, timing: "before", priority: "high" }, |
| { name: "Sleepers (3-5)", quantity: 5, purchased: false, timing: "before", priority: "high" }, |
| { name: "Socks or booties (5-7 pairs)", quantity: 7, purchased: false, timing: "before", priority: "high" }, |
| { name: "Hats (2-3)", quantity: 3, purchased: false, timing: "before", priority: "high" }, |
| { name: "Mittens (to prevent scratching)", quantity: 2, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Swaddle blankets (3-5)", quantity: 5, purchased: false, timing: "before", priority: "high" }, |
| { name: "Receiving blankets (5-7)", quantity: 7, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Outfits for going home (2)", quantity: 2, purchased: false, timing: "before", priority: "high" } |
| ], |
| feeding: [ |
| { name: "Breast pump (if breastfeeding)", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Nursing bras (3-4)", quantity: 4, purchased: false, timing: "before", priority: "high" }, |
| { name: "Nursing pads", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Nipple cream", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Bottles (6-8)", quantity: 8, purchased: false, timing: "before", priority: "high" }, |
| { name: "Bottle brush", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Formula (if not breastfeeding)", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Burp cloths (5-7)", quantity: 7, purchased: false, timing: "before", priority: "high" }, |
| { name: "Bibs (5-7)", quantity: 7, purchased: false, timing: "before", priority: "medium" } |
| ], |
| diapering: [ |
| { name: "Diapers (newborn size, 1-2 packs)", quantity: 2, purchased: false, timing: "before", priority: "high" }, |
| { name: "Diaper pail", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Diaper bag", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Diaper rash cream", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Baby wipes (2-3 packs)", quantity: 3, purchased: false, timing: "before", priority: "high" }, |
| { name: "Changing pad", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Changing pad covers (2-3)", quantity: 3, purchased: false, timing: "before", priority: "medium" } |
| ], |
| bathing: [ |
| { name: "Baby bathtub", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Baby shampoo & body wash", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Baby lotion", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Hooded towels (2-3)", quantity: 3, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Washcloths (5-7)", quantity: 7, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Soft-bristled hair brush", quantity: 1, purchased: false, timing: "before", priority: "low" }, |
| { name: "Nail clippers or file", quantity: 1, purchased: false, timing: "before", priority: "high" } |
| ], |
| health: [ |
| { name: "Digital thermometer", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Nasal aspirator", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Baby-safe nail scissors", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Medicine dropper", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Infant acetaminophen", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Baby sunscreen (for after 6 months)", quantity: 1, purchased: false, timing: "after", priority: "low" }, |
| { name: "First aid kit", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Outlet covers", quantity: 10, purchased: false, timing: "before", priority: "high" }, |
| { name: "Cabinet locks", quantity: 4, purchased: false, timing: "before", priority: "high" } |
| ], |
| travel: [ |
| { name: "Infant car seat", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Stroller", quantity: 1, purchased: false, timing: "before", priority: "high" }, |
| { name: "Baby carrier or wrap", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Car seat cover (for cold weather)", quantity: 1, purchased: false, timing: "before", priority: "low" }, |
| { name: "Stroller blanket", quantity: 1, purchased: false, timing: "before", priority: "medium" }, |
| { name: "Car window shades", quantity: 2, purchased: false, timing: "after", priority: "low" } |
| ] |
| }; |
| |
| |
| const categoryDescriptions = { |
| nursery: "Essential items for your baby's nursery and sleep space", |
| clothing: "All the clothing essentials for your newborn", |
| feeding: "Everything you need for feeding your baby", |
| diapering: "Diapering essentials for your newborn", |
| bathing: "Items for keeping your baby clean and fresh", |
| health: "Health and safety items for your baby", |
| travel: "Items for traveling with your newborn" |
| }; |
| |
| |
| const suggestedItems = [ |
| { name: "White noise machine", category: "nursery", timing: "before", icon: "fas fa-volume-up", color: "bg-blue-100 text-blue-600" }, |
| { name: "Diaper genie", category: "diapering", timing: "before", icon: "fas fa-trash-alt", color: "bg-green-100 text-green-600" }, |
| { name: "Baby swing", category: "nursery", timing: "before", icon: "fas fa-child", color: "bg-blue-100 text-blue-600" }, |
| { name: "Wipe warmer", category: "diapering", timing: "before", icon: "fas fa-temperature-high", color: "bg-green-100 text-green-600" }, |
| { name: "Bottle sterilizer", category: "feeding", timing: "before", icon: "fas fa-spray-can", color: "bg-yellow-100 text-yellow-600" }, |
| { name: "Baby food maker", category: "feeding", timing: "after", icon: "fas fa-blender", color: "bg-yellow-100 text-yellow-600" }, |
| { name: "Nursing pillow", category: "feeding", timing: "before", icon: "fas fa-pillow", color: "bg-yellow-100 text-yellow-600" }, |
| { name: "Baby gym", category: "nursery", timing: "before", icon: "fas fa-dumbbell", color: "bg-blue-100 text-blue-600" }, |
| { name: "Sound machine", category: "nursery", timing: "before", icon: "fas fa-music", color: "bg-blue-100 text-blue-600" } |
| ]; |
| |
| |
| let currentCategory = 'nursery'; |
| |
| |
| function loadShoppingList() { |
| const savedList = localStorage.getItem('newbornShoppingList'); |
| if (savedList) { |
| Object.assign(shoppingList, JSON.parse(savedList)); |
| } |
| } |
| |
| |
| function saveShoppingList() { |
| localStorage.setItem('newbornShoppingList', JSON.stringify(shoppingList)); |
| showAlert('List saved successfully!', 'success'); |
| } |
| |
| |
| function showAlert(message, type) { |
| const alert = document.createElement('div'); |
| alert.className = `fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg text-white flex items-center ${ |
| type === 'success' ? 'bg-green-500' : 'bg-red-500' |
| } animate__animated animate__fadeInDown`; |
| alert.innerHTML = ` |
| <i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-triangle'} mr-3"></i> |
| <span>${message}</span> |
| `; |
| document.body.appendChild(alert); |
| |
| setTimeout(() => { |
| alert.classList.add('animate__fadeOutUp'); |
| setTimeout(() => { |
| alert.remove(); |
| }, 500); |
| }, 3000); |
| } |
| |
| |
| function togglePurchased(category, index) { |
| shoppingList[category][index].purchased = !shoppingList[category][index].purchased; |
| renderItems(currentCategory); |
| updateProgress(); |
| saveShoppingList(); |
| } |
| |
| |
| function updateQuantity(category, index, value) { |
| shoppingList[category][index].quantity = parseInt(value) || 0; |
| saveShoppingList(); |
| } |
| |
| |
| function addCustomItem() { |
| const itemName = prompt("Enter the name of the item you want to add:"); |
| if (itemName && itemName.trim() !== '') { |
| shoppingList[currentCategory].push({ |
| name: itemName.trim(), |
| quantity: 1, |
| purchased: false, |
| timing: "before", |
| priority: "medium" |
| }); |
| renderItems(currentCategory); |
| updateProgress(); |
| saveShoppingList(); |
| showAlert(`${itemName.trim()} added to your list!`, 'success'); |
| } |
| } |
| |
| |
| function removeItem(category, index) { |
| if (confirm("Are you sure you want to remove this item?")) { |
| const removedItem = shoppingList[category][index].name; |
| shoppingList[category].splice(index, 1); |
| renderItems(currentCategory); |
| updateProgress(); |
| saveShoppingList(); |
| showAlert(`${removedItem} removed from your list`, 'success'); |
| } |
| } |
| |
| |
| function showCategory(category) { |
| currentCategory = category; |
| |
| |
| document.querySelectorAll('.category-btn').forEach(btn => { |
| btn.classList.remove('active-category'); |
| btn.classList.remove('bg-blue-50', 'text-blue-600'); |
| btn.classList.remove('bg-pink-50', 'text-pink-600'); |
| btn.classList.remove('bg-yellow-50', 'text-yellow-600'); |
| btn.classList.remove('bg-green-50', 'text-green-600'); |
| btn.classList.remove('bg-indigo-50', 'text-indigo-600'); |
| btn.classList.remove('bg-red-50', 'text-red-600'); |
| btn.classList.remove('bg-purple-50', 'text-purple-600'); |
| }); |
| |
| |
| const activeBtn = document.querySelector(`.category-btn[data-category="${category}"]`); |
| activeBtn.classList.add('active-category'); |
| |
| switch(category) { |
| case 'nursery': activeBtn.classList.add('bg-blue-50', 'text-blue-600'); break; |
| case 'clothing': activeBtn.classList.add('bg-pink-50', 'text-pink-600'); break; |
| case 'feeding': activeBtn.classList.add('bg-yellow-50', 'text-yellow-600'); break; |
| case 'diapering': activeBtn.classList.add('bg-green-50', 'text-green-600'); break; |
| case 'bathing': activeBtn.classList.add('bg-indigo-50', 'text-indigo-600'); break; |
| case 'health': activeBtn.classList.add('bg-red-50', 'text-red-600'); break; |
| case 'travel': activeBtn.classList.add('bg-purple-50', 'text-purple-600'); break; |
| } |
| |
| |
| let categoryTitle = ''; |
| switch(category) { |
| case 'nursery': categoryTitle = 'Nursery Items'; break; |
| case 'clothing': categoryTitle = 'Clothing Items'; break; |
| case 'feeding': categoryTitle = 'Feeding Items'; break; |
| case 'diapering': categoryTitle = 'Diapering Items'; break; |
| case 'bathing': categoryTitle = 'Bathing Items'; break; |
| case 'health': categoryTitle = 'Health & Safety Items'; break; |
| case 'travel': categoryTitle = 'Travel Items'; break; |
| } |
| document.getElementById('current-category').textContent = categoryTitle; |
| document.getElementById('category-description').textContent = categoryDescriptions[category]; |
| |
| renderItems(category); |
| renderSuggestions(); |
| } |
| |
| |
| function renderItems(category) { |
| const container = document.getElementById('items-container'); |
| const filterTiming = document.getElementById('filter-timing').value; |
| const searchQuery = document.getElementById('search-items').value.toLowerCase(); |
| |
| let itemsHTML = ` |
| <div class="mb-8"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-lg font-medium text-gray-800">${category.charAt(0).toUpperCase() + category.slice(1)} Checklist</h3> |
| <span class="text-sm text-gray-500">${shoppingList[category].length} items</span> |
| </div> |
| |
| <div class="overflow-hidden rounded-lg border border-gray-200"> |
| <table class="min-w-full divide-y divide-gray-200"> |
| <thead class="bg-gray-50"> |
| <tr> |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Item</th> |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Quantity</th> |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Timing</th> |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Priority</th> |
| <th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th> |
| </tr> |
| </thead> |
| <tbody class="bg-white divide-y divide-gray-200"> |
| `; |
| |
| const filteredItems = shoppingList[category].filter(item => { |
| const matchesSearch = item.name.toLowerCase().includes(searchQuery); |
| const matchesTiming = filterTiming === 'all' || item.timing === filterTiming; |
| return matchesSearch && matchesTiming; |
| }); |
| |
| if (filteredItems.length === 0) { |
| itemsHTML += ` |
| <tr> |
| <td colspan="6" class="px-6 py-4 text-center text-gray-500">No items found</td> |
| </tr> |
| `; |
| } else { |
| filteredItems.forEach((item, index) => { |
| |
| let priorityColor = ''; |
| let priorityText = ''; |
| switch(item.priority) { |
| case 'high': |
| priorityColor = 'bg-red-100 text-red-800'; |
| priorityText = 'High'; |
| break; |
| case 'medium': |
| priorityColor = 'bg-yellow-100 text-yellow-800'; |
| priorityText = 'Medium'; |
| break; |
| case 'low': |
| priorityColor = 'bg-green-100 text-green-800'; |
| priorityText = 'Low'; |
| break; |
| } |
| |
| itemsHTML += ` |
| <tr class="${item.purchased ? 'bg-gray-50' : ''}"> |
| <td class="px-6 py-4 whitespace-nowrap"> |
| <span onclick="togglePurchased('${category}', ${index})" class="checkmark ${item.purchased ? 'checked' : ''}"></span> |
| </td> |
| <td class="px-6 py-4"> |
| <div class="flex items-center"> |
| <div class="text-sm font-medium ${item.purchased ? 'text-gray-400 line-through' : 'text-gray-900'}">${item.name}</div> |
| </div> |
| </td> |
| <td class="px-6 py-4 whitespace-nowrap"> |
| <input type="number" min="1" value="${item.quantity}" |
| onchange="updateQuantity('${category}', ${index}, this.value)" |
| class="w-16 px-2 py-1 border border-gray-200 rounded focus:ring-0 focus:border-purple-500 custom-number-input"> |
| </td> |
| <td class="px-6 py-4 whitespace-nowrap"> |
| <span class="px-2 py-1 text-xs rounded-full ${item.timing === 'before' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800'}"> |
| ${item.timing === 'before' ? 'Before' : 'After'} |
| </span> |
| </td> |
| <td class="px-6 py-4 whitespace-nowrap"> |
| <span class="px-2 py-1 text-xs rounded-full ${priorityColor}"> |
| ${priorityText} |
| </span> |
| </td> |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |
| <button onclick="removeItem('${category}', ${index})" class="text-red-600 hover:text-red-900"> |
| <i class="fas fa-trash-alt"></i> |
| </button> |
| </td> |
| </tr> |
| `; |
| }); |
| } |
| |
| itemsHTML += ` |
| </tbody> |
| </table> |
| </div> |
| </div> |
| <button onclick="addCustomItem()" class="w-full bg-gray-50 hover:bg-gray-100 border-2 border-dashed border-gray-300 text-gray-600 px-4 py-6 rounded-lg flex flex-col items-center transition"> |
| <i class="fas fa-plus-circle text-2xl mb-2"></i> |
| <span>Add Custom Item</span> |
| </button> |
| `; |
| |
| container.innerHTML = itemsHTML; |
| } |
| |
| |
| function renderSuggestions() { |
| const container = document.getElementById('suggestions-container'); |
| let suggestionsHTML = ''; |
| |
| |
| const categorySuggestions = suggestedItems.filter(item => item.category === currentCategory); |
| |
| if (categorySuggestions.length === 0) { |
| suggestionsHTML = ` |
| <div class="col-span-3 text-center py-8"> |
| <i class="fas fa-lightbulb text-3xl text-yellow-400 mb-3"></i> |
| <p class="text-gray-500">No suggestions for this category</p> |
| </div> |
| `; |
| } else { |
| categorySuggestions.forEach((item, index) => { |
| suggestionsHTML += ` |
| <div class="suggestion-card bg-white rounded-lg p-5 flex flex-col"> |
| <div class="flex items-center mb-3"> |
| <div class="${item.color} w-10 h-10 rounded-full flex items-center justify-center mr-3"> |
| <i class="${item.icon}"></i> |
| </div> |
| <h4 class="font-medium text-gray-800">${item.name}</h4> |
| </div> |
| <div class="mt-auto flex justify-between items-center"> |
| <span class="text-xs px-2 py-1 rounded-full ${item.timing === 'before' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800'}"> |
| ${item.timing === 'before' ? 'Before hospital' : 'After hospital'} |
| </span> |
| <button onclick="addSuggestedItem(${index})" class="text-sm bg-white border border-purple-200 hover:bg-purple-50 text-purple-600 px-3 py-1 rounded-lg flex items-center"> |
| <i class="fas fa-plus mr-1"></i> Add |
| </button> |
| </div> |
| </div> |
| `; |
| }); |
| } |
| |
| container.innerHTML = suggestionsHTML; |
| } |
| |
| |
| function addSuggestedItem(index) { |
| const item = suggestedItems[index]; |
| shoppingList[item.category].push({ |
| name: item.name, |
| quantity: 1, |
| purchased: false, |
| timing: item.timing, |
| priority: "medium" |
| }); |
| renderItems(currentCategory); |
| updateProgress(); |
| saveShoppingList(); |
| showAlert(`${item.name} added to your list!`, 'success'); |
| } |
| |
| |
| function updateProgress() { |
| let totalItems = 0; |
| let completedItems = 0; |
| |
| |
| Object.values(shoppingList).forEach(category => { |
| category.forEach(item => { |
| totalItems++; |
| if (item.purchased) completedItems++; |
| }); |
| }); |
| |
| const percentage = totalItems > 0 ? Math.round((completedItems / totalItems) * 100) : 0; |
| |
| document.getElementById('progress-percentage').textContent = `${percentage}%`; |
| document.getElementById('progress-fill').style.width = `${percentage}%`; |
| document.getElementById('items-completed').textContent = `${completedItems} items completed`; |
| document.getElementById('items-total').textContent = `${totalItems} total items`; |
| } |
| |
| |
| function printList() { |
| const { jsPDF } = window.jspdf; |
| const doc = new jsPDF(); |
| |
| |
| doc.setFontSize(24); |
| doc.setTextColor(59, 130, 246); |
| doc.text('Newborn Baby Shopping List', 105, 20, { align: 'center' }); |
| |
| |
| doc.setFontSize(14); |
| doc.setTextColor(100, 116, 139); |
| doc.text('Everything you need for your little one', 105, 30, { align: 'center' }); |
| |
| |
| doc.setFontSize(10); |
| doc.setTextColor(100, 116, 139); |
| doc.text(`Generated on: ${new Date().toLocaleDateString()}`, 105, 38, { align: 'center' }); |
| |
| |
| const progress = document.getElementById('progress-percentage').textContent; |
| doc.setTextColor(59, 130, 246); |
| doc.text(`Preparation Progress: ${progress}`, 105, 46, { align: 'center' }); |
| |
| let yPosition = 60; |
| |
| |
| Object.entries(shoppingList).forEach(([category, items]) => { |
| if (items.length > 0) { |
| |
| doc.setFontSize(16); |
| doc.setTextColor(15, 23, 42); |
| doc.text(category.charAt(0).toUpperCase() + category.slice(1) + ':', 15, yPosition); |
| yPosition += 8; |
| |
| |
| doc.setDrawColor(226, 232, 240); |
| doc.setLineWidth(0.5); |
| doc.line(15, yPosition, 195, yPosition); |
| yPosition += 5; |
| |
| |
| doc.setFontSize(12); |
| items.forEach(item => { |
| if (yPosition > 280) { |
| doc.addPage(); |
| yPosition = 20; |
| } |
| |
| doc.setTextColor(item.purchased ? 148, 163, 184 : 15, 23, 42); |
| const status = item.purchased ? '✓ Purchased' : '○ Needed'; |
| |
| |
| doc.text(`- ${item.name}`, 20, yPosition); |
| doc.text(status, 180, yPosition, { align: 'right' }); |
| yPosition += 5; |
| |
| |
| doc.text(` Qty: ${item.quantity} | Timing: ${item.timing === 'before' ? 'Before hospital' : 'After hospital'}`, 20, yPosition); |
| yPosition += 5; |
| |
| |
| doc.text(` Priority: ${item.priority}`, 20, yPosition); |
| yPosition += 8; |
| }); |
| |
| yPosition += 5; |
| } |
| }); |
| |
| |
| doc.setFontSize(10); |
| doc.setTextColor(100, 116, 139); |
| doc.text('Generated by Newborn Baby Shopping List - www.babyshoppinglist.com', 105, 290, { align: 'center' }); |
| |
| |
| doc.save('newborn-shopping-list.pdf'); |
| } |
| |
| |
| function saveList() { |
| saveShoppingList(); |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded', () => { |
| loadShoppingList(); |
| showCategory('nursery'); |
| updateProgress(); |
| |
| |
| document.getElementById('search-items').addEventListener('input', () => { |
| renderItems(currentCategory); |
| }); |
| |
| document.getElementById('filter-timing').addEventListener('change', () => { |
| renderItems(currentCategory); |
| }); |
| }); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=davidkkkk/baby" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |