diff --git a/public/assets/js/admin-stats.js b/public/assets/js/admin-stats.js new file mode 100644 index 0000000..588c8e8 --- /dev/null +++ b/public/assets/js/admin-stats.js @@ -0,0 +1,68 @@ +/* Admin stats : groupes AS + chargement pages via flux RSS XML /trending?period=14d */ + +// ── Groupes de réseaux ──────────────────────────────────────────────────────── +(function () { + var addBtn = document.getElementById('as-group-add'); + if (!addBtn) { return; } + + addBtn.addEventListener('click', function () { + var tpl = document.getElementById('as-group-tpl').content.cloneNode(true); + document.getElementById('as-groups-list').appendChild(tpl); + }); + + document.getElementById('as-groups-list').addEventListener('click', function (e) { + if (e.target.classList.contains('as-group-delete')) { + e.target.closest('.as-group-row').remove(); + } + }); +}()); + +// ── Pages les plus visitées (RSS XML) ──────────────────────────────────────── +(function () { + var container = document.getElementById('stats-pages-container'); + var badge = document.getElementById('stats-pages-count'); + if (!container) { return; } + + function esc(s) { + return String(s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + } + + fetch('/trending?period=14d') + .then(function (r) { return r.ok ? r.text() : Promise.reject(); }) + .then(function (xml) { + var doc = new DOMParser().parseFromString(xml, 'application/xml'); + var items = Array.from(doc.querySelectorAll('item')); + if (!items.length) { + container.innerHTML = '

Aucune donnée.

'; + return; + } + var rows = items.map(function (item) { + var raw = (item.querySelector('title') || { textContent: '' }).textContent; + var link = ((item.querySelector('link') || {}).textContent || '').trim(); + var m = raw.match(/\((\d+)\s+visiteurs?\)$/); + var vis = m ? parseInt(m[1], 10) : 0; + var title = raw.replace(/\s*\(\d+\s+visiteurs?\)$/, ''); + var slug = decodeURIComponent(link.replace(/.*\/post\//, '')); + return { title: title, link: link, slug: slug, vis: vis }; + }); + var maxV = Math.max.apply(null, rows.map(function (r) { return r.vis; })) || 1; + var html = '
'; + rows.forEach(function (row, i) { + var pct = Math.round(row.vis / maxV * 100); + var vis = row.vis.toLocaleString('fr-FR'); + html += '' + + '' + + '' + + '' + + ''; + }); + html += '
' + (i + 1) + '' + + esc(row.title || row.slug) + '' + + '
' + vis + ' vis.
'; + if (badge) { badge.textContent = rows.length + ' URLs'; } + container.innerHTML = html; + }) + .catch(function () { + container.innerHTML = '

Impossible de charger le flux.

