Files
waggle-os/docs/design_handoff_waggle_app/design-files/screens/onboarding.html
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

261 lines
19 KiB
HTML

<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Waggle · Onboarding</title>
<script>document.documentElement.classList.add('js');</script>
<link rel="stylesheet" href="../styles/waggle.css">
<style>
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
.seg button { font-family: var(--sans); font-size: 12px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 11px; border-radius: 7px; transition: .14s; }
.seg button.on { background: var(--honey); color: #1a1407; }
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
.stage { flex: 1; min-height: 0; position: relative; overflow: hidden; }
.stage .comb { position: absolute; inset: 0; opacity: .5; pointer-events: none; }
/* progress */
.prog { position: absolute; top: 18px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 8px; z-index: 5; }
.prog .step { display:flex; align-items:center; gap: 8px; }
.prog .pd { width: 26px; height: 4px; border-radius: 3px; background: var(--surface-3); transition:.3s; }
.prog .pd.done { background: var(--honey); } .prog .pd.cur { background: var(--honey-bright); }
.screen { position: absolute; inset: 0; display: none; align-items: flex-start; justify-content: center; padding: 92px 32px 96px; overflow: auto; }
.screen.on { display: flex; }
.card { width: 100%; max-width: 600px; text-align: center; position: relative; }
.eyebrow { font-family: var(--mono); font-size: 11px; letter-spacing:.14em; text-transform:uppercase; color: var(--honey); margin-bottom: 14px; }
.card h1 { font-size: clamp(28px, 4vw, 40px); font-weight: 650; letter-spacing:-0.02em; line-height:1.06; margin: 0 0 14px; text-wrap:balance; }
.card h1 em { font-style: normal; color: var(--honey); }
.card .lede { font-size: 16px; color: var(--text-2); line-height: 1.55; margin: 0 auto 30px; max-width: 46ch; }
.mk { width: 60px; height: 66px; margin: 0 auto 24px; display:grid; place-items:center; font-weight:800; font-size:24px; color:#1a1407; background: linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); box-shadow: var(--honey-glow); }
.chips { display:flex; flex-wrap:wrap; gap: 10px; justify-content:center; margin-bottom: 16px; }
.chip { font-size: 14px; font-weight: 550; padding: 10px 16px; border-radius: 999px; border:1px solid var(--line-strong); background: var(--surface); color: var(--text-2); cursor:pointer; transition:.14s; }
.chip:hover { border-color: var(--honey-line); color: var(--text); }
.chip.sel { background: var(--honey); color:#1a1407; border-color: var(--honey); }
.flabel { font-size: 12.5px; color: var(--text-dim); margin: 22px 0 12px; font-family:var(--mono); letter-spacing:.08em; text-transform:uppercase; }
.field { width:100%; max-width: 360px; margin: 0 auto 8px; padding: 12px 16px; border-radius: 11px; border:1px solid var(--line); background: var(--surface); color: var(--text); font-family:var(--sans); font-size:15px; outline:none; text-align:center; }
.field:focus { border-color: var(--honey-line); }
/* import cards */
.opts { display:grid; grid-template-columns: repeat(2,1fr); gap: 12px; max-width: 460px; margin: 0 auto; }
.opt { padding: 18px; border-radius: var(--r-lg); border:1px solid var(--line-strong); background: var(--surface); cursor:pointer; transition:.15s; text-align:left; display:flex; align-items:center; gap:13px; }
.opt:hover { border-color: var(--honey-line); } .opt.sel { border-color: var(--honey); background: var(--honey-wash); }
.opt .oi { width:34px; height:38px; flex:none; display:grid; place-items:center; font-family:var(--mono); font-weight:700; font-size:12px; color:var(--text); background:var(--surface-2); border:1px solid var(--line); }
.opt b { font-size: 14px; font-weight: 650; display:block; } .opt small { font-size: 11.5px; color: var(--text-muted); }
.reassure { margin-top: 18px; font-size: 12.5px; color: var(--text-dim); display:inline-flex; align-items:center; gap:8px; }
.reassure svg { width:14px; height:14px; stroke: var(--healthy); fill:none; stroke-width:1.8; }
/* template cards */
.tpls { display:grid; grid-template-columns: repeat(3,1fr); gap: 11px; max-width: 540px; margin: 0 auto; }
.tpl { padding: 16px 12px; border-radius: var(--r); border:1px solid var(--line-strong); background: var(--surface); cursor:pointer; transition:.15s; }
.tpl:hover { border-color: var(--honey-line); } .tpl.sel { border-color: var(--honey); background: var(--honey-wash); }
.tpl .ti { width: 32px; height: 36px; margin: 0 auto 9px; display:grid; place-items:center; }
.tpl .ti svg { width:18px; height:18px; stroke: var(--honey); fill:none; stroke-width:1.7; }
.tpl b { font-size: 13px; font-weight: 600; display:block; } .tpl small { font-size: 10.5px; color: var(--text-dim); }
/* first task */
.ask { display:flex; align-items:center; gap:10px; max-width: 480px; margin: 0 auto 16px; padding: 6px 6px 6px 18px; border-radius: 999px; border:1px solid var(--line); background: var(--surface); }
.ask:focus-within { border-color: var(--honey-line); box-shadow: var(--honey-glow); }
.ask input { flex:1; border:0; background:transparent; color:var(--text); font-family:var(--sans); font-size:15px; outline:none; text-align:left; }
.ask .go { width:40px;height:40px;border-radius:999px;border:0;background:var(--honey);color:#1a1407;font-size:17px;cursor:pointer;flex:none; }
.suggest { display:flex; flex-direction:column; gap:8px; max-width: 480px; margin: 0 auto; }
.sg { text-align:left; padding: 11px 15px; border-radius: 10px; border:1px solid var(--line-soft); background: var(--surface); color: var(--text-2); font-size:13.5px; cursor:pointer; transition:.14s; }
.sg:hover { border-color: var(--honey-line); color: var(--text); }
/* model gate */
.mtabs { display:inline-flex; padding:3px; gap:3px; border-radius:10px; background:var(--surface-2); border:1px solid var(--line-soft); margin-bottom:20px; }
.mtab { font-size:13px; font-weight:600; cursor:pointer; padding:8px 16px; border-radius:7px; color:var(--text-muted); }
.mtab.sel { background:var(--honey); color:#1a1407; }
.keyfield { display:flex; align-items:center; gap:10px; max-width:420px; margin:0 auto 8px; padding:6px 8px 6px 16px; border-radius:11px; border:1px solid var(--healthy); background:var(--surface); }
.keyfield input { flex:1; border:0; background:transparent; color:var(--text); font-family:var(--mono); font-size:13.5px; outline:none; text-align:left; }
.keyfield .valid { font-size:12px; font-weight:600; color:var(--healthy); white-space:nowrap; padding-right:6px; }
.mpane.hidden { display:none; }
/* nav */
.nav { position: absolute; bottom: 0; left:0; right:0; display:flex; align-items:center; justify-content:space-between; padding: 18px 32px; border-top: 1px solid var(--line-soft); background: color-mix(in srgb,var(--bg) 80%, transparent); backdrop-filter: blur(8px); }
.nav .skip { font-size: 13px; color: var(--text-dim); cursor:pointer; } .nav .skip:hover { color: var(--text-2); }
.nav .rgt { display:flex; gap: 10px; align-items:center; }
.btn { font-family:var(--sans); font-size: 14px; font-weight: 650; padding: 11px 20px; border-radius: 11px; cursor:pointer; border:1px solid transparent; }
.btn.back { background: transparent; color: var(--text-muted); } .btn.back:hover { color: var(--text); }
.btn.next { background: var(--honey); color:#1a1407; } .btn.next:hover { background: var(--honey-bright); }
@media (max-width: 620px){ .opts, .tpls { grid-template-columns: 1fr 1fr; } }
</style>
</head>
<body>
<div class="controls">
<span class="lab">Onboarding · jump to step</span>
<div class="seg" id="seg">
<button class="on" data-s="0">1</button><button data-s="1">2</button><button data-s="2">3</button><button data-s="3">4</button><button data-s="4">5</button><button data-s="5">6</button>
</div>
<span class="vlabel" id="vlabel"><b>Welcome</b> — first run, full-screen takeover</span>
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme"></button></div>
</div>
<div class="stage">
<div class="comb"></div>
<div class="prog" id="prog"></div>
<!-- 1 welcome -->
<div class="screen on" data-step="0">
<div class="card">
<div class="mk hex">W</div>
<h1>Welcome to Waggle.<br>The workspace that <em>remembers.</em></h1>
<p class="lede">In two minutes we'll set up a workspace that knows you and your work — so you never start from a blank box again. Everything stays on your machine.</p>
<div class="chips"><span class="chip sel" onclick="next()">Let's set it up →</span></div>
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg>Local-first · no account needed to start</div>
</div>
</div>
<!-- 2 about you -->
<div class="screen" data-step="1">
<div class="card">
<div class="eyebrow">Step 2 · about you</div>
<h1>A little about <em>you.</em></h1>
<p class="lede">This shapes how Waggle works for you — your personas, suggestions, and defaults. You can change any of it later.</p>
<input class="field" placeholder="Your name" value="Mara">
<div class="flabel">What do you do most?</div>
<div class="chips" data-single>
<span class="chip">Research</span><span class="chip sel">Strategy / exec</span><span class="chip">Engineering</span>
<span class="chip">Writing</span><span class="chip">Sales</span><span class="chip">Legal</span><span class="chip">Finance</span>
</div>
<div class="flabel">Working...</div>
<div class="chips" data-single>
<span class="chip sel">Solo</span><span class="chip">Small team</span><span class="chip">Larger org</span>
</div>
</div>
</div>
<!-- 3 give it a brain (model gate) -->
<div class="screen" data-step="2">
<div class="card">
<div class="eyebrow">Step 3 · the one requirement</div>
<h1>Give it a <em>brain.</em></h1>
<p class="lede">Waggle is model-agnostic — but it needs at least one to think with. Bring an API key, or run a model locally. You can add more and set up failover anytime.</p>
<div class="mtabs" id="mtabs"><span class="mtab sel" data-m="key">Use an API key</span><span class="mtab" data-m="local">Run it locally</span></div>
<div class="mpane" data-m="key">
<div class="chips" data-single style="margin-bottom:14px"><span class="chip sel">Anthropic</span><span class="chip">OpenAI</span><span class="chip">Google</span><span class="chip">Groq</span></div>
<div class="keyfield"><input placeholder="sk-ant-… paste your key" value="sk-ant-api03-••••••••••3a9f"><span class="valid">✓ valid</span></div>
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg>Encrypted in your local vault — never shown to a model or sent anywhere</div>
</div>
<div class="mpane hidden" data-m="local">
<div class="opts" style="max-width:460px">
<div class="opt sel"><div class="oi">QW</div><div><b>Qwen 2.5 7B</b><small>detected · Ollama · running</small></div></div>
<div class="opt"><div class="oi">L3</div><div><b>Llama 3.2</b><small>pull · ~2 GB</small></div></div>
</div>
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></svg>100% on your machine — no key, no cloud, no cost</div>
</div>
</div>
</div>
<!-- 4 import -->
<div class="screen" data-step="3">
<div class="card">
<div class="eyebrow">Step 4 · bring your history</div>
<h1>Start with what you <em>already have.</em></h1>
<p class="lede">Import past conversations and Waggle learns you on day one. Or start fresh — it learns fast either way.</p>
<div class="opts">
<div class="opt sel"><div class="oi">CG</div><div><b>ChatGPT</b><small>export → import</small></div></div>
<div class="opt"><div class="oi">Cl</div><div><b>Claude</b><small>export → import</small></div></div>
<div class="opt"><div class="oi">Cu</div><div><b>Cursor</b><small>history</small></div></div>
<div class="opt"><div class="oi">+</div><div><b>Start fresh</b><small>learns as you go</small></div></div>
</div>
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg>Imported on your machine — it never leaves</div>
</div>
</div>
<!-- 5 template -->
<div class="screen" data-step="4">
<div class="card">
<div class="eyebrow">Step 5 · first workspace</div>
<h1>Pick a <em>starting point.</em></h1>
<p class="lede">A template seeds the right persona, connectors, and a few starter prompts. One click and you're in.</p>
<div class="tpls" id="tpls"></div>
</div>
</div>
<!-- 6 first task -->
<div class="screen" data-step="5">
<div class="card">
<div class="eyebrow">Step 6 · your first move</div>
<h1>What should we <em>start with?</em></h1>
<p class="lede">Type the first thing you'd like help with, or pick one — your workspace opens straight into it.</p>
<div class="ask"><input placeholder="e.g. “Map our top 5 competitors and where we win”" value=""><button class="go"></button></div>
<div class="suggest" id="suggest"></div>
</div>
</div>
<div class="nav">
<span class="skip" id="skip">Skip setup</span>
<div class="rgt">
<button class="btn back" id="back" style="visibility:hidden">← Back</button>
<button class="btn next" id="nextb">Continue →</button>
</div>
</div>
</div>
<script>
const root = document.documentElement, tbtn = document.getElementById('tbtn');
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
const STEPS = 6;
const labels = ['<b>Welcome</b> — first run, full-screen takeover','<b>About you</b> — role &amp; team shape your defaults','<b>Give it a brain</b> — one model required (key or local)','<b>Import</b> — start from your history, locally','<b>Template</b> — seed persona + connectors','<b>First task</b> — open straight into the work'];
let step = 0;
const tplData = [
{ ic:'<path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/>', n:'Research', s:'analyst' },
{ ic:'<path d="m12 3 2.5 6 6.5.5-5 4.2 1.6 6.3L12 16.8 6 20l1.6-6.3-5-4.2 6.5-.5z"/>', n:'Strategy', s:'consultant', sel:true },
{ ic:'<rect x="4" y="4" width="16" height="16" rx="3"/><path d="M9 9h6v6H9z"/>', n:'Engineering', s:'coder' },
{ ic:'<path d="m22 2-7 20-4-9-9-4Z"/>', n:'Sales', s:'sales-rep' },
{ ic:'<path d="M4 6h16M4 12h12M4 18h8"/>', n:'Writing', s:'writer' },
{ ic:'<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>', n:'Custom', s:'general' },
];
document.getElementById('tpls').innerHTML = tplData.map(t=>`<div class="tpl ${t.sel?'sel':''}"><div class="ti"><svg viewBox="0 0 24 24">${t.ic}</svg></div><b>${t.n}</b><small>${t.s}</small></div>`).join('');
document.getElementById('suggest').innerHTML = ['Map our top 5 competitors and where we win','Draft the Q2 board narrative from this week\u2019s work','Summarize what changed in the market this month'].map(s=>`<div class="sg">${s}</div>`).join('');
// single-select chips & cards
document.querySelectorAll('[data-single]').forEach(grp => grp.addEventListener('click', e => { const c=e.target.closest('.chip'); if(!c)return; grp.querySelectorAll('.chip').forEach(x=>x.classList.remove('sel')); c.classList.add('sel'); }));
['opts','tpls'].forEach(id => { const el=document.getElementById(id)||document.querySelector('.'+id); });
document.querySelector('.opts').addEventListener('click', e=>{const o=e.target.closest('.opt');if(!o)return;document.querySelectorAll('.opt').forEach(x=>x.classList.remove('sel'));o.classList.add('sel');});
document.getElementById('tpls').addEventListener('click', e=>{const t=e.target.closest('.tpl');if(!t)return;document.querySelectorAll('.tpl').forEach(x=>x.classList.remove('sel'));t.classList.add('sel');});
document.getElementById('suggest').addEventListener('click', e=>{const s=e.target.closest('.sg');if(s)document.querySelector('[data-step="5"] .ask input').value=s.textContent;});
// model step: tab switch + provider/local select
const mtabs = document.getElementById('mtabs');
mtabs.addEventListener('click', e => { const t=e.target.closest('.mtab'); if(!t)return; mtabs.querySelectorAll('.mtab').forEach(x=>x.classList.toggle('sel',x===t)); document.querySelectorAll('.mpane').forEach(p=>p.classList.toggle('hidden', p.dataset.m!==t.dataset.m)); });
document.querySelectorAll('.mpane .opts').forEach(grp => grp.addEventListener('click', e=>{const o=e.target.closest('.opt');if(!o)return;grp.querySelectorAll('.opt').forEach(x=>x.classList.remove('sel'));o.classList.add('sel');}));
function renderProg(){ document.getElementById('prog').innerHTML = Array.from({length:STEPS},(_,i)=>`<span class="pd ${i<step?'done':i===step?'cur':''}"></span>`).join(''); }
function go(s){
step = Math.max(0, Math.min(STEPS-1, s));
document.querySelectorAll('.screen').forEach(el => el.classList.toggle('on', +el.dataset.step===step));
document.querySelectorAll('#seg button').forEach(b => b.classList.toggle('on', +b.dataset.s===step));
document.getElementById('vlabel').innerHTML = labels[step];
document.getElementById('back').style.visibility = step===0 ? 'hidden':'visible';
document.getElementById('nextb').textContent = step===STEPS-1 ? 'Enter Waggle →' : 'Continue →';
renderProg();
}
function next(){ go(step+1); }
document.getElementById('nextb').onclick = () => { if(step===STEPS-1){ document.getElementById('nextb').textContent='Opening your workspace…'; } else next(); };
document.getElementById('back').onclick = () => go(step-1);
document.getElementById('skip').onclick = () => go(STEPS-1);
document.getElementById('seg').addEventListener('click', e => { const b=e.target.closest('button'); if(b) go(+b.dataset.s); });
go(0);
</script>
</body>
</html>