import { getToken, isLoggedIn } from './auth.js'; const API_URL = '/api'; let galleryStacks = []; export function initGallery(getSelectedApps, getConfig) { loadGallery(); document.getElementById('gallery-search').addEventListener('input', debounce(loadGallery, 300)); document.getElementById('gallery-sort').addEventListener('change', loadGallery); // Share button document.getElementById('share-stack-btn').addEventListener('click', () => { if (!isLoggedIn()) { document.getElementById('auth-modal').classList.remove('hidden'); return; } if (getSelectedApps().length === 0) { alert('Select some apps in the Stack Builder first!'); return; } document.getElementById('share-modal').classList.remove('hidden'); }); document.getElementById('share-modal-close').addEventListener('click', () => { document.getElementById('share-modal').classList.add('hidden'); }); document.getElementById('share-form').addEventListener('submit', async (e) => { e.preventDefault(); const name = document.getElementById('share-name').value.trim(); const desc = document.getElementById('share-desc').value.trim(); const tags = document.getElementById('share-tags').value.split(',').map(t => t.trim()).filter(Boolean); const res = await fetch(`${API_URL}/stacks`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` }, body: JSON.stringify({ name, description: desc, apps: getSelectedApps(), config: getConfig(), tags, }), }); if (res.ok) { document.getElementById('share-modal').classList.add('hidden'); document.getElementById('share-form').reset(); loadGallery(); } }); } async function loadGallery() { const search = document.getElementById('gallery-search').value.trim(); const sort = document.getElementById('gallery-sort').value; let url = `${API_URL}/stacks?sort=${sort}&limit=30`; if (search) url += `&search=${encodeURIComponent(search)}`; try { const res = await fetch(url, { headers: getToken() ? { Authorization: `Bearer ${getToken()}` } : {}, }); if (res.ok) { galleryStacks = await res.json(); renderGallery(); } } catch (e) { document.getElementById('gallery-grid').innerHTML = '

Unable to load community stacks. Is the API running?

'; } } function renderGallery() { const grid = document.getElementById('gallery-grid'); if (galleryStacks.length === 0) { grid.innerHTML = '

No stacks shared yet. Be the first!

'; return; } grid.innerHTML = galleryStacks.map(stack => `
${esc(stack.name)}
${esc(stack.description || '')}
${stack.apps.slice(0, 8).map(a => `${a}`).join('')}${stack.apps.length > 8 ? `+${stack.apps.length - 8}` : ''}
⭐ ${stack.stars} 📦 ${stack.downloads} by ${esc(stack.display_name || stack.username)}
`).join(''); // Event listeners grid.querySelectorAll('[data-action="star"]').forEach(btn => { btn.addEventListener('click', () => starStack(btn.dataset.id)); }); grid.querySelectorAll('[data-action="use"]').forEach(btn => { btn.addEventListener('click', () => useStack(btn.dataset.id)); }); } async function starStack(id) { if (!isLoggedIn()) { document.getElementById('auth-modal').classList.remove('hidden'); return; } await fetch(`${API_URL}/stacks/${id}/star`, { method: 'POST', headers: { Authorization: `Bearer ${getToken()}` }, }); loadGallery(); } async function useStack(id) { const stack = galleryStacks.find(s => s.id === parseInt(id)); if (!stack) return; // Track download fetch(`${API_URL}/stacks/${id}/download`, { method: 'POST' }); // Dispatch event for main.js to load these apps window.dispatchEvent(new CustomEvent('use-stack', { detail: { apps: stack.apps, config: stack.config } })); // Switch to builder mode document.querySelectorAll('.mode-btn').forEach(b => b.classList.remove('active')); document.querySelector('.mode-btn[data-mode="builder"]').classList.add('active'); document.querySelector('.container').style.display = 'block'; document.getElementById('step-gallery').style.display = 'none'; document.getElementById('step-analyser').style.display = 'none'; } function esc(str) { return str.replace(/&/g, '&').replace(//g, '>'); } function debounce(fn, ms) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; }