'; + }); +}()); diff --git a/public/assets/js/admin.js b/public/assets/js/admin.js index 12d6f90..33b859f 100644 --- a/public/assets/js/admin.js +++ b/public/assets/js/admin.js @@ -45,4 +45,28 @@ document.addEventListener('DOMContentLoaded', function () { } }); } + + // Suppression groupée avec confirmation (remplace onclick inline) + var bulkDeleteBtn = document.getElementById('bulk-delete-btn'); + if (bulkDeleteBtn) { + bulkDeleteBtn.addEventListener('click', function (e) { + var checked = document.querySelectorAll('.bulk-check:checked').length; + if (checked === 0) { e.preventDefault(); return; } + var msg = bulkDeleteBtn.getAttribute('data-confirm-bulk') || 'Confirmer ?'; + if (!window.confirm(msg)) { e.preventDefault(); } + }); + } + + // Ajout d'un article à un livre (remplace onchange="bookAddArticle(this)") + var bookArticleSel = document.getElementById('book-article-select'); + if (bookArticleSel) { + bookArticleSel.addEventListener('change', function () { + var slug = bookArticleSel.value; + if (!slug) { return; } + var ta = document.getElementById('book-articles-ta'); + var lines = ta.value.split('\n').map(function (s) { return s.trim(); }).filter(Boolean); + if (lines.indexOf(slug) === -1) { lines.push(slug); ta.value = lines.join('\n'); } + bookArticleSel.value = ''; + }); + } }); diff --git a/public/assets/js/density-fouc.js b/public/assets/js/density-fouc.js new file mode 100644 index 0000000..89c097c --- /dev/null +++ b/public/assets/js/density-fouc.js @@ -0,0 +1,11 @@ +/* Anti-FOUC densité — chargé tôt dans pour appliquer max-width avant rendu de
*/ +(function () { + var d = localStorage.getItem('folio_density'); + if (d && d !== 'l') { + var mw = d === 'm' ? '980px' : '660px'; + var s = document.createElement('style'); + s.id = 'density-fouc'; + s.textContent = 'main[role="main"]{max-width:' + mw + '!important;margin-left:auto!important;margin-right:auto!important}'; + document.head.appendChild(s); + } +}()); diff --git a/public/assets/js/density.js b/public/assets/js/density.js new file mode 100644 index 0000000..17847b3 --- /dev/null +++ b/public/assets/js/density.js @@ -0,0 +1,38 @@ +/* Sélecteur de densité L/M/S — persisté dans localStorage */ +(function () { + var KEY = 'folio_density'; + var cur = localStorage.getItem(KEY) || 'l'; + + function applyDensity(d) { + var fouc = document.getElementById('density-fouc'); + if (d !== 'l') { + var mw = d === 'm' ? '980px' : '660px'; + if (!fouc) { + fouc = document.createElement('style'); + fouc.id = 'density-fouc'; + document.head.appendChild(fouc); + } + fouc.textContent = 'main[role="main"]{max-width:' + mw + '!important;margin-left:auto!important;margin-right:auto!important}'; + } else { + if (fouc) { fouc.parentNode.removeChild(fouc); } + } + document.querySelectorAll('.density-btn').forEach(function (btn) { + btn.classList.toggle('active', btn.getAttribute('data-d') === d); + }); + } + + applyDensity(cur); + + document.addEventListener('click', function (e) { + var el = e.target; + while (el && el !== document) { + if (el.classList && el.classList.contains('density-btn')) { + cur = el.getAttribute('data-d') || 'l'; + try { localStorage.setItem(KEY, cur); } catch (ignore) {} + applyDensity(cur); + return; + } + el = el.parentNode; + } + }); +}()); diff --git a/public/assets/js/trending-home.js b/public/assets/js/trending-home.js new file mode 100644 index 0000000..6c37e4a --- /dev/null +++ b/public/assets/js/trending-home.js @@ -0,0 +1,51 @@ +/* Chargement AJAX de la section "Meilleures audiences" via le flux RSS XML /trending?period=1h */ +(function () { + var grid = document.getElementById('home-audiences-grid'); + if (!grid) { return; } + + var gradients = [ + 'linear-gradient(135deg,#667eea 0%,#764ba2 100%)', + 'linear-gradient(135deg,#f093fb 0%,#f5576c 100%)', + 'linear-gradient(135deg,#4facfe 0%,#00f2fe 100%)', + 'linear-gradient(135deg,#43e97b 0%,#38f9d7 100%)', + 'linear-gradient(135deg,#fa709a 0%,#fee140 100%)', + 'linear-gradient(135deg,#a18cd1 0%,#fbc2eb 100%)' + ]; + + function esc(s) { + return String(s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + } + + fetch('/trending?period=1h') + .then(function (r) { return r.ok ? r.text() : Promise.reject(); }) + .then(function (xml) { + var doc = new DOMParser().parseFromString(xml, 'application/xml'); + var items = Array.from(doc.querySelectorAll('item')).slice(0, 6); + if (!items.length) { return; } + + grid.innerHTML = items.map(function (item, i) { + var raw = (item.querySelector('title') || { textContent: '' }).textContent; + var title = raw.replace(/\s*\(\d+\s+visiteurs?\)$/, ''); + var link = ((item.querySelector('link') || {}).textContent || '#').trim(); + var pd = (item.querySelector('pubDate') || { textContent: '' }).textContent; + var date = ''; + try { if (pd) { date = new Date(pd).toLocaleDateString('fr-FR'); } } catch (err) {} + var grad = gradients[i % gradients.length]; + + return '
' + + '
' + + '
' + + '

' + esc(title) + '

' + + '
' + + '' + + '
'; + }).join(''); + + var section = document.getElementById('home-audiences-section'); + if (section) { section.hidden = false; } + }) + .catch(function () {}); +}()); diff --git a/templates/admin.php b/templates/admin.php index 5e531bf..8affe38 100644 --- a/templates/admin.php +++ b/templates/admin.php @@ -264,8 +264,8 @@ function adminStatusBadge(array $a, int $now): string - @@ -1273,7 +1273,7 @@ foreach (COLOR_PALETTE_16 as $_i => $_rgb):
- $_rgb): -
Nouveau livre
diff --git a/templates/admin_stats.php b/templates/admin_stats.php index 8dca9e0..60174bf 100644 --- a/templates/admin_stats.php +++ b/templates/admin_stats.php @@ -195,60 +195,4 @@ $_activeGroup = trim($_GET['group'] ?? '');
- + diff --git a/templates/layout.php b/templates/layout.php index ee64ef2..c96bf79 100644 --- a/templates/layout.php +++ b/templates/layout.php @@ -50,7 +50,7 @@ class=""> - +