Files
html/weval-sitemap.html

306 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WEVAL Sitemap · Toutes pages · Source unique</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
--bg:#09090b; --surface:#13131a; --surface2:#1a1a24; --border:#2a2a35;
--text:#fafafa; --muted:#94a3b8; --accent:#6366f1; --accent2:#a855f7;
--green:#22c55e; --amber:#f59e0b; --red:#ef4444; --cyan:#22d3ee;
--grad:linear-gradient(135deg,#6366f1 0%,#a855f7 50%,#ec4899 100%);
}
body{font-family:-apple-system,Inter,Segoe UI,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;line-height:1.5}
.topbar{background:var(--surface);border-bottom:1px solid var(--border);padding:14px 28px;display:flex;justify-content:space-between;align-items:center;position:sticky;top:0;z-index:100;backdrop-filter:blur(20px)}
.topbar h1{font-size:1.15rem;font-weight:700;background:var(--grad);-webkit-background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:-0.02em}
.topbar .meta{display:flex;gap:14px;align-items:center;font-size:.78rem;color:var(--muted)}
.topbar .live{display:inline-flex;align-items:center;gap:6px;color:var(--green);font-weight:600}
.topbar .live::before{content:'';width:8px;height:8px;background:var(--green);border-radius:99px;box-shadow:0 0 12px var(--green);animation:pulse 1.5s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
.bread{padding:14px 28px;background:var(--surface);font-size:.78rem;color:var(--muted);border-bottom:1px solid var(--border)}
.bread a{color:var(--accent);text-decoration:none;margin-right:6px}
main{padding:28px;max-width:1700px;margin:0 auto}
.hero{background:linear-gradient(135deg,rgba(99,102,241,.1),rgba(168,85,247,.05));border:1px solid rgba(99,102,241,.2);border-radius:16px;padding:24px 28px;margin-bottom:24px;position:relative;overflow:hidden}
.hero::before{content:'';position:absolute;top:-50%;right:-10%;width:300px;height:300px;background:radial-gradient(circle,rgba(99,102,241,.15),transparent 70%);pointer-events:none}
.hero h2{font-size:1.4rem;margin-bottom:6px;background:var(--grad);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.hero p{color:var(--muted);font-size:.85rem;line-height:1.6}
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:18px}
.kpi{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:16px;position:relative;overflow:hidden}
.kpi::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:var(--grad);opacity:.6}
.kpi .lbl{font-size:.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:1px;font-weight:600;margin-bottom:4px}
.kpi .val{font-size:1.6rem;font-weight:700;background:linear-gradient(180deg,var(--text),var(--muted));-webkit-background-clip:text;-webkit-text-fill-color:transparent;line-height:1.1}
.kpi .sub{font-size:.7rem;color:var(--muted);margin-top:4px}
.controls{display:flex;gap:10px;margin-bottom:18px;flex-wrap:wrap;align-items:center}
.search{flex:1;min-width:280px;padding:10px 14px;background:var(--surface);border:1px solid var(--border);border-radius:10px;color:var(--text);font-size:.88rem;outline:none}
.search:focus{border-color:var(--accent)}
.filter-btn{padding:7px 13px;background:var(--surface);border:1px solid var(--border);border-radius:99px;color:var(--muted);font-size:.75rem;cursor:pointer;transition:.2s;font-weight:600}
.filter-btn:hover{border-color:var(--accent);color:var(--text)}
.filter-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}
.cat-section{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px}
.cat-title{font-size:.95rem;font-weight:700;color:var(--text);display:flex;align-items:center;gap:10px;margin-bottom:12px}
.cat-title .badge{background:var(--surface2);color:var(--cyan);padding:3px 9px;border-radius:99px;font-size:.7rem;font-weight:600;font-variant-numeric:tabular-nums}
.page-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:8px}
.page-card{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:4px;transition:.2s;text-decoration:none;color:var(--text);cursor:pointer}
.page-card:hover{border-color:var(--accent);background:rgba(99,102,241,.08);transform:translateY(-1px);box-shadow:0 8px 20px rgba(99,102,241,.1)}
.page-card .name{font-size:.78rem;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.page-card .meta{font-size:.65rem;color:var(--muted);display:flex;justify-content:space-between;align-items:center;gap:6px}
.page-card .badge-orphan{background:rgba(245,158,11,.15);color:var(--amber);padding:1px 6px;border-radius:4px;font-size:.6rem;font-weight:600}
.page-card .badge-linked{background:rgba(34,197,94,.15);color:var(--green);padding:1px 6px;border-radius:4px;font-size:.6rem;font-weight:600}
.empty{text-align:center;color:var(--muted);padding:40px;font-size:.85rem;font-style:italic}
footer{padding:32px 28px;text-align:center;color:var(--muted);font-size:.75rem;border-top:1px solid var(--border);margin-top:32px}
footer a{color:var(--accent);text-decoration:none;margin:0 8px}
.refresh{padding:5px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:99px;color:var(--muted);font-size:.7rem;cursor:pointer}
.refresh:hover{border-color:var(--accent);color:var(--text)}
</style>
<!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-143942 -->
<style id="doctrine60-ux-direct">
/* DOCTRINE-60-UX-ENRICH injected-direct */
body::before {
content: '';
position: fixed;
top: 0; left: 0; width: 100vw; height: 100vh;
background: radial-gradient(circle at 50% 50%, rgba(100,180,255,0.08), transparent 60%);
pointer-events: none;
z-index: -1;
}
.card, .kpi, .panel, .btn {
transition: all 0.3s cubic-bezier(0.2,0,0.1,1);
}
.card:hover, .kpi:hover, .panel:hover {
box-shadow: 0 4px 20px rgba(100,180,255,0.2);
border-color: rgba(100,180,255,0.5);
}
@keyframes pulseD60 {
0%,100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.05); }
}
.pulse, .live-indicator, .active, .online {
animation: pulseD60 3s ease-in-out infinite;
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.enter-stagger {
animation: enterStagD60 0.5s cubic-bezier(0.2,0,0.1,1) forwards;
}
@keyframes enterStagD60 {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<div class="topbar">
<h1>🗺 WEVAL Sitemap · Toutes pages</h1>
<div class="meta">
<span>Source: <a href="/api/weval-sitemap-api.php" style="color:var(--cyan)">sitemap-api</a></span>
<span>Refresh: <span id="ts"></span></span>
<button class="refresh" onclick="loadAll()"></button>
<span class="live">LIVE</span>
</div>
</div>
<div class="bread">
<a href="/">Home</a> /
<a href="/wevia-erp-v2.html">ERP V2</a> /
<a href="/architecture.html">Architecture</a> /
<span style="color:var(--text)">Sitemap exhaustif</span>
</div>
<main>
<div class="hero">
<h2>🗺 Sitemap exhaustif · Source unique fichiers</h2>
<p>Référentiel complet de toutes les pages HTML déployées · Live filesystem scan · Catégorisation automatique · Détection orphelins · Last modified · Recherche + filtres · <b>Aucune page perdue</b> · <b>Zero orphan</b> · Auto-refresh 60s</p>
</div>
<div class="kpi-grid">
<div class="kpi"><div class="lbl">Total pages</div><div class="val" id="k-total"></div><div class="sub">HTML déployées</div></div>
<div class="kpi"><div class="lbl">Catégories</div><div class="val" id="k-cats"></div><div class="sub">groupées par fonction</div></div>
<div class="kpi"><div class="lbl">Orphan pages</div><div class="val" id="k-orphan"></div><div class="sub">non linkées encore</div></div>
<div class="kpi"><div class="lbl">Last update</div><div class="val" id="k-last" style="font-size:1rem"></div><div class="sub">scan timestamp</div></div>
</div>
<div class="controls">
<input type="text" class="search" id="search" placeholder="🔍 Rechercher par nom (ex: agent, hub, dashboard, ethica)..." oninput="render()">
<button class="filter-btn active" onclick="setFilter('all',this)">Toutes</button>
<button class="filter-btn" onclick="setFilter('orphan',this)">⚠ Orphelines</button>
<button class="filter-btn" onclick="setFilter('linked',this)">✓ Liées</button>
</div>
<div id="cat-list"></div>
</main>
<footer>
WEVAL Sitemap · scan exhaustif filesystem · v1.0 ·
<a href="/wevia-master.html">WEVIA Master</a> ·
<a href="/wevia-erp-v2.html">ERP V2</a> ·
<a href="/wevia-erp-unified.html">ERP V1</a> ·
<a href="/architecture.html">Architecture</a> ·
<a href="/api/weval-sitemap-api.php">API JSON</a>
</footer>
<script>
let DATA = null;
let FILTER = 'all';
function fmt(n){return (n||0).toLocaleString('fr-FR')}
async function loadAll() {
document.getElementById('ts').textContent = new Date().toLocaleTimeString('fr-FR');
try {
DATA = await fetch('/api/weval-sitemap-api.php').then(r => r.json());
if (!DATA.ok) throw new Error('api error');
document.getElementById('k-total').textContent = fmt(DATA.stats.total_pages);
document.getElementById('k-cats').textContent = fmt(DATA.stats.total_categories);
document.getElementById('k-orphan').textContent = fmt(DATA.stats.orphan_count);
document.getElementById('k-last').textContent = new Date(DATA.ts).toLocaleString('fr-FR');
render();
} catch (e) {
document.getElementById('cat-list').innerHTML = '<div class="empty">Erreur API: ' + e.message + '</div>';
}
}
function setFilter(f, btn) {
FILTER = f;
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
render();
}
function render() {
if (!DATA) return;
const search = document.getElementById('search').value.toLowerCase().trim();
const out = [];
const cats = Object.keys(DATA.by_category).sort((a,b) =>
DATA.by_category[b].length - DATA.by_category[a].length
);
for (const cat of cats) {
let pages = DATA.by_category[cat];
if (FILTER === 'orphan') pages = pages.filter(p => p.is_orphan);
if (FILTER === 'linked') pages = pages.filter(p => !p.is_orphan);
if (search) pages = pages.filter(p => p.name.toLowerCase().includes(search));
if (pages.length === 0) continue;
const cards = pages.map(p => {
const orphanBadge = p.is_orphan
? `<span class="badge-orphan">orphan</span>`
: `<span class="badge-linked">${p.ref_count}×</span>`;
return `
<a class="page-card" href="${p.url}" target="_blank">
<div class="name" title="${p.name}">${p.name}</div>
<div class="meta">
<span>${p.size_kb} KB · ${p.mtime_human}</span>
${orphanBadge}
</div>
</a>`;
}).join('');
out.push(`
<div class="cat-section">
<div class="cat-title">${cat} <span class="badge">${pages.length}</span></div>
<div class="page-grid">${cards}</div>
</div>`);
}
document.getElementById('cat-list').innerHTML = out.length
? out.join('')
: '<div class="empty">Aucun résultat pour ces filtres</div>';
}
loadAll();
setInterval(loadAll, 60000);
</script>
<script src="/api/ux-drill-enricher.php"></script>
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
<script>
(function(){
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
var d = document;
var m = d.createElement('div');
m.id = 'opus-udrill';
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
var inner = d.createElement('div');
inner.id = 'opus-udrill-in';
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
inner.addEventListener('click', function(e){ e.stopPropagation(); });
m.appendChild(inner);
m.addEventListener('click', function(){ m.style.display='none'; });
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
(d.body || d.documentElement).appendChild(m);
function openCard(card) {
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
inner.innerHTML = html;
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
m.style.display = 'flex';
}
function wire(root) {
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
var cards = root.querySelectorAll(sels);
for (var i = 0; i < cards.length; i++) {
var c = cards[i];
if (c.__opusWired) continue;
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
var r = c.getBoundingClientRect();
if (r.width < 60 || r.height < 40) continue;
c.__opusWired = true;
c.style.cursor = 'pointer';
c.setAttribute('role','button');
c.setAttribute('tabindex','0');
c.addEventListener('click', function(ev){
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
if (ev.target.closest('a,button,input,select')) return;
ev.preventDefault(); ev.stopPropagation();
openCard(this);
});
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
}
}
var initRun = function(){ wire(d.body || d.documentElement); };
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
else initRun();
var mo = new MutationObserver(function(muts){
var newCard = false;
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
if (newCard) initRun();
});
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t31b3) --><script src="/wtp-unified-dock.js" defer></script>
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-direct">
// DOCTRINE-60-UX-JS staggered entrance
(function(){
if (!('IntersectionObserver' in window)) return;
const obs = new IntersectionObserver((entries) => {
entries.forEach((e, i) => {
if (e.isIntersecting) {
setTimeout(() => e.target.classList.add('enter-stagger'), i * 80);
obs.unobserve(e.target);
}
});
});
document.querySelectorAll('.card, .kpi, .panel').forEach(el => obs.observe(el));
})();
</script>
</body>
</html>