Created
March 13, 2026 17:07
-
-
Save pksbogastro/e224617ea70c695a83cfa22bc21f2782 to your computer and use it in GitHub Desktop.
Einkaufen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="de"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <title>Einkaufsliste Stabil</title> | |
| <style> | |
| :root { --primary: #4CAF50; --secondary: #2196F3; --danger: #ff5252; --bg: #f4f4f9; } | |
| body { font-family: sans-serif; background: var(--bg); margin: 0; padding: 10px; text-align: center; } | |
| /* Header-Bereich fest fixiert */ | |
| .header-area { background: white; padding: 12px; border-radius: 15px; margin-bottom: 15px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } | |
| select { width: 100%; padding: 12px; font-size: 18px; font-weight: bold; border: 2px solid var(--secondary); border-radius: 8px; margin-bottom: 10px; } | |
| .btn-row { display: flex; gap: 5px; margin-bottom: 5px; } | |
| button { padding: 12px; border: none; border-radius: 10px; cursor: pointer; font-weight: bold; font-size: 14px; color: #333; } | |
| .btn-add { background: var(--primary); color: white; width: 95%; padding: 15px; margin: 5px auto; display: block; } | |
| .btn-mode { background: var(--secondary); color: white; width: 95%; padding: 15px; margin: 5px auto; display: block; } | |
| .btn-multi { background: #673AB7; color: white; width: 95%; padding: 15px; margin: 5px auto; display: block; } | |
| /* Formular-Bereich */ | |
| #admin-panel { background: #fff; padding: 15px; border-radius: 12px; margin: 10px auto; border: 1px solid #ddd; display: none; width: 90%; } | |
| input[type="text"] { width: 90%; padding: 12px; margin-bottom: 10px; border: 1px solid #ccc; border-radius: 8px; font-size: 16px; } | |
| /* Artikel-Karten */ | |
| .card { background: white; border-radius: 12px; padding: 10px; margin-bottom: 8px; display: flex; align-items: center; box-shadow: 0 2px 4px rgba(0,0,0,0.08); position: relative; } | |
| .card img { width: 60px; height: 50px; object-fit: cover; border-radius: 6px; margin-right: 10px; } | |
| .card .info { flex-grow: 1; text-align: left; font-weight: bold; } | |
| .multi-checkbox { width: 25px; height: 25px; margin-right: 10px; display: none; } | |
| body.multi-mode .multi-checkbox { display: block; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header-area"> | |
| <select id="listSelect" onchange="changeList()"></select> | |
| <div id="nav-standard" class="btn-row"> | |
| <button style="flex:1; background:#eee;" onclick="newList()">+ Neu</button> | |
| <button style="flex:1; background:#eee;" onclick="renameList()">✏️ Name ändern</button> | |
| <button style="flex:1; background:var(--danger); color:white;" onclick="delList()">🗑️ Lösch</button> | |
| </div> | |
| <div id="nav-multi" class="btn-row" style="display:none;"> | |
| <button style="flex:3; background:#673AB7; color:white;" onclick="openCopyModal()">In Liste kopieren</button> | |
| <button style="flex:1; background:#ccc;" onclick="toggleMultiMode()">X</button> | |
| </div> | |
| </div> | |
| <div id="main-ui"> | |
| <button class="btn-add" onclick="toggleAdmin()">➕ Artikel hinzufügen</button> | |
| <div id="admin-panel"> | |
| <input type="text" id="pName" placeholder="Name..."> | |
| <input type="file" id="pImage" accept="image/*"> | |
| <button class="btn-add" onclick="saveProduct()">Speichern</button> | |
| </div> | |
| <button class="btn-multi" onclick="toggleMultiMode()">📦 Mehrere auswählen & kopieren</button> | |
| <button class="btn-mode" id="modeBtn" onclick="toggleMode()">➡️ Einkaufsmodus</button> | |
| </div> | |
| <div id="list-container"></div> | |
| <script> | |
| // Einfacher Datenspeicher | |
| let db = JSON.parse(localStorage.getItem('shop_final_v1')) || { active: "Standard", lists: { "Standard": [] } }; | |
| let isShopping = false; | |
| let isMulti = false; | |
| function sync() { | |
| localStorage.setItem('shop_final_v1', JSON.stringify(db)); | |
| render(); | |
| } | |
| function render() { | |
| const sel = document.getElementById('listSelect'); | |
| sel.innerHTML = ''; | |
| Object.keys(db.lists).forEach(l => { | |
| let o = document.createElement('option'); o.value = l; o.innerText = l; | |
| if(l === db.active) o.selected = true; | |
| sel.appendChild(o); | |
| }); | |
| document.body.className = isMulti ? 'multi-mode' : ''; | |
| document.getElementById('nav-standard').style.display = isMulti ? 'none' : 'flex'; | |
| document.getElementById('nav-multi').style.display = isMulti ? 'flex' : 'none'; | |
| document.getElementById('main-ui').style.display = isMulti ? 'none' : 'block'; | |
| const cont = document.getElementById('list-container'); | |
| cont.innerHTML = ''; | |
| (db.lists[db.active] || []).forEach(p => { | |
| if(isShopping && p.count <= 0) return; | |
| const card = document.createElement('div'); | |
| card.className = 'card'; | |
| card.innerHTML = ` | |
| <input type="checkbox" class="multi-checkbox" data-id="${p.id}"> | |
| <img src="${p.img || ''}"> | |
| <div class="info">${p.name}</div> | |
| <input type="number" value="${p.count}" style="width:40px" onchange="updQty(${p.id}, this.value)"> | |
| `; | |
| card.onclick = (e) => { | |
| if(isMulti && e.target.tagName !== 'INPUT') { | |
| const cb = card.querySelector('.multi-checkbox'); | |
| cb.checked = !cb.checked; | |
| } | |
| }; | |
| cont.appendChild(card); | |
| }); | |
| } | |
| function toggleAdmin() { | |
| const p = document.getElementById('admin-panel'); | |
| p.style.display = p.style.display === 'none' ? 'block' : 'none'; | |
| } | |
| function saveProduct() { | |
| const n = document.getElementById('pName').value; | |
| const f = document.getElementById('pImage').files[0]; | |
| if(!n) return alert("Name?"); | |
| if(!f) { | |
| db.lists[db.active].push({ id: Date.now(), name: n, img: '', count: 1 }); | |
| sync(); toggleAdmin(); return; | |
| } | |
| const r = new FileReader(); | |
| r.onload = e => { | |
| db.lists[db.active].push({ id: Date.now(), name: n, img: e.target.result, count: 1 }); | |
| sync(); toggleAdmin(); | |
| }; | |
| r.readAsDataURL(f); | |
| } | |
| function renameList() { | |
| const old = db.active; | |
| const n = prompt("Neuer Name für '" + old + "':", old); | |
| if(n && n !== old) { | |
| db.lists[n] = db.lists[old]; | |
| delete db.lists[old]; | |
| db.active = n; | |
| sync(); | |
| } | |
| } | |
| function newList() { | |
| const n = prompt("Name der Liste:"); | |
| if(n) { db.lists[n] = []; db.active = n; sync(); } | |
| } | |
| function toggleMultiMode() { isMulti = !isMulti; render(); } | |
| function changeList() { db.active = document.getElementById('listSelect').value; sync(); } | |
| function updQty(id, v) { | |
| const p = db.lists[db.active].find(x => x.id === id); | |
| if(p) p.count = parseInt(v); | |
| localStorage.setItem('shop_final_v1', JSON.stringify(db)); | |
| } | |
| render(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment