From 66c93ee41ef0cd26a305d46dcf05f919fcd62210 Mon Sep 17 00:00:00 2001 From: chrischristiansen-glitch Date: Wed, 10 Jun 2026 22:52:06 +0200 Subject: [PATCH] feat(opax): add MD docs module to sidebar + panel --- static/opax.html | 184 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 10 deletions(-) diff --git a/static/opax.html b/static/opax.html index 1008c61..d30edfc 100644 --- a/static/opax.html +++ b/static/opax.html @@ -218,6 +218,40 @@ .if-btn{font-size:11px;padding:4px 10px;border-radius:6px;background:var(--bg-3);border:1px solid var(--border);color:var(--text-dim);transition:background .14s;white-space:nowrap} .if-btn:hover{background:var(--bg);color:var(--text)} .if-frame{flex:1;border:none;width:100%;height:100%} + + /* MD MODULE */ + .md-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px} + .md-card{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius);padding:20px;display:flex;flex-direction:column;gap:10px;cursor:pointer;transition:border-color .14s,background .14s} + .md-card:hover{border-color:var(--accent);background:rgba(124,92,255,.04)} + .md-hd{display:flex;align-items:center;gap:10px} + .md-icon{font-size:22px;flex-shrink:0} + .md-name{font-size:14px;font-weight:700} + .md-path{font-size:11px;font-family:var(--mono);color:var(--text-faint);margin-top:2px} + .md-desc{font-size:12px;color:var(--text-dim);line-height:1.5} + .md-ft{display:flex;align-items:center;justify-content:space-between;margin-top:4px} + .md-badge{font-size:10px;font-weight:700;padding:2px 8px;border-radius:99px;background:rgba(124,92,255,.15);color:var(--accent)} + .md-badge.auth{background:rgba(62,207,142,.15);color:var(--green)} + .md-badge.append{background:rgba(0,212,168,.15);color:var(--accent-2)} + .md-open-btn{font-size:11px;font-weight:600;padding:5px 12px;border-radius:7px;background:var(--bg-3);border:1px solid var(--border);color:var(--text-dim);transition:background .14s,color .14s} + .md-open-btn:hover{background:var(--accent);color:#fff;border-color:var(--accent)} + + /* inline MD viewer */ + .md-viewer{flex:1;overflow-y:auto;padding:32px 40px;font-size:14px;line-height:1.75;color:var(--text)} + .md-viewer h1{font-size:22px;font-weight:800;margin-bottom:16px;letter-spacing:-0.02em} + .md-viewer h2{font-size:16px;font-weight:700;margin:24px 0 10px;color:var(--text)} + .md-viewer h3{font-size:14px;font-weight:600;margin:18px 0 8px;color:var(--text-dim)} + .md-viewer p{margin-bottom:12px;color:var(--text-dim)} + .md-viewer code{font-family:var(--mono);font-size:12px;background:rgba(255,255,255,.06);padding:2px 6px;border-radius:4px} + .md-viewer pre{background:var(--bg-2);border:1px solid var(--border);padding:14px 16px;border-radius:10px;overflow-x:auto;font-family:var(--mono);font-size:12px;margin:12px 0;line-height:1.6} + .md-viewer table{width:100%;border-collapse:collapse;margin:14px 0;font-size:13px} + .md-viewer th{text-align:left;padding:8px 12px;border-bottom:1px solid var(--border);font-size:11px;text-transform:uppercase;letter-spacing:0.05em;color:var(--text-faint)} + .md-viewer td{padding:9px 12px;border-bottom:1px solid var(--border);color:var(--text-dim)} + .md-viewer tr:last-child td{border-bottom:none} + .md-viewer ul,.md-viewer ol{margin:0 0 12px 20px;color:var(--text-dim)} + .md-viewer li{margin-bottom:4px} + .md-viewer blockquote{border-left:3px solid var(--accent);padding:8px 16px;margin:12px 0;background:rgba(124,92,255,.06);border-radius:0 8px 8px 0;color:var(--text-dim)} + .md-viewer hr{border:none;border-top:1px solid var(--border);margin:20px 0} + .md-viewer-loading{display:flex;align-items:center;justify-content:center;height:200px;color:var(--text-faint);font-family:var(--mono);font-size:13px;gap:10px} @@ -259,6 +293,11 @@ ⌨️ Terminal +
Dokumentasjon
+ +
Chris Christiansen
@@ -416,6 +455,27 @@
+ +
+
+
📄
+
+
MD — Dokumenter
+
Kjerndoks · vauco-saas/OSVauco
+
+
+ + +
+
+
+
+
+ +
+ @@ -426,14 +486,28 @@ const AGENT_URL = '' const USER_ID = 'chris' const STORAGE_KEY = 'jason_history_v2' const SESSION_KEY = 'jason_session_v2' +const GH_RAW = 'https://raw.githubusercontent.com/vauco-saas/OSVauco/main/' +const GH_BLOB = 'https://github.com/vauco-saas/OSVauco/blob/main/' + +const MD_DOCS = [ + { icon:'🏛️', name:'MASTERPLAN', path:'docs/MASTERPLAN.md', desc:'Autoritativ sannhet — vinner alltid ved konflikt', badge:'autoritativ', badgeCls:'auth' }, + { icon:'🗺️', name:'ROADMAP', path:'docs/ROADMAP.md', desc:'Hva som skjer akkurat nå — prioriteringer per sprint', badge:'aktiv', badgeCls:'' }, + { icon:'🤝', name:'HANDOFF', path:'docs/HANDOFF.md', desc:'Siste sesjonsstatus — overskrives hver sesjon', badge:'sesjon', badgeCls:'' }, + { icon:'📏', name:'AGENT RULEBOOK',path:'docs/AGENT_RULEBOOK.md', desc:'Låste regler for alle agenter — R-01 til R-08', badge:'låst', badgeCls:'auth' }, + { icon:'📚', name:'LEARNINGS', path:'docs/LEARNINGS.md', desc:'Append-only lærdom fra alle sesjoner', badge:'append-only', badgeCls:'append' }, + { icon:'🌍', name:'EMMA world.md', path:'docs/gemma/world.md', desc:'Emmas kontekstpakke — leses ved oppstart', badge:'emma', badgeCls:'' }, + { icon:'🏗️', name:'ARCHITECTURE', path:'docs/ARCHITECTURE.md', desc:'Teknisk arkitektur — tjenester, flows, infra', badge:'tech', badgeCls:'' }, + { icon:'🤖', name:'AGENTS', path:'AGENTS.md', desc:'Agent-oversikt — roller, ML-faser, state store', badge:'ml-visjon', badgeCls:'' }, +] const PANEL_META = { - jason: ['Jason', 'Gemini 2.5 Pro · ADK'], - billing: ['CostGuard', 'Token & kostnad · live'], - build: ['Cloud Build', 'Pipeline · propane-will-491900-m5'], - vms: ['VM-er', 'Compute Engine · us-central1-b'], - sites: ['Sites & Moduler', 'Alle Vauco-flater'], - terminal: ['Terminal', 'OPAX agent · Cloud Run'], + jason: ['Jason', 'Gemini 2.5 Pro · ADK'], + billing: ['CostGuard', 'Token & kostnad · live'], + build: ['Cloud Build', 'Pipeline · propane-will-491900-m5'], + vms: ['VM-er', 'Compute Engine · us-central1-b'], + sites: ['Sites & Moduler', 'Alle Vauco-flater'], + terminal: ['Terminal', 'OPAX agent · Cloud Run'], + md: ['MD — Dokumenter', 'Kjerndoks · vauco-saas/OSVauco'], } const SITES_DATA = [ @@ -457,7 +531,6 @@ document.getElementById('sb-session').textContent = 'session: '+SESSION_ID.slice // PANEL SWITCH const PANELS = Object.keys(PANEL_META) function go(name){ - // remove any iframe overlay first document.getElementById('panel-iframe-overlay')?.remove() PANELS.forEach(p=>{ document.getElementById('panel-'+p).classList.remove('active') @@ -472,6 +545,7 @@ function go(name){ if(name==='build') loadBuild() if(name==='sites') renderSites() if(name==='terminal') initTerminal() + if(name==='md') renderMdGrid() } // BUILD STATUS POLL @@ -581,6 +655,94 @@ function openInline(url, name){ document.getElementById('tb-sub').textContent=url } +// MD MODULE +function renderMdGrid(){ + const g=document.getElementById('md-grid') + if(g.children.length) return + g.innerHTML=MD_DOCS.map(d=>` +
+
+ ${d.icon} +
+
${d.name}
+
${d.path}
+
+
+
${d.desc}
+
+ ${d.badge} + +
+
`).join('') +} + +async function openMd(path, name){ + document.getElementById('md-grid-view').style.display='none' + const vv=document.getElementById('md-viewer-view') + vv.style.display='flex' + document.getElementById('md-back-btn').style.display='' + const ghBtn=document.getElementById('md-gh-btn') + ghBtn.href=GH_BLOB+path + ghBtn.style.display='' + document.getElementById('tb-title').textContent='MD · '+name + document.getElementById('tb-sub').textContent=path + const viewer=document.getElementById('md-viewer') + viewer.innerHTML='
Laster '+esc(path)+'...
' + try{ + const raw=await fetch(GH_RAW+path+'?t='+Date.now()).then(r=>{ if(!r.ok) throw new Error('HTTP '+r.status); return r.text() }) + viewer.innerHTML=renderMd(raw) + }catch(e){ + viewer.innerHTML=`
❌ Kunne ikke laste: ${esc(e.message)}
` + } +} + +function mdShowGrid(){ + document.getElementById('md-grid-view').style.display='' + document.getElementById('md-viewer-view').style.display='none' + document.getElementById('md-back-btn').style.display='none' + document.getElementById('md-gh-btn').style.display='none' + document.getElementById('tb-title').textContent='MD — Dokumenter' + document.getElementById('tb-sub').textContent='Kjerndoks · vauco-saas/OSVauco' +} + +function renderMd(text){ + let s=esc(text) + // code blocks first + s=s.replace(/```[^\n]*\n([\s\S]*?)```/g,'
$1
') + s=s.replace(/`([^`]+)`/g,'$1') + // headings + s=s.replace(/^### (.+)$/gm,'

$1

') + s=s.replace(/^## (.+)$/gm,'

$1

') + s=s.replace(/^# (.+)$/gm,'

$1

') + // bold + s=s.replace(/\*\*(.+?)\*\*/g,'$1') + // hr + s=s.replace(/^---$/gm,'
') + // blockquote + s=s.replace(/^> (.+)$/gm,'
$1
') + // tables (simple) + s=s.replace(/((?:^\|.+\|\n)+)/gm, tbl=>{ + const rows=tbl.trim().split('\n').filter(r=>!/^\|[-| :]+\|$/.test(r)) + if(!rows.length) return tbl + let out='' + rows.forEach((r,i)=>{ + const cells=r.split('|').slice(1,-1) + out+=i===0?'':'' + cells.forEach(c=>{ out+=i===0?``:`` }) + out+=i===0?'':'' + }) + out+='
${c.trim()}${c.trim()}
' + return out + }) + // lists + s=s.replace(/^[-*] (.+)$/gm,'
  • $1
  • ') + s=s.replace(/(
  • .*<\/li>)/s, m=>'') + s=s.replace(/^\d+\. (.+)$/gm,'
  • $1
  • ') + // paragraphs — wrap loose lines + s=s.replace(/^(?!<[htublp|]).+$/gm, line=>line.trim()?`

    ${line}

    `:'') + return s +} + // TERMINAL let termInited=false function initTerminal(){ @@ -614,10 +776,12 @@ async function termKey(e){ try{ const d=await fetch('/health').then(r=>r.json()); tprint(JSON.stringify(d,null,2),'ok') }catch(e){ tprint('Feil: '+e.message,'err') } break case 'billing': - try{ const d=await fetch('/billing/summary').then(r=>r.json()); tprint(JSON.stringify(d,null,2),'ok') }catch(e){ tprint('Feil: '+e.message,'err') } + try{ const d=await fetch('/billing/summary').then(r=>r.json()); tprint(JSON.stringify(d,null,2),'ok') } + catch(e){ tprint('Feil: '+e.message,'err') } break case 'build': - try{ const d=await fetch('/opax/build-status').then(r=>r.json()); tprint(JSON.stringify(d,null,2),'ok') }catch(e){ tprint('Feil: '+e.message,'err') } + try{ const d=await fetch('/opax/build-status').then(r=>r.json()); tprint(JSON.stringify(d,null,2),'ok') } + catch(e){ tprint('Feil: '+e.message,'err') } break default: tprint('Ukjent kommando: '+cmd+' (skriv «help»)','err') } @@ -625,7 +789,7 @@ async function termKey(e){ function confirmVmStop(){ if(!confirm('⚠️ Stop osvauco-dev-vm? Du mister SSH-tilgang til den startes igjen.')) return tprint('→ Stopper VM via: bash scripts/stop-osvauco-dev-vm.sh','info') - switchPanel('terminal');go('terminal') + go('terminal') } // JASON CHAT