/** * OmégaKube — Services Tabs Renderer * Charge assets/data/services.json et construit dynamiquement * les onglets de navigation et leurs contenus. * * Dépend de main.js et services-process.js (déjà chargés avant ce script). */ (function () { 'use strict'; /* ── Helpers ─────────────────────────────────────────────── */ function stampHtml(stamp, extraClass) { if (!stamp) return ''; const animated = stamp.animated ? ' service-stamp-animated' : ''; const extra = extraClass ? ' ' + extraClass : ''; return `${window.escapeHTML(stamp.text)}`; } function particlesHtml() { return `
${'
'.repeat(6)}
`; } /* ── Rendu ───────────────────────────────────────────────── */ function renderNavBtn(service, isFirst) { return ` `; } function renderVisual(service) { const { accentFrom, accentTo, stamp } = service.visual; const safeFrom = window.escapeHTML(accentFrom); const safeTo = window.escapeHTML(accentTo); return `
${stampHtml(stamp, 'service-visual-stamp')} ${particlesHtml()}
`; } function renderHighlights(highlights) { return highlights.map(h => `
${window.escapeHTML(h.value)}
${window.escapeHTML(h.label)}
`).join(''); } function renderFeatures(features, accentFrom, accentTo) { const safeFrom = window.escapeHTML(accentFrom); const safeTo = window.escapeHTML(accentTo); return features.map(f => `

${window.escapeHTML(f.title)}

${window.escapeHTML(f.desc)}

`).join(''); } function renderNote(note) { if (!note || !note.length) return ''; return `

${note.map(n => `${window.escapeHTML(n.value)} ${window.escapeHTML(n.label)}
`).join(' ')}

`; } function renderCtas(ctas) { return ctas.map(c => ` ${window.escapeHTML(c.label)} `).join(''); } function renderTabContent(service, isFirst) { const { accentFrom, accentTo } = service.visual; const titleStamp = service.titleStamp ? ' ' + stampHtml({ ...service.titleStamp }, 'service-stamp-inline') : ''; return `
${renderVisual(service)}

${window.escapeHTML(service.title)}${titleStamp}

${window.escapeHTML(service.description)}

${renderHighlights(service.highlights)}
${renderFeatures(service.features, accentFrom, accentTo)}
${renderNote(service.note)}
${renderCtas(service.cta)}
`; } /* ── Logique des onglets ─────────────────────────────────── */ function initTabs() { const tabBtns = document.querySelectorAll('.service-tab-btn'); const tabContents = document.querySelectorAll('.service-tab-content'); if (!tabBtns.length || !tabContents.length) return; tabBtns.forEach(btn => { btn.addEventListener('click', () => { const tabId = btn.dataset.tab; tabBtns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); tabContents.forEach(content => { content.classList.remove('active'); if (content.id === 'tab-' + tabId) content.classList.add('active'); }); if (window.feather) window.feather.replace(); }); }); } /* ── Init ────────────────────────────────────────────────── */ async function init() { const navContainer = document.getElementById('service-tabs-nav'); const contentContainer = document.getElementById('service-tabs-contents'); if (!navContainer || !contentContainer) return; let services; try { const res = await fetch('../assets/data/services.json'); if (!res.ok) throw new Error(`HTTP ${res.status}`); services = await res.json(); } catch (err) { console.error('[services-tabs.js] Impossible de charger services.json :', err); return; } if (!Array.isArray(services) || services.length === 0) { console.warn('[services-tabs.js] services.json est vide ou mal formé.'); return; } navContainer.innerHTML = services.map((s, i) => renderNavBtn(s, i === 0)).join(''); contentContainer.innerHTML = services.map((s, i) => renderTabContent(s, i === 0)).join(''); if (window.feather) window.feather.replace(); initTabs(); } document.addEventListener('DOMContentLoaded', init); })();