AlphaX:Admin Control Panel

From AlphaX Wiki
Revision as of 01:30, 21 April 2026 by Admin (talk | contribs) (Create Admin Control Panel with live API-powered article table (words, category, size, revisions, watchers, dates, status))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

<style>

  1. axcp-root{font-family:system-ui,-apple-system,sans-serif;background:#0D0D0D;color:#fff;padding:0;margin:0 -10px;}

.axcp-header{background:#1A1A1A;border-bottom:1px solid #2E2E2E;padding:22px 28px 18px;} .axcp-title{font-size:22px;font-weight:700;color:#fff;margin-bottom:4px;} .axcp-subtitle{font-size:12px;color:#666;text-transform:uppercase;letter-spacing:.1em;} .axcp-stats-row{display:flex;gap:12px;margin:16px 0 0;} .axcp-stat{background:#0D0D0D;border:1px solid #2E2E2E;border-radius:12px;padding:12px 18px;flex:1;} .axcp-stat-val{font-size:24px;font-weight:700;color:#FF6600;} .axcp-stat-label{font-size:11px;color:#666;text-transform:uppercase;letter-spacing:.08em;margin-top:2px;} .axcp-controls{display:flex;gap:10px;padding:16px 28px;background:#0D0D0D;border-bottom:1px solid #2E2E2E;flex-wrap:wrap;align-items:center;} .axcp-search{flex:1;min-width:200px;background:#1A1A1A;border:1px solid #2E2E2E;border-radius:8px;padding:9px 14px;color:#fff;font-size:14px;outline:none;} .axcp-search:focus{border-color:rgba(255,102,0,.5);} .axcp-select{background:#1A1A1A;border:1px solid #2E2E2E;border-radius:8px;padding:9px 14px;color:#fff;font-size:13px;outline:none;cursor:pointer;} .axcp-select:focus{border-color:rgba(255,102,0,.5);} .axcp-badge-count{background:rgba(255,102,0,.12);border:1px solid rgba(255,102,0,.3);color:#FF6600;border-radius:6px;padding:3px 10px;font-size:12px;font-weight:600;} .axcp-table-wrap{overflow-x:auto;padding:0 28px 28px;} table.axcp-table{width:100%;border-collapse:collapse;margin-top:16px;font-size:13px;} table.axcp-table th{background:#111;color:#666;text-transform:uppercase;letter-spacing:.08em;font-size:11px;font-weight:600;padding:10px 12px;border-bottom:1px solid #2E2E2E;cursor:pointer;white-space:nowrap;user-select:none;} table.axcp-table th:hover{color:#FF6600;} table.axcp-table th.sorted-asc::after{content:" ↑";color:#FF6600;} table.axcp-table th.sorted-desc::after{content:" ↓";color:#FF6600;} table.axcp-table td{padding:9px 12px;border-bottom:1px solid rgba(255,255,255,.04);vertical-align:middle;color:#ccc;} table.axcp-table tr:hover td{background:rgba(255,102,0,.04);} table.axcp-table tr:last-child td{border-bottom:none;} .axcp-title-link{color:#fff;text-decoration:none;font-weight:500;} .axcp-title-link:hover{color:#FF6600;} .axcp-cat-badge{display:inline-block;padding:2px 8px;border-radius:6px;font-size:11px;font-weight:600;white-space:nowrap;} .axcp-status{display:inline-block;padding:2px 8px;border-radius:6px;font-size:11px;font-weight:600;} .status-stub{background:rgba(255,60,60,.15);color:#ff6b6b;border:1px solid rgba(255,60,60,.3);} .status-short{background:rgba(255,166,0,.15);color:#ffa600;border:1px solid rgba(255,166,0,.3);} .status-medium{background:rgba(61,220,132,.15);color:#3ddc84;border:1px solid rgba(61,220,132,.3);} .status-long{background:rgba(100,160,255,.15);color:#64a0ff;border:1px solid rgba(100,160,255,.3);} .axcp-bar-wrap{background:#1A1A1A;border-radius:4px;height:6px;width:80px;overflow:hidden;display:inline-block;vertical-align:middle;margin-left:6px;} .axcp-bar{height:6px;border-radius:4px;background:linear-gradient(to right,#FF6600,#FF8533);} .axcp-loading{text-align:center;padding:60px;color:#666;font-size:15px;} .axcp-error{text-align:center;padding:40px;color:#ff6b6b;} .axcp-num{text-align:right;font-variant-numeric:tabular-nums;color:#999;} .axcp-refresh{background:linear-gradient(135deg,#FF6600,#FF8533);border:none;border-radius:8px;color:#fff;padding:9px 18px;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;} .axcp-refresh:hover{opacity:.85;} </style> <script> (function(){

 var root=document.getElementById('axcp-root');
 // Category color map
 var CAT_COLORS={
   'Sexual Health':'rgba(255,100,100,.15)|#ff7a7a',
   'Dating, Sex & Relationships':'rgba(255,182,100,.15)|#FFB664',
   'Kink & BDSM':'rgba(180,100,255,.15)|#c47aff',
   'Culture, History & Politics':'rgba(100,160,255,.15)|#64a0ff',
   'Fashion & Visual Signaling':'rgba(255,220,100,.15)|#ffd664',
   'Community & Identity':'rgba(61,220,132,.15)|#3ddc84',
   'Drugs, Party Culture & Harm Reduction':'rgba(255,120,50,.15)|#ff7832',
   'Life Planning':'rgba(100,200,255,.15)|#64c8ff'
 };
 function catStyle(cat){
   var s=CAT_COLORS[cat]||'rgba(150,150,150,.15)|#888';
   var p=s.split('|');
   return 'background:'+p[0]+';color:'+p[1]+';border:1px solid '+p[1].replace(')',', .3)').replace('rgb','rgba')+';';
 }
 function wordStatus(w){
   if(w<200)return['stub','Stub'];
   if(w<600)return['short','Short'];
   if(w<1500)return['medium','Medium'];
   return['long','Long'];
 }
 function fmtDate(iso){
   if(!iso)return'—';
   var d=new Date(iso);
   return d.toLocaleDateString('en-GB',{day:'2-digit',month:'short',year:'numeric'});
 }
 function fmtSize(bytes){
   if(!bytes)return'—';
   return(bytes/1024).toFixed(1)+' KB';
 }
 function escHtml(s){
   return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
 }
 var allData=[];
 var sortCol='title';
 var sortDir=1;
 var filterText=;
 var filterCat=;
 function render(data){
   var filtered=data.filter(function(r){
     var matchText=!filterText||r.title.toLowerCase().indexOf(filterText)>=0||(r.cat||).toLowerCase().indexOf(filterText)>=0;
     var matchCat=!filterCat||r.cat===filterCat;
     return matchText&&matchCat;
   });
   filtered.sort(function(a,b){
     var av=a[sortCol]||,bv=b[sortCol]||;
     if(typeof av==='number'&&typeof bv==='number')return sortDir*(av-bv);
     return sortDir*String(av).localeCompare(String(bv));
   });
   var maxWords=Math.max.apply(null,filtered.map(function(r){return r.words||0;}));
   // Stats
   var totalWords=filtered.reduce(function(s,r){return s+(r.words||0);},0);
   var avgWords=filtered.length?Math.round(totalWords/filtered.length):0;
   var totalRevs=filtered.reduce(function(s,r){return s+(r.revisions||0);},0);
   // Build cats for dropdown
   var cats={};
   data.forEach(function(r){if(r.cat)cats[r.cat]=1;});
   var catList=Object.keys(cats).sort();
   var html=;
   // Header

html+='

'; html+='
⚙ Admin Control Panel
'; html+='
AlphaX Wiki — Article Database — Live Data
'; html+='
'; html+='
'+filtered.length+'
Articles
'; html+='
'+avgWords.toLocaleString()+'
Avg Words
'; html+='
'+totalWords.toLocaleString()+'
Total Words
'; html+='
'+totalRevs.toLocaleString()+'
Total Revisions
'; html+='
'+catList.length+'
Categories
'; html+='

';

   // Controls

html+='

';
   html+='<input class="axcp-search" id="axcp-search" type="text" placeholder="🔍 Search articles..." value="'+escHtml(filterText)+'">';
   html+='<select class="axcp-select" id="axcp-cat-filter"><option value="">All Categories</option>';
   catList.forEach(function(c){html+='<option value="'+escHtml(c)+'"'+(filterCat===c?' selected':)+'>'+escHtml(c)+'</option>';});
   html+='</select>';
   html+=''+filtered.length+' articles';
   html+='<button class="axcp-refresh" id="axcp-reload">↻ Refresh Data</button>';
html+='

';

   // Table

html+='

'; html+='<thead>'; var cols=[ {key:'title',label:'Article'}, {key:'cat',label:'Category'}, {key:'subcat',label:'Subcategory'}, {key:'words',label:'Words'}, {key:'size',label:'Size'}, {key:'status',label:'Status'}, {key:'created',label:'Created'}, {key:'touched',label:'Last Edited'}, {key:'revisions',label:'Revisions'}, {key:'watchers',label:'Watchers'}, {key:'links',label:'Inbound Links'} ]; cols.forEach(function(c){ var cls=sortCol===c.key?(sortDir===1?'sorted-asc':'sorted-desc'):; html+='';
   });
html+='</thead><tbody>'; if(filtered.length===0){ html+='';
   }
   filtered.forEach(function(r){
     var st=wordStatus(r.words||0);
     var barW=maxWords>0?Math.round(((r.words||0)/maxWords)*80):0;
     var cs=catStyle(r.cat||);
html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; html+=''; }); html+='</tbody>
'+c.label+'
No articles match your filters.
<a class="axcp-title-link" href="/wiki/'+encodeURIComponent((r.title||).replace(/ /g,'_'))+'" target="_blank">'+escHtml(r.title||)+'</a>'+(r.cat?''+escHtml(r.cat)+'':'')+''+escHtml(r.subcat||'—')+''+((r.words||0).toLocaleString())+''+fmtSize(r.size)+''+st[1]+''+fmtDate(r.created)+''+fmtDate(r.touched)+'10?'#FF6600':'#777')+'">'+((r.revisions||0))+'0?'#3ddc84':'#444')+'">'+(r.watchers!=null?(r.watchers>0?'👁 '+r.watchers:'0'):'—')+''+((r.links||0))+'

