sdelay-sayt-pro-kofeynyu/script.js

248 lines
8.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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) => "<span>" + l + "</span>").join("");
const total = priceTotal();
const base = b.price;
$("buildPrice").innerHTML = "<small>Итого</small> " + fmt(total) +
(total > base ? " <small>(база " + fmt(base) + " + " + fmt(total - base) + ")</small>" : "");
}
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();