// Aulv Health Sleep Truffles PDP — root app const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": ["#1d3a2f", "#c9a96a", "#fafaf6"], "headline": "geist", "heroLayout": "thumbs-left", "density": "regular" }/*EDITMODE-END*/; const PALETTES = { // [brand, accent, bg] forest: ["#1d3a2f", "#c9a96a", "#fafaf6"], midnight: ["#1a1f3a", "#9ba8c9", "#f5f5f1"], cocoa: ["#3d2418", "#d49b6a", "#f7f1ea"], charcoal: ["#1a1a1a", "#b48a4d", "#f5f4ef"], }; const FONTS = { geist: { sans: '"Geist", ui-sans-serif, system-ui, sans-serif', display: '"Geist", ui-sans-serif, system-ui, sans-serif' }, inter: { sans: '"Inter", ui-sans-serif, system-ui, sans-serif', display: '"Inter", ui-sans-serif, system-ui, sans-serif' }, fraunces: { sans: '"Geist", ui-sans-serif, system-ui, sans-serif', display: '"Fraunces", ui-serif, Georgia, serif' }, instrument: { sans: '"Geist", ui-sans-serif, system-ui, sans-serif', display: '"Instrument Serif", ui-serif, Georgia, serif' }, }; function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const [cart, setCart] = React.useState([]); const [drawerOpen, setDrawerOpen] = React.useState(false); const [toast, setToast] = React.useState({ show: false, msg: "" }); // apply tweaks → CSS vars React.useEffect(() => { const r = document.documentElement; const [brand, accent, bg] = Array.isArray(t.palette) ? t.palette : PALETTES.forest; r.style.setProperty("--brand", brand); r.style.setProperty("--accent", accent); r.style.setProperty("--bg", bg); // derive a 2-tone bg-2 from bg r.style.setProperty("--bg-2", shade(bg, -3)); const f = FONTS[t.headline] || FONTS.geist; r.style.setProperty("--font-sans", f.sans); r.style.setProperty("--font-display", f.display); }, [t.palette, t.headline]); const addToCart = (item) => { setCart(prev => { const idx = prev.findIndex(x => x.planId === item.planId && x.variant === item.variant); if (idx >= 0) { const next = [...prev]; next[idx] = { ...next[idx], qty: next[idx].qty + item.qty }; return next; } return [...prev, item]; }); setToast({ show: true, msg: `${item.qty} × ${item.product} added` }); setTimeout(() => setDrawerOpen(true), 350); setTimeout(() => setToast(s => ({ ...s, show: false })), 2400); }; const onQty = (i, q) => { if (q < 1) return onRemove(i); setCart(prev => prev.map((it, j) => j === i ? { ...it, qty: q } : it)); }; const onRemove = (i) => setCart(prev => prev.filter((_, j) => j !== i)); const cartCount = cart.reduce((s, it) => s + it.qty, 0); return ( <> setDrawerOpen(true)} /> setDrawerOpen(false)} items={cart} onQty={onQty} onRemove={onRemove} /> setTweak("palette", v)} /> setTweak("headline", v)} /> setTweak("heroLayout", v)} /> setTweak("density", v)} /> ); } // shade a hex by N percentage points of lightness function shade(hex, pct) { const h = String(hex).replace("#", ""); const x = h.length === 3 ? h.replace(/./g, c => c + c) : h.padEnd(6, "0"); let r = parseInt(x.slice(0,2), 16); let g = parseInt(x.slice(2,4), 16); let b = parseInt(x.slice(4,6), 16); const adj = pct / 100 * 255; r = Math.max(0, Math.min(255, Math.round(r + adj))); g = Math.max(0, Math.min(255, Math.round(g + adj))); b = Math.max(0, Math.min(255, Math.round(b + adj))); return "#" + [r,g,b].map(v => v.toString(16).padStart(2,"0")).join(""); } ReactDOM.createRoot(document.getElementById("root")).render();