';

   root.innerHTML=html;
   // Bind events
   document.getElementById('axcp-search').addEventListener('input',function(){filterText=this.value.toLowerCase();render(allData);});
   document.getElementById('axcp-cat-filter').addEventListener('change',function(){filterCat=this.value;render(allData);});
   document.getElementById('axcp-reload').addEventListener('click',function(){loadData();});
   document.querySelectorAll('table.axcp-table th').forEach(function(th){
     th.addEventListener('click',function(){
       var col=this.getAttribute('data-col');
       if(sortCol===col){sortDir*=-1;}else{sortCol=col;sortDir=1;}
       render(allData);
     });
   });
 }
 async function loadData(){

root.innerHTML='

⚙ Loading article data from API…

';

   try{
     // Step 1: get all article page IDs + basic info
     var pages=[];
     var apcontinue=null;
     do{
       var url='/api.php?action=query&list=allpages&apnamespace=0&aplimit=500&format=json';
       if(apcontinue)url+='&apcontinue='+encodeURIComponent(apcontinue);
       var r=await fetch(url);
       var d=await r.json();
       pages=pages.concat(d.query.allpages);
       apcontinue=d.continue?d.continue.apcontinue:null;
     }while(apcontinue);
     // Step 2: batch fetch page props (size, touched, lastrevid, categories) in chunks of 50
     var map={};
     pages.forEach(function(p){map[p.pageid]={title:p.title,cat:,subcat:,words:0,size:0,created:,touched:,revisions:0,watchers:null,links:0};});
     var ids=pages.map(function(p){return p.pageid;});
     for(var i=0;i<ids.length;i+=50){
       var chunk=ids.slice(i,i+50).join('|');
       var r2=await fetch('/api.php?action=query&pageids='+chunk+'&prop=info|categories|revisions&inprop=watchers&rvprop=size|timestamp&rvdir=newer&rvlimit=1&cllimit=10&format=json');
       var d2=await r2.json();
       Object.keys(d2.query.pages).forEach(function(pid){
         var pg=d2.query.pages[pid];
         if(!map[pid])return;
         map[pid].size=pg.length||0;
         map[pid].touched=pg.touched||;
         map[pid].watchers=pg.watchers!=null?pg.watchers:null;
         // categories
         if(pg.categories){
           pg.categories.forEach(function(c){
             var cn=c.title.replace('Category:',);
             var knownCats=['Sexual Health','Dating, Sex & Relationships','Kink & BDSM','Culture, History & Politics','Fashion & Visual Signaling','Community & Identity','Drugs, Party Culture & Harm Reduction','Life Planning'];
             if(knownCats.indexOf(cn)>=0){
               if(!map[pid].cat)map[pid].cat=cn;
             }else if(!cn.startsWith('Pages') && !cn.startsWith('Articles')){
               if(!map[pid].subcat)map[pid].subcat=cn;
             }
           });
         }
         // creation date from first revision
         if(pg.revisions&&pg.revisions[0])map[pid].created=pg.revisions[0].timestamp||;
       });
     }
     // Step 3: get revision counts and word counts via separate calls
     for(var j=0;j<ids.length;j+=50){
       var chunk2=ids.slice(j,j+50).join('|');
       // revision count via revisions prop count
       var r3=await fetch('/api.php?action=query&pageids='+chunk2+'&prop=revisions&rvprop=ids&rvlimit=max&format=json');
       var d3=await r3.json();
       Object.keys(d3.query.pages).forEach(function(pid){
         var pg=d3.query.pages[pid];
         if(!map[pid])return;
         map[pid].revisions=(pg.revisions||[]).length;
       });
     }
     // Step 4: get wikitext word counts (batch extracts)
     for(var k=0;k<ids.length;k+=20){
       var chunk3=ids.slice(k,k+20).join('|');
       var r4=await fetch('/api.php?action=query&pageids='+chunk3+'&prop=revisions&rvprop=content&rvslots=main&format=json');
       var d4=await r4.json();
       Object.keys(d4.query.pages).forEach(function(pid){
         var pg=d4.query.pages[pid];
         if(!map[pid]||!pg.revisions||!pg.revisions[0])return;
         var content=pg.revisions[0].slots?pg.revisions[0].slots.main['*']:(pg.revisions[0]['*']||);
         // Strip wiki markup
         var clean=content
           .replace(//g,)
           .replace(/<[^>]+>/g,' ')
           .replace(/[[File:[^]]+]]/gi,)
           .replace(/[[([^]|]+|)?([^]]+)]]/g,'$2')
           .replace(/{{[^}]+}}/g,)
           .replace(/={2,}[^=]+=={2,}/g,' ')
           .replace(/[*#:;|!]/g,' ')
           .replace(/https?://S+/g,)
           .replace(/s+/g,' ').trim();
         map[pid].words=clean?clean.split(/s+/).filter(function(w){return w.length>0;}).length:0;
       });
     }
     // Step 5: inbound links count
     for(var l=0;l<ids.length;l+=50){
       var chunk4=ids.slice(l,l+50).join('|');
       var r5=await fetch('/api.php?action=query&pageids='+chunk4+'&prop=linkshere&lhnamespace=0&lhlimit=max&format=json');
       var d5=await r5.json();
       Object.keys(d5.query.pages).forEach(function(pid){
         var pg=d5.query.pages[pid];
         if(!map[pid])return;
         map[pid].links=(pg.linkshere||[]).length;
       });
     }
     allData=Object.values(map);
     render(allData);
   }catch(e){

root.innerHTML='

⚠ Error loading data: '+e.message+'

';

   }
 }
 loadData();

})(); </script>