const PRODUCTS = { base: [ { id: "espresso", label: "Эспрессо", price: 900, hasMilk: false, drink: true }, { id: "americano", label: "Американо", price: 1100, hasMilk: false, drink: true }, { id: "latte", label: "Латте (база)", price: 900, hasMilk: true, drink: true }, { id: "mocha", label: "Мока", price: 1100, hasMilk: true, drink: true }, { id: "herb", label: "Травяной чай", price: 800, hasMilk: false, drink: true }, ], milk: [ { id: "none", label: "Без молока", price: 0 }, { id: "milk", label: "Коровье", price: 100 }, { id: "oat", label: "Овсяное", price: 300 }, { id: "almond", label: "Миндальное", price: 300 }, { id: "coconut", label: "Кокосовое", price: 350 }, ], syrup: [ { id: "none", label: "Без сиропа", price: 0 }, { id: "vanilla", label: "Ваниль", price: 300 }, { id: "caramel", label: "Карамель", price: 300 }, { id: "lavender", label: "Лаванда", price: 350 }, { id: "honey", label: "Мёд", price: 350 }, ], size: [ { id: "s", label: "250 мл", price: 0 }, { id: "m", label: "350 мл", price: 300 }, { id: "l", label: "450 мл", price: 500 }, ], temp: [ { id: "hot", label: "Горячий", price: 0 }, { id: "iced", label: "На льду", price: 200 }, ], }; const BASE_COLORS = { espresso: "var(--kt-ai-fg)", americano: "var(--kt-ai-fg-muted)", latte: "var(--kt-ai-primary-subtle)", mocha: "var(--kt-ai-border-strong)", herb: "var(--kt-ai-chart-green)", }; const MILK_COLORS = { none: "transparent", milk: "var(--kt-ai-bg)", oat: "var(--kt-ai-bg-soft)", almond: "var(--kt-ai-bg-hover)", coconut: "var(--kt-ai-bg-elevated)", }; const SYRUP_COLORS = { none: "transparent", vanilla: "var(--kt-ai-chip-orange-bg)", caramel: "var(--kt-ai-chip-orange-fg)", lavender: "var(--kt-ai-chip-purple-bg)", honey: "var(--kt-ai-chip-orange-bg)", }; const MOODS = { wake: { base: "espresso", milk: "none", syrup: "none", size: "s", temp: "hot" }, soft: { base: "latte", milk: "milk", syrup: "vanilla", size: "m", temp: "hot" }, light: { base: "herb", milk: "none", syrup: "honey", size: "m", temp: "hot" }, }; const state = { base: null, milk: "none", syrup: "none", size: "m", temp: "hot" }; const $ = (id) => document.getElementById(id); const byId = (group, id) => (PRODUCTS[group] || []).find((p) => p.id === id); const fmt = (price) => price.toLocaleString("ru-RU") + " \u20B8"; function renderGroup(group) { const wrap = $("group-" + group); wrap.innerHTML = ""; PRODUCTS[group].forEach((opt) => { const label = document.createElement("label"); label.className = "opt"; const input = document.createElement("input"); input.type = "radio"; input.name = "opt-" + group; input.value = opt.id; input.checked = state[group] === opt.id; input.addEventListener("change", () => { state[group] = opt.id; update(); }); const name = document.createElement("span"); name.className = "opt-label"; name.textContent = opt.label; label.appendChild(input); label.appendChild(name); if (opt.price > 0) { const price = document.createElement("span"); price.className = "opt-price"; price.textContent = "+" + fmt(opt.price); label.appendChild(price); } wrap.appendChild(label); }); } function selected(group) { return byId(group, state[group]); } function priceTotal() { if (!state.base) return 0; const b = selected("base"); const m = selected("milk"); const s = selected("syrup"); const z = selected("size"); const t = selected("temp"); return ( b.price + (b.hasMilk ? m.price : 0) + (b.drink ? s.price : 0) + z.price + t.price ); } function paintCup() { const layers = $("layers"); const ice = $("iceGroup"); const steam = $("steam"); layers.innerHTML = ""; ice.innerHTML = ""; if (!state.base) return; const b = selected("base"); const m = selected("milk"); const s = selected("syrup"); const z = selected("size"); const t = selected("temp"); const fillFactor = z.id === "s" ? 0.45 : z.id === "m" ? 0.72 : 0.9; const innerTop = 52; const innerH = 158; const fillH = Math.round(innerH * fillFactor); const fillY = innerTop + (innerH - fillH); const widthBySize = { s: 88, m: 124, l: 148 }; const width = widthBySize[z.id]; const cupX = 100 - width / 2; [ $("cupInner"), $("cupBody") ].forEach((el) => { el.setAttribute("width", width); el.setAttribute("x", cupX); }); const NS = "http://www.w3.org/2000/svg"; const addRect = (x, width, y, h, color, rx) => { const rect = document.createElementNS(NS, "rect"); rect.setAttribute("x", x); rect.setAttribute("width", width); rect.setAttribute("y", Math.max(innerTop, y)); rect.setAttribute("height", h); rect.setAttribute("fill", color); rect.setAttribute("class", "part"); if (rx) rect.setAttribute("rx", rx); layers.appendChild(rect); return rect; }; const innerX = cupX + 5; const innerW = width - 10; let y = fillY + fillH; if (t.id === "iced") { if (b.hasMilk && m.id !== "none") { y -= fillH * 0.35; addRect(innerX, innerW, y, fillH * 0.35, MILK_COLORS[m.id]); } y -= fillH * 0.45; addRect(innerX, innerW, y, fillH * 0.45, BASE_COLORS[b.id]); if (b.drink && s.id !== "none") { y -= fillH * 0.2; addRect(innerX, innerW, y, fillH * 0.2, SYRUP_COLORS[s.id]); } for (let i = 0; i < 3; i++) { const cube = document.createElementNS(NS, "rect"); cube.setAttribute("x", cupX + 10 + i * (innerW - 20) / 3); cube.setAttribute("y", fillY + 6); cube.setAttribute("width", Math.round((innerW - 20) / 3 - 8)); cube.setAttribute("height", "22"); cube.setAttribute("rx", "4"); cube.setAttribute("fill", "rgba(190,222,240,0.9)"); cube.setAttribute("stroke", "rgba(255,255,255,0.7)"); cube.setAttribute("stroke-width", "2"); cube.setAttribute("class", "part"); ice.appendChild(cube); } } else { addRect(innerX, innerW, fillY, fillH * 0.45, BASE_COLORS[b.id]); if (b.hasMilk && m.id !== "none") addRect(innerX, innerW, fillY + fillH * 0.45, fillH * 0.3, MILK_COLORS[m.id]); if (b.drink && s.id !== "none") addRect(innerX, innerW, fillY + fillH * 0.75, fillH * 0.25, SYRUP_COLORS[s.id]); } steam.setAttribute("opacity", t.id === "hot" ? "1" : "0"); } function buildName(b, m, s, z, t) { const tempWord = t.id === "iced" ? "Ледяной" : "Горячий"; const sizeWord = z.id === "s" ? "маленький" : z.id === "m" ? "средний" : "большой"; const bits = [tempWord, sizeWord.toLowerCase()]; if (b.hasMilk && m.id !== "none") bits.push(m.label.toLowerCase()); if (b.drink && s.id !== "none") bits.push("сироп " + s.label.toLowerCase()); bits.push(b.label.toLowerCase()); return bits.join(", "); } function update() { paintCup(); if (!state.base) return; const b = selected("base"); const m = selected("milk"); const s = selected("syrup"); const z = selected("size"); const t = selected("temp"); $("buildName").textContent = buildName(b, m, s, z, t); const lines = ["Основа: " + b.label, "Размер: " + z.label, "Подача: " + t.label]; if (b.hasMilk) lines.splice(1, 0, "Молоко: " + m.label); if (b.drink) lines.splice(2, 0, "Сироп: " + s.label); $("buildSummary").innerHTML = lines.map((l) => "" + l + "").join(""); const total = priceTotal(); const base = b.price; $("buildPrice").innerHTML = "Итого " + fmt(total) + (total > base ? " (база " + fmt(base) + " + " + fmt(total - base) + ")" : ""); } function renderAll() { Object.keys(PRODUCTS).forEach(renderGroup); } function applyMood(moodId) { const preset = MOODS[moodId]; if (!preset) return; Object.assign(state, preset); renderAll(); update(); document.querySelectorAll(".mood-btn").forEach((btn) => { const active = btn.dataset.mood === moodId; btn.style.borderColor = active ? "var(--kt-ai-primary)" : ""; btn.style.background = active ? "var(--kt-ai-primary-subtle)" : ""; }); $("builderCard").hidden = false; $("builderCard").scrollIntoView({ behavior: "smooth", block: "nearest" }); } document.querySelectorAll(".mood-btn").forEach((btn) => { btn.addEventListener("click", () => applyMood(btn.dataset.mood)); }); renderAll();