Files
html/api/avatar-picker.php
2026-04-12 22:57:03 +02:00

186 lines
9.6 KiB
PHP

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WEVIA Agent Avatar Picker</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#050a18;color:#e2e8f0;font-family:system-ui,sans-serif;min-height:100vh}
.hdr{background:linear-gradient(135deg,#0f1629,#1a2035);border-bottom:1px solid rgba(6,182,212,.2);padding:12px 16px;position:sticky;top:0;z-index:50}
.hdr-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
.title{font-size:15px;font-weight:900;color:#06b6d4;letter-spacing:1px}
.copy-btn{padding:6px 16px;border:none;border-radius:8px;background:linear-gradient(135deg,#06b6d4,#8b5cf6);color:#fff;font-weight:700;font-size:12px;cursor:pointer}
.copy-btn:hover{transform:scale(1.05)}
.filters{display:flex;gap:6px}
.fbtn{padding:4px 12px;border-radius:6px;border:1px solid rgba(255,255,255,.1);background:transparent;color:#94a3b8;font-size:10px;font-weight:700;cursor:pointer;letter-spacing:1px}
.fbtn.active{border-color:#06b6d4;background:rgba(6,182,212,.15);color:#06b6d4}
.picks-bar{padding:8px 16px;background:#0a0f1e;border-bottom:1px solid rgba(255,215,0,.15);display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.pick-tag{display:inline-flex;align-items:center;gap:4px;background:rgba(255,215,0,.08);border:1px solid rgba(255,215,0,.2);border-radius:6px;padding:2px 6px;font-size:9px;color:#ffd700}
.pick-tag img{width:16px;height:16px;border-radius:3px}
.grid{padding:12px;display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:10px}
.card{background:#0f1629;border:1px solid rgba(255,255,255,.06);border-radius:10px;padding:12px}
.card.picked{background:rgba(255,215,0,.03);border-color:rgba(255,215,0,.3)}
.card-hdr{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.card-hdr img{width:36px;height:36px;border-radius:8px;border:2px solid #ffd700}
.agent-name{font-weight:800;font-size:13px}
.agent-meta{font-size:9px;color:#64748b}
.picked-label{margin-left:auto;font-size:9px;color:#ffd700;background:rgba(255,215,0,.1);padding:2px 8px;border-radius:4px}
.opts{display:flex;gap:5px;flex-wrap:wrap}
.opt{display:flex;flex-direction:column;align-items:center;gap:2px;padding:4px;border-radius:8px;border:2px solid rgba(255,255,255,.05);background:rgba(255,255,255,.02);cursor:pointer;width:72px;transition:all .15s}
.opt:hover{transform:scale(1.05)}
.opt.selected{border-color:#ffd700;background:rgba(255,215,0,.06)}
.opt img{width:52px;height:52px;border-radius:6px;background:#1a2035;object-fit:cover}
.opt .lbl{font-size:7px;color:#94a3b8;text-align:center;line-height:1.1}
.opt .src{font-size:6px;color:#475569}
.footer{padding:12px 16px;text-align:center;color:#475569;font-size:10px}
</style>
</head>
<body>
<div class="hdr">
<div class="hdr-top">
<div class="title">🎨 AGENT AVATAR PICKER</div>
<button class="copy-btn" onclick="copyPicks()" id="copyBtn" style="display:none">📋 Copier choix</button>
</div>
<div class="filters" id="filters"></div>
</div>
<div class="picks-bar" id="picksBar" style="display:none"></div>
<div class="grid" id="grid"></div>
<div class="footer">Clique sur un avatar pour le sélectionner · Re-clique pour désélectionner · Copie tes choix en haut</div>
<script>
const AGENTS=[
{n:"WEVIA Master",tier:"STRATÉGIE",type:"robot",color:"#06b6d4"},
{n:"Director",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"Master Router",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"Consensus",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"Dispatcher",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"MiroFish",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"Blade",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"DeerFlow",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"AutoFix",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"Fiability",tier:"DIRECTION",type:"robot",color:"#8b5cf6"},
{n:"DevOps",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"Ethica",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"Security",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"Monitor",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"NonReg",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"WEVCODE",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"L99 Pilot",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"Scraper",tier:"TACTIQUE",type:"robot",color:"#f59e0b"},
{n:"ArchScan",tier:"TACTIQUE",type:"robot",color:"#f59e0b"},
{n:"CrowdSec",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"Fail2Ban",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"Registry",tier:"TACTIQUE",type:"human",color:"#f59e0b"},
{n:"Ollama",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
{n:"Groq",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
{n:"Cerebras",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
{n:"SambaNova",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
{n:"Paperclip",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
{n:"Sentinel",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
{n:"Docker",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
{n:"PMTA",tier:"EXÉCUTION",type:"robot",color:"#ef4444"},
];
function getOpts(a) {
const s = encodeURIComponent(a.n);
if (a.type === "robot") return [
{url:`https://robohash.org/${s}?set=set1&size=150x150`,label:"Robot Set1",src:"RoboHash"},
{url:`https://robohash.org/${s}-v2?set=set1&size=150x150`,label:"Robot Alt",src:"RoboHash"},
{url:`https://robohash.org/${s}-v3?set=set1&size=150x150`,label:"Robot V3",src:"RoboHash"},
{url:`https://robohash.org/${s}?set=set2&size=150x150`,label:"Monster",src:"RoboHash"},
{url:`https://robohash.org/${s}?set=set3&size=150x150`,label:"Head",src:"RoboHash"},
{url:`https://robohash.org/${s}?set=set4&size=150x150`,label:"Cat",src:"RoboHash"},
{url:`https://api.dicebear.com/9.x/bottts/svg?seed=${s}`,label:"Bottts",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/fun-emoji/svg?seed=${s}`,label:"Fun Emoji",src:"DiceBear"},
];
return [
{url:`https://api.dicebear.com/9.x/adventurer/svg?seed=${s}`,label:"Adventurer",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/adventurer/svg?seed=${s}-v2`,label:"Adventurer V2",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/adventurer/svg?seed=${s}-v3`,label:"Adventurer V3",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/avataaars/svg?seed=${s}`,label:"Avataaars",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/big-smile/svg?seed=${s}`,label:"Big Smile",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/lorelei/svg?seed=${s}`,label:"Lorelei",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/notionists/svg?seed=${s}`,label:"Notionists",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/open-peeps/svg?seed=${s}`,label:"Open Peeps",src:"DiceBear"},
{url:`https://api.dicebear.com/9.x/pixel-art/svg?seed=${s}`,label:"Pixel Art",src:"DiceBear"},
{url:`https://robohash.org/${s}?set=set5&size=150x150`,label:"RoboHash Human",src:"RoboHash"},
];
}
const picks = {};
let currentFilter = "ALL";
function render() {
const grid = document.getElementById("grid");
const filtered = currentFilter === "ALL" ? AGENTS : AGENTS.filter(a => a.tier === currentFilter);
// Filters
const filtersDiv = document.getElementById("filters");
filtersDiv.innerHTML = ["ALL","STRATÉGIE","DIRECTION","TACTIQUE","EXÉCUTION"].map(t =>
`<button class="fbtn ${currentFilter===t?'active':''}" onclick="setFilter('${t}')">${t}</button>`
).join("");
// Copy button
const n = Object.keys(picks).length;
document.getElementById("copyBtn").style.display = n > 0 ? "block" : "none";
document.getElementById("copyBtn").textContent = `📋 Copier ${n} choix`;
// Picks bar
const bar = document.getElementById("picksBar");
if (n > 0) {
bar.style.display = "flex";
bar.innerHTML = `<span style="font-size:10px;color:#94a3b8">✅ ${n} choix :</span>` +
Object.entries(picks).map(([name, {url, label}]) =>
`<span class="pick-tag"><img src="${url}">${name} <span style="color:#94a3b8">(${label})</span></span>`
).join("");
} else {
bar.style.display = "none";
}
// Cards
grid.innerHTML = filtered.map(agent => {
const opts = getOpts(agent);
const p = picks[agent.n];
return `<div class="card ${p?'picked':''}">
<div class="card-hdr">
${p ? `<img src="${p.url}">` : ''}
<div>
<div class="agent-name" style="color:${agent.color}">${agent.n}</div>
<div class="agent-meta">${agent.tier} · ${agent.type}</div>
</div>
${p ? `<span class="picked-label"> ${p.label}</span>` : ''}
</div>
<div class="opts">
${opts.map((o,i) => `<div class="opt ${p?.url===o.url?'selected':''}" onclick="pick('${agent.n.replace(/'/g,"\\'")}','${o.url.replace(/'/g,"\\'")}','${o.label}')"
onmouseover="this.style.borderColor='${agent.color}'"
onmouseout="this.style.borderColor='${p?.url===o.url?'#ffd700':'rgba(255,255,255,.05)}'">
<img src="${o.url}" onerror="this.style.opacity=0.3">
<div class="lbl">${o.label}</div>
<div class="src">${o.src}</div>
</div>`).join("")}
</div>
</div>`;
}).join("");
}
function setFilter(f) { currentFilter = f; render(); }
function pick(name, url, label) {
if (picks[name]?.url === url) delete picks[name];
else picks[name] = { url, label };
render();
}
function copyPicks() {
const txt = Object.entries(picks).map(([k,v]) => `${k}: ${v.label} → ${v.url}`).join("\n");
navigator.clipboard?.writeText(txt);
alert(`${Object.keys(picks).length} choix copiés !\n\n${txt}`);
}
render();
</script>
</body>
</html>