Catálogo Drevolia
Escolha o seu próximo gesto floral.
Percursos claros para explorar composição, técnica e processo criativo com tempo para praticar.
A carregar cursos.
Não foi possível carregar o catálogo.
Verifique a ligação e tente novamente.
`;
const footerHTML = ``;
function initHeaderFooter() {
document.querySelector('header').innerHTML = headerHTML;
document.querySelector('footer').innerHTML = footerHTML;
initGlobalScripts();
}
function initGlobalScripts() {
document.querySelectorAll('[data-action="toggle-menu"]').forEach(btn => {
btn.addEventListener('click', () => {
const target = document.getElementById(btn.dataset.target);
target.classList.toggle('hidden');
});
});
document.querySelectorAll('[data-action="open-modal"]').forEach(btn => {
btn.addEventListener('click', () => {
const modal = document.getElementById(btn.dataset.target);
modal.classList.remove('hidden');
modal.classList.add('flex');
});
});
document.querySelectorAll('[data-action="close-modal"]').forEach(btn => {
btn.addEventListener('click', () => {
const modal = btn.closest('[role="dialog"]');
modal.classList.add('hidden');
modal.classList.remove('flex');
});
});
document.querySelectorAll('[data-action="toggle-theme"]').forEach(btn => {
btn.addEventListener('click', () => {
document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light');
});
});
if (localStorage.getItem('theme') === 'dark') document.documentElement.classList.add('dark');
const cookieBanner = document.getElementById('cookie-catalog');
if (!localStorage.getItem('cookiesAccepted')) cookieBanner.classList.remove('hidden');
document.querySelectorAll('[data-action="accept-cookies"]').forEach(btn => {
btn.addEventListener('click', () => {
localStorage.setItem('cookiesAccepted', 'true');
cookieBanner.classList.add('hidden');
});
});
}
const state = {items: [], page: 1, perPage: 6, search: '', category: 'all', level: 'all'};
const followingKey = 'drevoliaFollowing';
const cartKey = 'drevoliaCart';
function getFollowing() { return JSON.parse(localStorage.getItem(followingKey) || '[]'); }
function saveFollowing(arr) { localStorage.setItem(followingKey, JSON.stringify(arr)); }
function getCart() { return JSON.parse(localStorage.getItem(cartKey) || '[]'); }
function saveCart(arr) { localStorage.setItem(cartKey, JSON.stringify(arr)); }
fetch('./catalog.json')
.then(r => { if (!r.ok) throw new Error(); return r.json(); })
.then(items => { state.items = items; fillOptions(); render(); })
.catch(() => document.getElementById('catalog-error').classList.remove('hidden'));
function fillOptions() {
['category', 'level'].forEach(key => {
const el = document.getElementById('catalog-' + key);
[...new Set(state.items.map(i => i[key]))].forEach(v => {
el.insertAdjacentHTML('beforeend', ``);
});
el.addEventListener('change', () => { state[key] = el.value; state.page = 1; render(); });
});
const search = document.getElementById('catalog-search');
search.addEventListener('input', () => { state.search = search.value.toLowerCase(); state.page = 1; render(); });
}
function render() {
const filtered = state.items.filter(i => {
const s = state.search === '' || i.title.toLowerCase().includes(state.search) || i.summary.toLowerCase().includes(state.search);
const c = state.category === 'all' || i.category === state.category;
const l = state.level === 'all' || i.level === state.level;
return s && c && l;
});
const status = document.getElementById('catalog-status');
const grid = document.getElementById('catalog-grid');
const pag = document.getElementById('catalog-pagination');
status.textContent = filtered.length + ' cursos encontrados';
grid.innerHTML = '';
pag.innerHTML = '';
const start = (state.page - 1) * state.perPage;
const pageItems = filtered.slice(start, start + state.perPage);
pageItems.forEach(item => {
const isFollowing = getFollowing().includes(item.id);
const card = document.createElement('div');
card.className = 'dd23l xk9h7 p2aql rounded-3xl border border-stone-200 bg-white p-8 dark:border-stone-800 dark:bg-stone-900 flex flex-col';
card.innerHTML = `
${item.category}
${item.level}
${item.title}
${item.summary}
${item.price} € · ${item.duration}
`;
grid.appendChild(card);
});
const totalPages = Math.ceil(filtered.length / state.perPage);
for (let p = 1; p <= totalPages; p++) {
const b = document.createElement('button');
b.type = 'button';
b.className = `px-5 py-2 text-sm rounded-full border ${p === state.page ? 'bg-stone-900 text-stone-50 dark:bg-stone-800' : 'border-stone-300 dark:border-stone-700'}`;
b.textContent = p;
b.onclick = () => { state.page = p; render(); };
pag.appendChild(b);
}
bindCardActions();
}
function bindCardActions() {
document.querySelectorAll('[data-action="follow"]').forEach(btn => {
btn.onclick = () => {
const id = parseInt(btn.dataset.id);
let f = getFollowing();
if (f.includes(id)) f = f.filter(x => x !== id); else f.push(id);
saveFollowing(f);
render();
};
});
document.querySelectorAll('[data-action="detail"]').forEach(btn => {
btn.onclick = () => {
const item = state.items.find(i => i.id === parseInt(btn.dataset.id));
showDetail(item);
};
});
document.querySelectorAll('[data-action="add-cart"]').forEach(btn => {
btn.onclick = () => {
const id = parseInt(btn.dataset.id);
let cart = getCart();
const ex = cart.find(x => x.id === id);
if (ex) ex.quantity++; else cart.push({id, quantity: 1});
saveCart(cart);
btn.textContent = 'Adicionado';
setTimeout(() => { btn.textContent = 'Adicionar'; }, 1200);
};
});
}
function showDetail(item) {
const modal = document.getElementById('product-detail-catalog');
const content = document.getElementById('product-detail-content');
const isFollowing = getFollowing().includes(item.id);
content.innerHTML = `
${item.category}
${item.level} · ${item.format}
${item.title}
${item.duration} · ${item.price} €
${item.description}
`;
modal.classList.remove('hidden');
modal.classList.add('flex');
content.querySelector('[data-action="close-modal"]').onclick = () => { modal.classList.add('hidden'); modal.classList.remove('flex'); };
content.querySelector('[data-action="follow-detail"]').onclick = () => {
let f = getFollowing();
if (f.includes(item.id)) f = f.filter(x => x !== item.id); else f.push(item.id);
saveFollowing(f);
modal.classList.add('hidden'); modal.classList.remove('flex');
render();
};
content.querySelector('[data-action="add-cart-detail"]').onclick = () => {
let cart = getCart();
const ex = cart.find(x => x.id === item.id);
if (ex) ex.quantity++; else cart.push({id: item.id, quantity: 1});
saveCart(cart);
modal.classList.add('hidden'); modal.classList.remove('flex');
};
}
document.addEventListener('DOMContentLoaded', () => {
initHeaderFooter();
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') document.documentElement.classList.add('dark');
});