put it on live

This commit is contained in:
2026-03-29 17:22:14 -05:00
committed by GitHub
commit b3d92b5f6e
8 changed files with 357 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
MIT License
Copyright (c) 2026 miles
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+3
View File
@@ -0,0 +1,3 @@
# gd-list
my gd list
+143
View File
@@ -0,0 +1,143 @@
// Lightweight multi-page handler for GD Demand List
(function(){
function qs(id){return document.getElementById(id)}
const page = document.body.dataset.page;
// Storage helpers
function read(key, fallback){
try{const v = localStorage.getItem(key); return v?JSON.parse(v):fallback}
catch(e){return fallback}
}
function write(key, val){localStorage.setItem(key,JSON.stringify(val))}
// Players page
if(page==='players'){
const form = qs('player-form'); const nameIn = qs('player-name'); const list = qs('players');
let players = read('gd_players',[]);
function render(){list.innerHTML=''; players.forEach((p,idx)=>{
const li=document.createElement('li'); li.innerHTML=`<span><span class="name">${escapeHtml(p.name)}</span> <span class="muted">(${p.id})</span></span>`;
const actions=document.createElement('div'); actions.className='actions';
const edit=document.createElement('button'); edit.textContent='Edit'; edit.onclick=()=>{const nv=prompt('Edit name',p.name); if(nv){players[idx].name=nv; write('gd_players',players); render()}};
const del=document.createElement('button'); del.textContent='Delete'; del.onclick=()=>{if(confirm('Delete player?')){players.splice(idx,1); write('gd_players',players); render()}};
actions.appendChild(edit); actions.appendChild(del); li.appendChild(actions); list.appendChild(li);
})}
form.addEventListener('submit',e=>{e.preventDefault(); const name=nameIn.value.trim(); if(!name) return; players.push({id:Date.now().toString(36),name}); write('gd_players',players); nameIn.value=''; render()});
render();
}
// Lists page
if(page==='lists'){
const levelsEl = qs('levels'); const listArea = qs('list-area'); const titleEl = qs('list-title');
// Load hard-coded data file data.txt (category|position|title|url per line)
function loadData(){
fetch('data.txt').then(r=>r.text()).then(txt=>{
const lines = txt.split(/\r?\n/).map(l=>l.trim()).filter(Boolean);
const items = lines.map(l=>{
const parts = l.split('|').map(p=>p.trim());
return {level:parts[0]||'Unknown',position:parts[1]||'',title:parts[2]||'Untitled',url:parts[3]||''};
});
setupLevels(items);
}).catch(err=>{listArea.innerHTML='<p class="muted">Failed to load data.txt — run via a local server.</p>'; console.error(err)});
}
function computeCategories(items){
const max = items.reduce((m,it)=>Math.max(m, Number(it.position)||0), 0);
const cats = ['Full List'];
for(let i=1;i<=max;i+=10){
const start = i; const end = Math.min(i+9, max);
cats.push(`Top ${start}-${end}`);
}
return cats;
}
function setupLevels(items){
const categories = computeCategories(items);
levelsEl.innerHTML='';
const filterSelect = qs('level-filter');
filterSelect.innerHTML = '<option value="all">Full List</option>';
categories.forEach(cat=>{
const li = document.createElement('li');
const btn = document.createElement('button');
btn.type = 'button';
btn.textContent = cat;
btn.className = 'level-link';
btn.addEventListener('click', ()=> {
selectLevel(cat, items, btn);
filterSelect.value = cat;
});
li.appendChild(btn);
levelsEl.appendChild(li);
const opt = document.createElement('option'); opt.value = cat; opt.textContent = cat; filterSelect.appendChild(opt);
});
// search and filter handlers
qs('search').addEventListener('input', ()=> renderTable(items));
filterSelect.addEventListener('change', ()=> renderTable(items));
// default select Full List
selectLevel('Full List', items, levelsEl.querySelector('.level-link'));
}
function selectLevel(level, items, linkEl){
levelsEl.querySelectorAll('.level-link').forEach(a=>a.classList.remove('active'));
if(linkEl) linkEl.classList.add('active');
qs('level-filter').value = level;
renderTable(items);
}
function renderTable(items){
const q = (qs('search') && qs('search').value || '').toLowerCase();
const levelFilter = (qs('level-filter') && qs('level-filter').value) || 'all';
const filtered = items.filter(it=>{
// apply level / category filter (support range categories like "Top 1-10")
if(levelFilter && levelFilter!=='all' && levelFilter!=='Full List'){
const m = levelFilter.match(/Top\s*(\d+)-(\d+)/i);
if(m){
const s = Number(m[1]); const e = Number(m[2]); const pos = Number(it.position)||0;
if(pos < s || pos > e) return false;
}
}
if(!q) return true;
return (it.title||'').toLowerCase().includes(q) || (it.level||'').toLowerCase().includes(q);
}).sort((a,b)=> (Number(a.position)||0)-(Number(b.position)||0));
const tbody = qs('list-area'); tbody.innerHTML='';
filtered.forEach(it=>{
const tr = document.createElement('tr');
const tdNum = document.createElement('td'); tdNum.textContent = it.position;
const tdTitle = document.createElement('td'); tdTitle.textContent = it.title;
const tdAct = document.createElement('td');
const a = document.createElement('a'); a.textContent='Open'; a.href='#'; a.className='btn';
a.addEventListener('click', (e)=>{e.preventDefault(); openVideo(it.url)});
tdAct.appendChild(a);
tr.appendChild(tdNum); tr.appendChild(tdTitle); tr.appendChild(tdAct);
tbody.appendChild(tr);
});
}
function openVideo(url){
if(!url) return; const id = extractYouTubeID(url);
if(!id){ window.open(url,'_blank'); return }
let modal = document.querySelector('.video-modal');
if(!modal){
modal = document.createElement('div'); modal.className='video-modal';
const inner = document.createElement('div'); inner.className='inner';
const close = document.createElement('button'); close.textContent='Close'; close.className='btn'; close.style.float='right'; close.onclick=()=>modal.remove();
inner.appendChild(close);
const iframe = document.createElement('iframe'); iframe.allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'; iframe.allowFullscreen=true;
inner.appendChild(iframe); modal.appendChild(inner); document.body.appendChild(modal);
}
modal.querySelector('iframe').src = `https://www.youtube.com/embed/${id}`;
modal.style.display = 'flex';
}
function extractYouTubeID(url){
const m = url.match(/(?:v=|\/embed\/|youtu\.be\/)([A-Za-z0-9_-]{6,})/); return m?m[1]:'';
}
loadData();
}
// Utility
function escapeHtml(s){return String(s).replace(/[&<>"']/g, c=>({"&":"&amp;","<":"&lt;",">":"&gt;","\"":"&quot;","'":"&#39;"})[c])}
})();
+50
View File
@@ -0,0 +1,50 @@
new|1|Flamewall|https://youtu.be/x4Io4zkWVRw?si=tf0DBaWahOPPEWxO
new|2|Thinking Space II|https://youtu.be/CELNmHwln_c?si=soP6SzRn92G1vKbl
new|4|Amethyst|https://youtu.be/4lfkzz1VCbA?si=6NNeWiH-nnwu21Cb
new|3|Tidal Wave|https://youtu.be/9fsZ014qB3s?si=oj4E4ceyNtRVcDvd
new|5|Orbit|https://youtu.be/QKcv8DkNPd0?si=cKBFqp7GRqmfupgJ
new|6|BOOBAWAMBA|https://youtu.be/20fYiqLAo_E?si=QSSixz31rWeeQ_8B
new|7|Nullscapes|https://youtu.be/EztneTPp5CU?si=ljn-S_bnGYwOoUyV
new|8|Quantuese Processing|https://youtu.be/j5NC0u1Q91Q?si=FvUEY2kdDtNMqWSD
new|9|Subsuming Vortex|https://youtu.be/0eYG1ogJpIQ?si=7XRxfDsmMVb0G9Si
new|10|Andromeda|https://youtu.be/mk3TDemdkC0?si=va13_RKAJUyFvhcv
new|11|Every End|https://youtu.be/AO--mVVFtKI?si=gIT5vxyc1FZ4_8Jj
new|12|Silent Clubstep|https://youtu.be/GR4OMkS3SN8?si=CMNz8bPBaUU94wiy
new|13|Anathema|https://youtu.be/_uKwmjHmySI?si=PgXwX7Z--wCay34b
new|14|Acheron|https://youtu.be/sBKR6aUorzA?si=0A9S2_W8gi1awZ81
new|15|Ashley Wave Trials|https://youtu.be/aTxt76U3e2Q?si=RVcEcOTOfs7NGWRi
new|16|Avernus|https://youtu.be/16Zh8jssanc?si=0o6d2dH4p_J7UjKB
new|17|Menace|https://youtu.be/nnkgghxxsEE?si=OuUQfD7WbXVooYyX
new|18|Spectre|https://youtu.be/MzsSLKJrLSI?si=-bXtr_jG96kTCzy4
new|19|Abyss Of Darkness|https://youtu.be/ejJkpqcMMCY?si=Rpp4HEi1kOMh-p0h
new|20|Defeated Circles|https://youtu.be/nU5AQPzd2YA?si=6eKDMPh-2QjDBBOF
new|21|Tunnel Of Despair|https://youtu.be/LpS4JREhW98?si=Z6_DRV5YZTEA0TeQ
new|22|Subterminal Point|https://youtu.be/h2wmRMgACH4?si=nDD0-bmLqPgcdVJP
new|23|KOCMOC|https://youtu.be/2CxE-UWCIG4?si=9xz4hBjtNKe8Rcbs
new|24|Slaughterhouse|https://youtu.be/kpcF1-QAHQc?si=7ybF9EbcjqHzloLM
new|25|Kyouki|https://youtu.be/KDa5c0CJTHs?si=WU0sPusFLB7Jtkam
new|26|The Lightning Rod|https://youtu.be/nQDTi077O6M?si=Kqp2Od3lJx1YWTDB
new|27|Based After Based|https://youtu.be/yQBFyUvB3lY?si=Cmxbc5jrTrNlcmG5
new|28|CHIL|https://youtu.be/DROMiCc2ZRM?si=_bR8CCnqJGVCex9F
new|29|Sakupen Circles|https://youtu.be/ofG2mJi9kEA?si=3yv78_jxidKPhtL5
new|30|Deimos (ItsHybrid)|https://youtu.be/b2yHaIk5zio?si=AMIuVFR-EW4CK8_P
new|31|Eyes In The Water|https://youtu.be/yvLwiOy3KEA?si=1991xs25WTEoTbE0
new|32|Voltage|https://youtu.be/wBRvBN9tmlc?si=GU2md9I7ZnUV7Rfr
new|33|Firework|https://youtu.be/QBe5x2o9v2w?si=dhPg9YcCRjwngxU9
new|34|Silentlocked|https://youtu.be/O-IQeUdEGvI?si=KeSHH6kwZoSVGINT
new|35|poocubed|https://youtu.be/fzL31vai1ms?si=9Gwk7RDtbEFxOJ6t
new|36|KOSETSU|https://youtu.be/hZ8vFX8z_BU?si=P6fFal0yazJbje2O
new|37|Through The Gates|https://youtu.be/4yHA6jux5UI?si=nstk3A6FDN3QR-qm
new|38|Saul Goodman|https://youtu.be/hjs5PjUaw9k?si=qJpGrru21d50gO5R
new|39|The Salt Factory|https://youtu.be/lQ7M-Sgov24?si=nXYVL0XGy5NOJLXn
new|40|Snowbound|https://youtu.be/cjHwgbtAkXU?si=ghJbRJCkN-m0zu60
new|41|CONVOLSION|https://youtu.be/qeRKuyU3eGI?si=UPaem0b3V8fX0L1r
new|42|The Apocalyptic Trilogy|https://youtu.be/RUBbpsTR5eU?si=mEsPtyMLrQgP5fWl
new|43|MINUSdry|https://youtu.be/YvA8ehhzz0Q?si=DT6DfrXOQ41swSIR
new|44|Sevvend Clubstep|https://youtu.be/TvA8EJTJFCc?si=Rm9HyExGYpeGn4qs
new|45|Edge Of Destiny|https://youtu.be/rUphe3H59yU?si=dZ8LgDyqif1ET_k1
new|46|The Halucination|https://youtu.be/tYbXsNkO9HE?si=b8hmXS98BAjDlPzF
new|47|CONVULSION|https://youtu.be/qeRKuyU3eGI?si=qJN026t6RcGjU3iW
new|48|Solar Flare|https://youtu.be/eHQNgty8ypY?si=ZdUIODdeDYLAXeHI
new|49|LIMBO|https://youtu.be/kXYMbaMVOZg?si=fWm4ngeSxBhFZadA
new|50|The Catacombs|https://youtu.be/T9-75lfKVQg?si=zEH6vP1617n5666I
+32
View File
@@ -0,0 +1,32 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>GD Demand List</title>
<link rel="stylesheet" href="styles.css">
</head>
<body data-page="index">
<header>
<h1>GD Demand List</h1>
<nav>
<a href="players.html">Players</a>
<a href="lists.html">Lists</a>
</nav>
</header>
<main>
<section class="panel">
<h2>Welcome</h2>
<p class="small muted">Use the top navigation to view players or demand lists. This UI follows a compact table-first layout for quick browsing.</p>
</section>
<section class="layout">
<div class="panel" style="flex:1">
<h3>Quick Links</h3>
<a class="btn" href="lists.html">View Lists</a>
<a class="btn" href="players.html" style="margin-left:8px">Players</a>
</div>
</section>
</main>
<script src="app.js"></script>
</body>
</html>
+44
View File
@@ -0,0 +1,44 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Lists — GD Demand List</title>
<link rel="stylesheet" href="styles.css">
</head>
<body data-page="lists">
<header>
<h1>Demand Lists</h1>
<nav>
<a href="index.html">Home</a>
<a href="players.html">Players</a>
</nav>
</header>
<main class="layout">
<aside class="sidebar">
<div class="panel">
<h2>Levels</h2>
<ul id="levels"></ul>
</div>
</aside>
<section class="panel content">
<div class="search-row">
<h2 id="list-title">All Videos</h2>
<input id="search" type="text" placeholder="Search videos or titles..." />
<select id="level-filter"><option value="all">All Levels</option></select>
</div>
<div class="table-wrap">
<table class="levels-table">
<thead>
<tr><th style="width:80px">#</th><th>Title</th><th style="width:140px">Action</th></tr>
</thead>
<tbody id="list-area"></tbody>
</table>
</div>
</section>
</main>
<script src="app.js"></script>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Players — GD Demand List</title>
<link rel="stylesheet" href="styles.css">
</head>
<body data-page="players">
<header>
<h1>Players</h1>
<nav>
<a href="index.html">Home</a>
<a href="lists.html">Lists</a>
</nav>
</header>
<main>
<section class="panel">
<h2>Add Player</h2>
<form id="player-form" style="display:flex;gap:8px">
<input id="player-name" placeholder="Player name" required />
<button class="btn" type="submit">Add</button>
</form>
</section>
<section class="panel">
<h2>Players</h2>
<ul id="players"></ul>
</section>
</main>
<script src="app.js"></script>
</body>
</html>
+34
View File
@@ -0,0 +1,34 @@
:root{--bg:#0f1724;--panel:#071326;--accent:#5cc5ff;--muted:#9fb3c8;--text:#e6eef8;--card:#081220}
*{box-sizing:border-box}
html,body{height:100%;margin:0;font-family:Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial;color:var(--text);background:linear-gradient(180deg,#061021 0%,#071426 100%)}
header{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:linear-gradient(90deg,rgba(255,255,255,0.02),transparent);backdrop-filter:blur(4px)}
header h1{margin:0;font-size:1.1rem}
nav a{color:var(--muted);margin-left:14px;text-decoration:none}
main{padding:18px 20px}
.layout{display:flex;gap:16px;align-items:flex-start}
.sidebar{width:220px}
.sidebar .panel{padding:12px;height:calc(100vh - 120px);overflow:auto}
.sidebar h2{margin:0 0 8px 0;font-size:0.95rem}
.sidebar ul{list-style:none;padding:0;margin:0}
.sidebar li{margin:6px 0}
.level-link{display:block;width:100%;text-align:left;padding:8px;border-radius:6px;border:0;background:transparent;color:var(--muted);cursor:pointer;font-weight:600}
.level-link.active{background:rgba(92,197,255,0.06);color:var(--accent)}
.content{flex:1}
.panel{background:var(--panel);padding:14px;border-radius:10px;margin-bottom:12px;box-shadow:0 3px 12px rgba(2,6,23,0.6)}
.search-row{display:flex;gap:8px;align-items:center;margin-bottom:12px}
.search-row input[type=text]{flex:1;padding:10px 12px;border-radius:8px;border:1px solid rgba(255,255,255,0.04);background:transparent;color:var(--text)}
.search-row select{padding:8px;border-radius:8px;border:1px solid rgba(255,255,255,0.04);background:transparent;color:var(--text)}
.table-wrap{overflow:auto;border-radius:8px}
table.levels-table{width:100%;border-collapse:collapse;background:linear-gradient(180deg,rgba(255,255,255,0.012),transparent)}
table.levels-table th,table.levels-table td{padding:12px 14px;border-bottom:1px solid rgba(255,255,255,0.02);text-align:left}
table.levels-table th{color:var(--muted);font-size:0.85rem;font-weight:600}
table.levels-table tr:hover td{background:rgba(255,255,255,0.01)}
.btn{display:inline-block;padding:8px 10px;border-radius:8px;background:var(--accent);color:#042;cursor:pointer;border:none}
.muted{color:var(--muted);font-size:0.9rem}
.video-modal{position:fixed;inset:0;background:rgba(0,0,0,0.7);display:flex;align-items:center;justify-content:center;z-index:1200}
.video-modal .inner{width:90%;max-width:960px;background:var(--card);padding:12px;border-radius:8px}
.video-modal iframe{width:100%;height:540px;border:0;border-radius:6px}
@media(max-width:900px){.layout{flex-direction:column}.sidebar{width:100%}.video-modal iframe{height:320px}}
/* small helpers reused */
.small{font-size:0.9rem}