/* ui.jsx — shared icons + small primitives */
/* Minimal line-icon set (simple geometric strokes only) */
const Icon = {
bag: (p) => (),
plus: (p) => (),
minus: (p) => (),
x: (p) => (),
check: (p) => (),
arrowR: (p) => (),
arrowL: (p) => (),
leaf: (p) => (),
bowl: (p) => (),
spoon: (p) => (),
heart: ({ filled, ...p } = {}) => (),
truck: (p) => (),
store: (p) => (),
lock: (p) => (),
clock: (p) => (),
pin: (p) => (),
info: (p) => (),
mail: (p) => (),
flame: (p) => (),
};
/* tag chip */
function Tag({ k }) {
const label = (window.TAG_LABEL || {})[k] || k;
const cls = { vegan: "tag-vegan", veg: "tag-veg", gf: "tag-gf", spicy: "tag-spicy" }[k] || "";
const ic = k === "vegan" || k === "veg" ? : k === "spicy" ? : null;
return ({ic}{label});
}
/* image-slot wrapper — renders the drop-in slot with a tasteful tinted fallback */
function Photo({ id, label, tint, shape, radius, style, src }) {
const ref = React.useRef(null);
// Real photo: explicit src wins, else look up by slot id in window.IMAGES.
// Falls back to the tinted empty state when neither is set.
const photo = src || (window.IMAGES && window.IMAGES[id]) || undefined;
return (
);
}
function mixTint(hex) {
// subtle diagonal wash using the soup's tint over cream
return `repeating-linear-gradient(135deg, ${hexA(hex,0.13)} 0 16px, ${hexA(hex,0.22)} 16px 32px), var(--cream-deep)`;
}
function hexA(hex, a) {
const h = hex.replace("#", "");
const r = parseInt(h.slice(0,2),16), g = parseInt(h.slice(2,4),16), b = parseInt(h.slice(4,6),16);
return `rgba(${r},${g},${b},${a})`;
}
/* quantity stepper */
function Stepper({ qty, onDec, onInc, min }) {
return (
{qty}
);
}
const CHF = (n) => "CHF " + n.toFixed(2).replace(".", ".");
Object.assign(window, { Icon, Tag, Photo, Stepper, CHF, hexA });