Ihr Kalkulator für die richtige Menge an Getränken für jeden Anlass
eta charset="utf-8" />
eta name="viewport" content="width=device-width, initial-scale=1" />
itle>Getränke-Kalkulator – Widget
tyle>
/* Fallback styles if Shadow DOM is not supported */
body { font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"; background:#0b0c10; color:#e6e6e6; }
cript>
(function(){
const mount = document.getElementById('drink-calculator-widget');
// Create Shadow DOM to avoid CSS conflicts
const root = mount.attachShadow ? mount.attachShadow({mode:'open'}) : mount;
// Utility: create elements
const h = (tag, attrs = {}, children = []) => {
const el = document.createElement(tag);
for (const [k,v] of Object.entries(attrs)) {
if (k === 'class') el.setAttribute('class', v);
else if (k === 'style') el.setAttribute('style', v);
else if (k.startsWith('on') && typeof v === 'function') el.addEventListener(k.substring(2), v);
else el.setAttribute(k, v);
}
if (!Array.isArray(children)) children = [children];
children.filter(Boolean).forEach(c => el.append(c.nodeType ? c : document.createTextNode(String(c))));
return el;
};
// Styles (scoped in Shadow Root)
const style = h('style', {}, `
:host, .dcw * { box-sizing: border-box; }
.dcw { --bg:#0b0c10; --panel:#11131a; --muted:#9aa0aa; --accent:#7dd3fc; --accent-2:#22d3ee; --border:#262b36; --ok:#22c55e; --warn:#f59e0b; --err:#ef4444; font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; color:#e6e6e6; }
.card { background: linear-gradient(180deg, rgba(125,211,252,0.05), rgba(34,211,238,0.04)); border:1px solid var(--border); border-radius:16px; padding:16px; box-shadow: 0 10px 25px rgba(0,0,0,0.25); }
.header { display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:12px; }
.title { font-weight:700; font-size:18px; letter-spacing:0.2px; }
.muted { color: var(--muted); font-size:12px; }
.grid { display:grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap:12px; }
@media (min-width: 720px){ .grid{ grid-template-columns: repeat(4, minmax(0,1fr)); } }
label { display:block; font-size:12px; color:var(--muted); margin:0 0 6px; }
input[type="number"], select { width:100%; padding:10px 12px; background:#0f1218; color:#e6e6e6; border:1px solid var(--border); border-radius:12px; outline:none; transition:border .15s ease; }
input[type="number"]:focus, select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(125,211,252,0.2); }
.row { display:flex; gap:8px; align-items:center; }
.btn { appearance:none; border:1px solid var(--border); background:linear-gradient(180deg, #0f1218, #0b0e14); color:#e6e6e6; padding:10px 14px; border-radius:12px; cursor:pointer; font-weight:600; transition: transform .06s ease, box-shadow .2s ease, border .15s ease; }
.btn:hover { border-color: var(--accent); box-shadow: 0 6px 16px rgba(34, 211, 238, 0.15); }
.btn:active { transform: translateY(1px); }
.btn.primary { background: linear-gradient(180deg, #0ea5e9, #06b6d4); color:#051018; border-color: transparent; }
.btn.ghost { background: transparent; }
.small { font-size:12px; }
.out { margin-top:14px; }
.table { width:100%; border-collapse: collapse; font-size:14px; }
.table th, .table td { padding:10px 8px; border-bottom:1px solid var(--border); text-align:left; }
.pill { display:inline-block; padding:4px 8px; border-radius:9999px; background:#0f1218; border:1px solid var(--border); font-size:12px; color:var(--muted); }
.footer { display:flex; flex-wrap:wrap; gap:8px; justify-content:space-between; align-items:center; margin-top:10px; }
details { background:#0f1218; border:1px solid var(--border); border-radius:12px; padding:10px 12px; }
details summary { cursor:pointer; font-weight:600; color:#c7cbd3; }
.tags { display:flex; gap:6px; flex-wrap:wrap; }
.tag { cursor:pointer; }
`);
// HTML structure
const container = h('div', { class: 'dcw card' }, [
h('div', { class: 'header' }, [
h('div', {}, [
h('div', { class: 'title' }, 'Getränke?Kalkulator'),
h('div', { class: 'muted' }, 'Schnelle Mengenempfehlung für deine Feier – lokal auf deiner Seite, ohne externe Abhängigkeiten.')
]),
h('div', { class:'pill' }, 'v1.0')
]),
h('div', { class:'grid' }, [
// Personen
h('div', {}, [
h('label', {}, 'Personenanzahl'),
h('input', { id:'people', type:'number', min:'1', value:'25', inputmode:'numeric' })
]),
// Dauer
h('div', {}, [
h('label', {}, 'Dauer (Stunden)'),
h('input', { id:'hours', type:'number', min:'1', value:'5', step:'1' })
]),
// Art
h('div', {}, [
h('label', {}, 'Art der Feier'),
h('select', { id:'intensity' }, [
h('option', { value:'chill' }, 'Gemütlich'),
h('option', { value:'normal', selected:'selected' }, 'Normal'),
h('option', { value:'party' }, 'Party (feuchtfröhlich)')
])
]),
// Kategorie
h('div', {}, [
h('label', {}, 'Getränkekategorie'),
h('select', { id:'category' }, [
h('option', { value:'mixed', selected:'selected' }, 'Gemischt'),
h('option', { value:'beer' }, 'Bier'),
h('option', { value:'wine' }, 'Wein'),
h('option', { value:'sparkling' }, 'Sekt/Prosecco'),
h('option', { value:'soft' }, 'Softdrinks'),
h('option', { value:'water' }, 'Wasser'),
h('option', { value:'spirits' }, 'Longdrinks/Spirituosen')
])
])
]),
h('details', { style:'margin-top:12px;' }, [
h('summary', {}, 'Erweiterte Optionen (Flaschengrößen & Verteilung)'),
h('div', { style:'margin-top:10px;' }, [
h('div', { class:'grid' }, [
h('div', {}, [ h('label', {}, 'Bier Flaschengröße (l)'), h('input', { id:'beerSize', type:'number', step:'0.01', value:'0.33' }) ]),
h('div', {}, [ h('label', {}, 'Wein/Sekt Flaschengröße (l)'), h('input', { id:'wineSize', type:'number', step:'0.01', value:'0.75' }) ]),
h('div', {}, [ h('label', {}, 'Softdrinks Flaschengröße (l)'), h('input', { id:'softSize', type:'number', step:'0.1', value:'1.0' }) ]),
h('div', {}, [ h('label', {}, 'Wasser Flaschengröße (l)'), h('input', { id:'waterSize', type:'number', step:'0.1', value:'1.0' }) ])
]),
h('div', { class:'muted', style:'margin:10px 0 6px;' }, 'Verteilung bei "Gemischt" (Summe 100%):'),
h('div', { class:'grid' }, [
h('div', {}, [ h('label', {}, 'Bier %'), h('input', { id:'mixBeer', type:'number', min:'0', max:'100', step:'1', value:'35' }) ]),
h('div', {}, [ h('label', {}, 'Wein %'), h('input', { id:'mixWine', type:'number', min:'0', max:'100', step:'1', value:'25' }) ]),
h('div', {}, [ h('label', {}, 'Sekt %'), h('input', { id:'mixSpark', type:'number', min:'0', max:'100', step:'1', value:'5' }) ]),
h('div', {}, [ h('label', {}, 'Softdrinks %'), h('input', { id:'mixSoft', type:'number', min:'0', max:'100', step:'1', value:'15' }) ]),
h('div', {}, [ h('label', {}, 'Wasser %'), h('input', { id:'mixWater', type:'number', min:'0', max:'100', step:'1', value:'20' }) ])
])
])
]),
h('div', { class:'footer' }, [
h('div', { class:'tags muted small' }, [
h('span', { class:'pill tag', id:'preset-small' }, 'Schnell: 10 Pers.'),
h('span', { class:'pill tag', id:'preset-mid' }, 'Schnell: 25 Pers.'),
h('span', { class:'pill tag', id:'preset-big' }, 'Schnell: 60 Pers.')
]),
h('div', { class:'row' }, [
h('button', { class:'btn ghost', id:'copy' }, 'Ergebnis kopieren'),
h('button', { class:'btn primary', id:'calc' }, 'Berechnen')
])
]),
h('div', { class:'out', id:'output' })
]);
root.append(style, container);
// Logic
const $ = sel => root.querySelector(sel);
const ratesPerHour = {
beer: { chill: 0.15, normal: 0.25, party: 0.4 }, // Liter pro Person/Stunde
wine: { chill: 0.10, normal: 0.15, party: 0.25 },
sparkling: { chill: 0.06, normal: 0.10, party: 0.16 },
soft: { chill: 0.12, normal: 0.20, party: 0.28 },
water: { chill: 0.18, normal: 0.25, party: 0.35 },
spirits: { chill: 0.04, normal: 0.08, party: 0.12 } // als Longdrink-Gesamtmenge (inkl. Mixer) in Litern
};
const roundUp = (num, digits = 0) => {
const p = Math.pow(10, digits);
return Math.ceil(num * p) / p;
};
function calc(){
const people = Math.max(1, Number($('#people').value || 0));
const hours = Math.max(1, Number($('#hours').value || 0));
const intensity = $('#intensity').value; // chill|normal|party
const category = $('#category').value; // mixed|beer|wine|...
const sizes = {
beer: Number($('#beerSize').value || 0.33),
wine: Number($('#wineSize').value || 0.75),
sparkling: Number($('#wineSize').value || 0.75),
soft: Number($('#softSize').value || 1.0),
water: Number($('#waterSize').value || 1.0),
spirits: 0.7 // feste Flaschengröße für Spirituosen
};
let mix = {
beer: Number($('#mixBeer').value||0)/100,
wine: Number($('#mixWine').value||0)/100,
sparkling: Number($('#mixSpark').value||0)/100,
soft: Number($('#mixSoft').value||0)/100,
water: Number($('#mixWater').value||0)/100
};
// Normalize mix if needed
const sumMix = Object.values(mix).reduce((a,b)=>a+b,0);
if (category === 'mixed' && sumMix > 0 && Math.abs(sumMix - 1) > 0.0001){
for (const k of Object.keys(mix)) mix[k] = mix[k] / sumMix; // rescale to 100%
}
// Calculate liters per category
const res = {};
if (category === 'mixed') {
// Total mixed beverage volume per person/hour = weighted sum of categories using their own rates
const perHourTotal =
mix.beer * ratesPerHour.beer[intensity] +
mix.wine * ratesPerHour.wine[intensity] +
mix.sparkling * ratesPerHour.sparkling[intensity] +
mix.soft * ratesPerHour.soft[intensity] +
mix.water * ratesPerHour.water[intensity];
const totalLiters = people * hours * perHourTotal;
for (const k of ['beer','wine','sparkling','soft','water']){
const liters = totalLiters * mix[k];
res[k] = { liters };
}
// Spirits are not included automatically in "Gemischt"
} else if (category === 'spirits') {
const liters = people * hours * ratesPerHour.spirits[intensity];
res.spirits = { liters };
} else {
const liters = people * hours * ratesPerHour[category][intensity];
res[category] = { liters };
}
// Build rows for output
const rows = [];
let shoppingLines = [];
function pushRow(label, liters, sizeL, options={}){
const bottles = sizeL ? Math.ceil(liters / sizeL) : 0;
let extra = '';
if (label === 'Bier'){
const crates = Math.ceil(bottles / 20);
const kegs30 = Math.ceil(liters / 30);
extra = `${crates} Kisten (à 20 Fl.) | optional: ${kegs30} × 30l-Fass`;
}
if (label === 'Wein' || label === 'Sekt/Prosecco'){
const glasses = Math.ceil(liters / 0.15); // 0.15l pro Glas Wein
extra = `${glasses} Gläser (à ~0,15l)`;
}
if (label === 'Longdrinks/Spirituosen'){
// Spirits liters include mixer. Assume 40ml Spirit + 160ml Mixer pro Drink
const drinks = Math.ceil(liters / 0.2);
const spiritBottles = Math.ceil((drinks * 0.04) / 0.7);
const mixerLiters = roundUp(drinks * 0.16, 1);
extra = `${drinks} Longdrinks ? ${spiritBottles} × 0,7l Spirituosen + ${mixerLiters}l Mixer`;
shoppingLines.push(`${spiritBottles} × 0,7l Spirituose(n)`);
shoppingLines.push(`${mixerLiters}l Mixer (Tonic, Cola, etc.)`);
rows.push(`| ${label} | ${roundUp(liters,1)} l | — | ${extra} | `);
return; // skip bottle calc row for spirits base
}
rows.push(`| ${label} | ${roundUp(liters,1)} l | ${bottles} Flaschen à ${sizeL}l | ${extra} | `);
shoppingLines.push(`${bottles} × ${sizeL}l ${label.toLowerCase()}`);
}
if (res.beer) pushRow('Bier', res.beer.liters, sizes.beer);
if (res.wine) pushRow('Wein', res.wine.liters, sizes.wine);
if (res.sparkling) pushRow('Sekt/Prosecco', res.sparkling.liters, sizes.sparkling);
if (res.soft) pushRow('Softdrinks', res.soft.liters, sizes.soft);
if (res.water) pushRow('Wasser', res.water.liters, sizes.water);
if (res.spirits) pushRow('Longdrinks/Spirituosen', res.spirits.liters, sizes.spirits);
const people = Number($('#people').value);
const hours = Number($('#hours').value);
const title = `Ergebnis für ${people} Pers. · ${hours} Std · ${$('#intensity').selectedOptions[0].text} · ${$('#category').selectedOptions[0].text}`;
$('#output').innerHTML = `
${title}
Richtwert – bitte an Zielgruppe & Saison anpassen
| Kategorie | Menge (Liter) | Flaschen | Hinweise |
${rows.join('')}
`;
return `Getränke-Kalkulation: ${title}\n- ${shoppingLines.join("\n- ")}`;
}
// Events
$('#calc').addEventListener('click', () => calc());
$('#copy').addEventListener('click', async () => {
const text = calc();
try {
await navigator.clipboard.writeText(text);
const old = $('#copy').textContent; $('#copy').textContent = 'Kopiert ?';
setTimeout(()=> $('#copy').textContent = old, 1500);
} catch(e){ alert('Konnte nicht in die Zwischenablage kopieren.'); }
});
// Presets
$('#preset-small').addEventListener('click', ()=>{ $('#people').value = 10; calc(); });
$('#preset-mid').addEventListener('click', ()=>{ $('#people').value = 25; calc(); });
$('#preset-big').addEventListener('click', ()=>{ $('#people').value = 60; calc(); });
// First render
calc();
})();
|