Files
html/vnc-picker.html
Opus 4c53d42794 ui(v1.7-premium): Luxury Darklab Control Room UX refresh
vnc-picker.html + web-ia-status.html refondus :
- Typo Cormorant Garamond display + JetBrains Mono
- Palette dark noir/ivoire/champagne gold + coral/mint accents
- Glassmorphism + gradient mesh + noise texture atmosphere
- Staggered reveal animations + 3D cursor tilt sur cards
- Stats temps reel (logged/running/prompts counters)
- Toast stack premium avec variants success/error
- Progress line streaming pendant send-prompt
- Live status dots (pulse green/gold/coral)
- Responsive breakpoints
- Zero icones, zero emojis - pure typographie editoriale

Doctrine en cours : 164 CDP attach (chrome-launch ports per-profile 9222-9229)
2026-04-24 01:43:00 +02:00

305 lines
18 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">
<title>WEVIA Cyber Command — Profile Picker</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;700&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#08080c;--panel:rgba(18,18,26,0.55);--panel-hover:rgba(28,28,40,0.75);
--border:rgba(255,255,255,0.06);--border-hover:rgba(246,213,114,0.4);
--ink:#ebe6d8;--ink-dim:#9a9384;--ink-faint:#5a5650;
--gold:#f6d572;--gold-deep:#b8923c;--coral:#ff6b5e;--mint:#7fffd4;--azure:#8ecfff;
--font-display:'Cormorant Garamond',serif;--font-mono:'JetBrains Mono',ui-monospace,monospace;
--ease:cubic-bezier(.23,1,.32,1);--ease-out:cubic-bezier(.16,1,.3,1);
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{background:var(--bg);color:var(--ink);font-family:var(--font-mono);min-height:100vh;overflow-x:hidden;font-weight:300;letter-spacing:.02em}
/* Atmosphere - gradient mesh background */
body::before{
content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
background:
radial-gradient(ellipse 80% 60% at 20% 10%,rgba(246,213,114,0.08) 0%,transparent 55%),
radial-gradient(ellipse 60% 80% at 85% 90%,rgba(142,207,255,0.06) 0%,transparent 55%),
radial-gradient(ellipse 50% 40% at 50% 50%,rgba(127,255,212,0.03) 0%,transparent 60%);
}
/* Noise texture overlay */
body::after{
content:"";position:fixed;inset:0;z-index:0;pointer-events:none;opacity:0.035;
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}
main{position:relative;z-index:1;min-height:100vh;padding:48px 56px 96px;max-width:1680px;margin:0 auto}
/* Header - editorial premium */
.masthead{display:grid;grid-template-columns:1fr auto;align-items:end;gap:40px;margin-bottom:56px;padding-bottom:32px;border-bottom:1px solid var(--border)}
.eyebrow{display:flex;align-items:center;gap:14px;color:var(--gold);font-size:10px;font-weight:500;letter-spacing:.42em;text-transform:uppercase;margin-bottom:18px}
.eyebrow::before{content:"";width:28px;height:1px;background:var(--gold)}
.eyebrow .live-dot{width:6px;height:6px;border-radius:50%;background:var(--mint);box-shadow:0 0 12px var(--mint);animation:pulse 2s ease infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.2)}}
h1{font-family:var(--font-display);font-weight:300;font-size:clamp(48px,6vw,88px);line-height:.94;letter-spacing:-.03em;color:var(--ink)}
h1 em{font-style:italic;font-weight:400;color:var(--gold);position:relative}
h1 em::after{content:"";position:absolute;left:0;bottom:.08em;width:100%;height:1px;background:var(--gold);opacity:.5}
.subtitle{max-width:520px;margin-top:24px;font-size:13px;line-height:1.8;color:var(--ink-dim);font-weight:300}
.stats{display:flex;gap:40px;align-items:flex-start}
.stat{text-align:right}
.stat-value{font-family:var(--font-display);font-size:52px;font-weight:300;line-height:1;color:var(--gold);letter-spacing:-.02em}
.stat-label{font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--ink-faint);margin-top:8px}
/* Command bar */
.command-bar{display:flex;align-items:center;gap:12px;padding:14px 18px;background:var(--panel);backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:2px;margin-bottom:40px;font-size:11px}
.cb-prompt{color:var(--gold);font-weight:500;letter-spacing:.12em}
.cb-path{color:var(--ink-dim);flex:1}
.cb-actions{display:flex;gap:4px}
.cb-btn{padding:7px 14px;background:transparent;border:1px solid var(--border);color:var(--ink-dim);font-family:var(--font-mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;cursor:pointer;text-decoration:none;transition:all .3s var(--ease);font-weight:400}
.cb-btn:hover{background:var(--panel-hover);border-color:var(--border-hover);color:var(--gold)}
.cb-btn.primary{background:var(--gold);color:#0a0a0f;border-color:var(--gold);font-weight:600}
.cb-btn.primary:hover{background:var(--ink);border-color:var(--ink)}
/* Instructions - editorial style */
.briefing{display:grid;grid-template-columns:auto 1fr auto;gap:32px;margin-bottom:56px;padding:28px 32px;background:linear-gradient(135deg,rgba(246,213,114,0.04) 0%,transparent 60%);border:1px solid var(--border);border-left:2px solid var(--gold);border-radius:2px;position:relative;overflow:hidden}
.briefing::before{content:"BRIEFING";position:absolute;top:12px;right:16px;font-size:8px;letter-spacing:.42em;color:var(--gold);opacity:.4;font-weight:600}
.briefing-num{font-family:var(--font-display);font-size:88px;font-weight:300;line-height:1;color:var(--gold);opacity:.2}
.briefing-steps{display:flex;flex-direction:column;gap:10px;padding:8px 0}
.briefing-step{display:flex;align-items:baseline;gap:16px;font-size:12px;line-height:1.6}
.briefing-step-n{color:var(--gold);font-weight:500;min-width:24px;font-variant-numeric:tabular-nums}
.briefing-step span{color:var(--ink-dim)}
.briefing-step code{color:var(--gold);background:rgba(246,213,114,0.08);padding:2px 6px;border-radius:2px;font-size:11px}
.briefing-secret{align-self:flex-end;display:flex;flex-direction:column;gap:6px;text-align:right}
.briefing-secret-label{font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--ink-faint)}
.briefing-secret-value{font-size:13px;color:var(--gold);font-weight:500;letter-spacing:.04em}
/* Cards grid */
.section-label{display:flex;align-items:center;gap:16px;font-size:10px;letter-spacing:.42em;text-transform:uppercase;color:var(--ink-faint);margin-bottom:24px;font-weight:500}
.section-label::before,.section-label::after{content:"";flex:1;height:1px;background:var(--border)}
.section-label span{color:var(--gold)}
.profiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:20px}
.profile-card{position:relative;padding:26px 28px 22px;background:var(--panel);backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:3px;cursor:pointer;transition:all .5s var(--ease);overflow:hidden;opacity:0;animation:slideUp .9s var(--ease) forwards}
.profile-card:nth-child(1){animation-delay:.05s}
.profile-card:nth-child(2){animation-delay:.1s}
.profile-card:nth-child(3){animation-delay:.15s}
.profile-card:nth-child(4){animation-delay:.2s}
.profile-card:nth-child(5){animation-delay:.25s}
.profile-card:nth-child(6){animation-delay:.3s}
.profile-card:nth-child(7){animation-delay:.35s}
.profile-card:nth-child(8){animation-delay:.4s}
@keyframes slideUp{from{opacity:0;transform:translateY(28px)}to{opacity:1;transform:translateY(0)}}
.profile-card::before{content:"";position:absolute;inset:0;background:radial-gradient(ellipse 80% 60% at 50% 0%,rgba(246,213,114,0.12) 0%,transparent 70%);opacity:0;transition:opacity .6s var(--ease);pointer-events:none}
.profile-card::after{content:"";position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent 0%,var(--gold) 50%,transparent 100%);opacity:0;transition:opacity .4s var(--ease)}
.profile-card:hover{border-color:var(--border-hover);background:var(--panel-hover);transform:translateY(-3px)}
.profile-card:hover::before{opacity:1}
.profile-card:hover::after{opacity:.6}
.pc-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:22px;position:relative}
.pc-monogram{font-family:var(--font-display);font-size:44px;font-weight:400;line-height:.85;color:var(--gold);letter-spacing:-.03em;font-style:italic}
.pc-index{font-size:9px;letter-spacing:.32em;color:var(--ink-faint);font-weight:500}
.pc-name{font-family:var(--font-display);font-size:26px;font-weight:400;letter-spacing:-.01em;color:var(--ink);line-height:1.1;margin-bottom:4px}
.pc-domain{font-size:11px;color:var(--ink-dim);letter-spacing:.04em;margin-bottom:18px;word-break:break-all}
.pc-status{display:flex;align-items:center;gap:10px;padding:10px 14px;margin:0 -4px 18px;background:rgba(255,255,255,0.02);border:1px solid var(--border);border-radius:2px;font-size:10px;letter-spacing:.12em;text-transform:uppercase}
.pc-status-dot{width:6px;height:6px;border-radius:50%;background:var(--ink-faint);flex-shrink:0;transition:all .3s var(--ease)}
.pc-status-dot.logged{background:var(--mint);box-shadow:0 0 8px var(--mint);animation:pulse 2.4s ease infinite}
.pc-status-dot.running{background:var(--gold);box-shadow:0 0 8px var(--gold);animation:pulse 1.8s ease infinite}
.pc-status-dot.offline{background:var(--coral);opacity:.4}
.pc-status-label{color:var(--ink-dim);flex:1}
.pc-status-label.ok{color:var(--mint)}
.pc-status-label.warn{color:var(--gold)}
.pc-status-meta{color:var(--ink-faint);font-family:var(--font-mono);font-size:10px;letter-spacing:0}
.pc-path{font-size:10px;color:var(--ink-faint);font-family:var(--font-mono);padding:8px 10px;background:rgba(0,0,0,0.25);border:1px solid var(--border);border-radius:2px;margin-bottom:18px;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pc-actions{display:flex;gap:6px}
.pc-btn{flex:1;padding:11px 14px;background:transparent;border:1px solid var(--border);color:var(--ink-dim);font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;cursor:pointer;transition:all .3s var(--ease);font-weight:500;text-decoration:none;text-align:center;border-radius:2px}
.pc-btn:hover{background:rgba(246,213,114,0.08);border-color:var(--gold);color:var(--gold)}
.pc-btn.primary{background:var(--gold);color:#0a0a0f;border-color:var(--gold);font-weight:600}
.pc-btn.primary:hover{background:var(--ink);border-color:var(--ink)}
/* Toast */
.toast-stack{position:fixed;bottom:32px;right:32px;z-index:9999;display:flex;flex-direction:column-reverse;gap:10px;pointer-events:none}
.toast{min-width:320px;padding:16px 20px;background:rgba(18,18,26,0.95);backdrop-filter:blur(24px);border:1px solid var(--border);border-left:2px solid var(--gold);border-radius:2px;font-size:12px;color:var(--ink-dim);box-shadow:0 20px 40px -12px rgba(0,0,0,0.6);pointer-events:auto;animation:toastIn .5s var(--ease) forwards}
.toast-title{color:var(--gold);font-size:10px;letter-spacing:.28em;text-transform:uppercase;margin-bottom:6px;font-weight:500}
.toast.success{border-left-color:var(--mint)}.toast.success .toast-title{color:var(--mint)}
.toast.error{border-left-color:var(--coral)}.toast.error .toast-title{color:var(--coral)}
@keyframes toastIn{from{opacity:0;transform:translateX(24px)}to{opacity:1;transform:translateX(0)}}
/* Footer */
footer{margin-top:80px;padding-top:32px;border-top:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;font-size:10px;letter-spacing:.12em;color:var(--ink-faint)}
footer a{color:var(--ink-dim);text-decoration:none;transition:color .3s var(--ease)}
footer a:hover{color:var(--gold)}
@media(max-width:900px){
main{padding:32px 24px 72px}
.masthead{grid-template-columns:1fr;gap:32px}
.stats{justify-content:flex-start}
.briefing{grid-template-columns:1fr;padding:24px}
.briefing-num{display:none}
}
</style>
</head>
<body>
<main>
<header class="masthead">
<div>
<div class="eyebrow"><span class="live-dot"></span> Doctrine 161 / 164 — Cyber Command Live</div>
<h1>Cyber <em>Profile</em><br>Picker</h1>
<p class="subtitle">Session interactive via noVNC pour étendre la souveraineté WEVIA aux 8 Web-IA gratuits. Login une fois — exploitation illimitée via Selenium CDP.</p>
</div>
<div class="stats">
<div class="stat"><div class="stat-value" id="stat-logged">0</div><div class="stat-label">Logged</div></div>
<div class="stat"><div class="stat-value" id="stat-running">0</div><div class="stat-label">Running</div></div>
<div class="stat"><div class="stat-value">8</div><div class="stat-label">Providers</div></div>
</div>
</header>
<div class="command-bar">
<span class="cb-prompt">wevia://</span>
<span class="cb-path">/cyber-profile-picker</span>
<div class="cb-actions">
<a class="cb-btn primary" href="/novnc/vnc.html" target="_blank">Open noVNC</a>
<a class="cb-btn" href="/web-ia-status.html">Dashboard</a>
<a class="cb-btn" href="/wevia-audit.html">Audit Trail</a>
<a class="cb-btn" href="javascript:location.reload()">Refresh</a>
</div>
</div>
<section class="briefing">
<div class="briefing-num">00</div>
<div class="briefing-steps">
<div class="briefing-step"><span class="briefing-step-n">01.</span><span>Sélectionne un profil ci-dessous — Chrome se lance dans le display virtuel du serveur avec <code>--remote-debugging-port</code> unique.</span></div>
<div class="briefing-step"><span class="briefing-step-n">02.</span><span>Clique "Open noVNC" pour projeter le bureau distant dans ton navigateur.</span></div>
<div class="briefing-step"><span class="briefing-step-n">03.</span><span>Login manuel (email, 2FA, etc.) — la session persiste dans <code>/var/lib/wevia-cyber-profiles/&lt;slug&gt;</code>.</span></div>
<div class="briefing-step"><span class="briefing-step-n">04.</span><span>WEVIA exploite la session via Selenium CDP attach — plus jamais de re-login.</span></div>
</div>
<div class="briefing-secret">
<div class="briefing-secret-label">VNC Password</div>
<div class="briefing-secret-value" id="vnc-pw">weviaVNC2026yac</div>
</div>
</section>
<div class="section-label"><span>Providers</span></div>
<div class="profiles" id="profiles-grid"></div>
<footer>
<div>WEVIA AUTONOMY — v1.7 / DOCTRINES 146164</div>
<div><a href="/wevia-audit.html">Audit Trail</a> · <a href="/web-ia-status.html">Live Status</a> · <a href="https://weval-consulting.com">weval-consulting.com</a></div>
</footer>
</main>
<div class="toast-stack" id="toast-stack"></div>
<script>
const PROVIDERS=[
{slug:'openai',name:'ChatGPT',mono:'C',domain:'chat.openai.com',cdp:9222},
{slug:'anthropic',name:'Claude.ai',mono:'A',domain:'claude.ai',cdp:9223},
{slug:'google',name:'Gemini',mono:'G',domain:'gemini.google.com',cdp:9224},
{slug:'deepseek',name:'DeepSeek',mono:'D',domain:'chat.deepseek.com',cdp:9225},
{slug:'mistral',name:'Mistral',mono:'M',domain:'chat.mistral.ai',cdp:9226},
{slug:'poe',name:'Poe',mono:'P',domain:'poe.com',cdp:9227},
{slug:'perplexity',name:'Perplexity',mono:'Px',domain:'www.perplexity.ai',cdp:9228},
{slug:'hf',name:'HuggingFace',mono:'H',domain:'huggingface.co',cdp:9229},
];
const state={};PROVIDERS.forEach(p=>state[p.slug]={running:false,logged:'unknown',cdp:null});
function toast(title,msg,kind){
const s=document.getElementById('toast-stack');
const t=document.createElement('div');
t.className='toast'+(kind?' '+kind:'');
t.innerHTML=`<div class="toast-title">${title}</div><div>${msg}</div>`;
s.appendChild(t);
setTimeout(()=>{t.style.opacity='0';t.style.transform='translateX(24px)';t.style.transition='all .4s';setTimeout(()=>t.remove(),400)},4800);
}
function render(){
const g=document.getElementById('profiles-grid');
g.innerHTML=PROVIDERS.map((p,i)=>{
const s=state[p.slug];
const dotCls=s.logged===true?'logged':s.running?'running':'offline';
const lbl=s.logged===true?'Session active':s.running?'Chrome running':'Not started';
const lblCls=s.logged===true?'ok':s.running?'warn':'';
const meta=s.cdp?`cdp :${s.cdp}`:s.running?'—':'—';
return `<article class="profile-card" data-slug="${p.slug}">
<div class="pc-top">
<div class="pc-monogram">${p.mono}</div>
<div class="pc-index">${String(i+1).padStart(2,'0')} / 08</div>
</div>
<div class="pc-name">${p.name}</div>
<div class="pc-domain">${p.domain}</div>
<div class="pc-status">
<div class="pc-status-dot ${dotCls}"></div>
<div class="pc-status-label ${lblCls}">${lbl}</div>
<div class="pc-status-meta">${meta}</div>
</div>
<div class="pc-path">/var/lib/wevia-cyber-profiles/${p.slug}</div>
<div class="pc-actions">
<button class="pc-btn primary" onclick="launch('${p.slug}')">Launch</button>
<a class="pc-btn" href="/novnc/vnc.html" target="_blank">noVNC</a>
</div>
</article>`;
}).join('');
const logged=Object.values(state).filter(s=>s.logged===true).length;
const running=Object.values(state).filter(s=>s.running).length;
document.getElementById('stat-logged').textContent=String(logged).padStart(2,'0');
document.getElementById('stat-running').textContent=String(running).padStart(2,'0');
}
async function launch(slug){
const prov=PROVIDERS.find(p=>p.slug===slug);
toast('Launching',`Chrome instance on profile ${prov.name}`);
try{
const r=await fetch('/api/wevia-autowire-trigger.php?action=chrome-launch&profile='+slug);
const d=await r.json();
if(d.ok&&d.result){
state[slug].running=true;
state[slug].cdp=d.result.cdp_port||prov.cdp;
toast('Online',`${prov.name} running · CDP :${state[slug].cdp}`,'success');
render();
setTimeout(()=>window.open('/novnc/vnc.html','_blank'),600);
}else{
toast('Failed',d.err||JSON.stringify(d).slice(0,120),'error');
}
}catch(e){toast('Error',e.message,'error')}
}
async function probeStatus(){
for(const p of PROVIDERS){
try{
const r=await fetch(`http://127.0.0.1:${p.cdp}/json/version`,{signal:AbortSignal.timeout(1500)}).catch(()=>null);
if(r&&r.ok){
state[p.slug].running=true;
state[p.slug].cdp=p.cdp;
}
}catch(e){}
}
render();
}
render();
// probeStatus() would be CORS-blocked from browser, so skip. Status updated on user action.
// Subtle cursor tilt on cards
document.addEventListener('mousemove',e=>{
document.querySelectorAll('.profile-card').forEach(c=>{
const r=c.getBoundingClientRect();
const inside=e.clientX>=r.left&&e.clientX<=r.right&&e.clientY>=r.top&&e.clientY<=r.bottom;
if(inside){
const x=(e.clientX-r.left)/r.width-.5;const y=(e.clientY-r.top)/r.height-.5;
c.style.transform=`translateY(-3px) perspective(800px) rotateX(${-y*2}deg) rotateY(${x*2}deg)`;
}else{c.style.transform=''}
});
},{passive:true});
</script>
</body></html>