The studio shelf
Courses for curious candle makers.
Choose a focused learning experience with practical outcomes, transparent pricing, and a pace that respects your creative process.
Loading the studio catalog…
`;
const footerHTML = ``;
document.querySelector('header').innerHTML = headerHTML;
document.querySelector('footer').innerHTML = footerHTML;
let products = [], page = 1; const size = 6;
const favKey = "blushrouteFavorites", cartKey = "blushrouteCart";
const $ = s => document.querySelector(s);
function getFavorites() { return JSON.parse(localStorage.getItem(favKey) || "[]"); }
function getCart() { return JSON.parse(localStorage.getItem(cartKey) || "[]"); }
function saveFavorites(favs) { localStorage.setItem(favKey, JSON.stringify(favs)); }
function saveCart(cart) { localStorage.setItem(cartKey, JSON.stringify(cart)); }
function updateStatus(msg) { $("#status").textContent = msg; }
function renderGrid(filtered) {
const grid = $("#grid");
grid.innerHTML = "";
if (!filtered.length) {
grid.innerHTML = `No courses match your search.
`;
return;
}
const start = (page - 1) * size;
const slice = filtered.slice(start, start + size);
slice.forEach(item => {
const favs = getFavorites();
const isFav = favs.includes(item.id);
const card = document.createElement("div");
card.className = `course-card rounded-3xl border border-rose-200 bg-white p-6 flex flex-col`;
card.innerHTML = `
${item.level}
${item.title}
${item.description}
${item.duration}
$${item.price} ${item.currency}
`;
grid.appendChild(card);
});
renderPagination(filtered.length);
attachCardListeners();
}
function renderPagination(total) {
const nav = $("#pagination");
nav.innerHTML = "";
const pages = Math.ceil(total / size);
if (pages <= 1) return;
for (let i = 1; i <= pages; i++) {
const btn = document.createElement("button");
btn.textContent = i;
btn.className = `rounded-full border px-4 py-2 text-sm font-semibold ${i === page ? "bg-fuchsia-700 text-white border-fuchsia-700" : "border-rose-200"}`;
btn.onclick = () => { page = i; applyFilters(); };
nav.appendChild(btn);
}
}
function attachCardListeners() {
document.querySelectorAll("[data-fav]").forEach(btn => {
btn.onclick = () => {
const id = btn.dataset.fav;
let favs = getFavorites();
if (favs.includes(id)) favs = favs.filter(x => x !== id);
else favs.push(id);
saveFavorites(favs);
applyFilters();
};
});
document.querySelectorAll("[data-details]").forEach(btn => {
btn.onclick = () => showDetails(btn.dataset.details);
});
document.querySelectorAll("[data-cart]").forEach(btn => {
btn.onclick = () => addToCart(btn.dataset.cart);
});
}
function applyFilters() {
const term = $("#search").value.toLowerCase().trim();
const level = $("#filter").value;
let filtered = products;
if (level !== "All") filtered = filtered.filter(p => p.level === level);
if (term) filtered = filtered.filter(p =>
p.title.toLowerCase().includes(term) ||
p.description.toLowerCase().includes(term) ||
p.outcomes.join(" ").toLowerCase().includes(term)
);
$("#status").textContent = `${filtered.length} courses found`;
renderGrid(filtered);
}
function showDetails(id) {
const item = products.find(p => p.id === id);
if (!item) return;
const modal = $("#details");
const content = $("#detailContent");
const favs = getFavorites();
const isFav = favs.includes(id);
content.innerHTML = `
${item.level}
${item.title}
${item.duration} • $${item.price} ${item.currency}
${item.description}
Learning outcomes
${item.outcomes.map(o => `- • ${o}
`).join("")}
Materials provided
${item.materials.map(m => `- • ${m}
`).join("")}
`;
modal.showModal();
content.querySelector("[data-fav-modal]").onclick = () => {
let favs = getFavorites();
if (favs.includes(id)) favs = favs.filter(x => x !== id);
else favs.push(id);
saveFavorites(favs);
modal.close();
applyFilters();
};
}
function addToCart(id) {
let cart = getCart();
const existing = cart.findIndex(x => x.id === id);
if (existing > -1) cart[existing].quantity++;
else cart.push({id, quantity: 1});
saveCart(cart);
const btns = document.querySelectorAll(`[data-cart="${id}"]`);
btns.forEach(b => { b.textContent = "Added ✓"; setTimeout(() => { b.textContent = "Add to cart"; }, 1200); });
}
function attachGlobalListeners() {
$("#search").addEventListener("input", () => { page = 1; applyFilters(); });
$("#filter").addEventListener("change", () => { page = 1; applyFilters(); });
const menuToggle = document.querySelector("#menuToggle");
const mainNav = document.querySelector("#mainNav");
menuToggle?.addEventListener("click", () => mainNav.classList.toggle("hidden"));
document.querySelectorAll("[data-auth]").forEach(x => x.addEventListener("click", () => {
const authTitle = document.querySelector("#authTitle");
authTitle.textContent = x.dataset.auth === "login" ? "Log in" : "Create an account";
document.querySelector("#authModal").showModal();
}));
const themeToggle = document.querySelector("#themeToggle");
themeToggle?.addEventListener("click", () => {
document.documentElement.classList.toggle("dark");
localStorage.setItem("blushrouteTheme", document.documentElement.classList.contains("dark") ? "dark" : "light");
});
if (localStorage.getItem("blushrouteTheme") === "dark") document.documentElement.classList.add("dark");
const cb = document.querySelector("#cookieBanner");
if (localStorage.getItem("blushrouteCookies") === "yes") cb?.remove();
document.querySelector("#acceptCookies")?.addEventListener("click", () => {
localStorage.setItem("blushrouteCookies", "yes");
cb?.remove();
});
}
async function init() {
try {
const r = await fetch("./catalog.json");
products = await r.json();
updateStatus(`${products.length} courses available`);
attachGlobalListeners();
applyFilters();
} catch (e) {
updateStatus("The catalog could not be loaded. Please try again or contact the studio.");
$("#grid").innerHTML = `Unable to load courses right now.
`;
}
}
init();