From d29719131c0208cbfebbeb602adc501311accbc7 Mon Sep 17 00:00:00 2001 From: mileswa1q22 Date: Tue, 31 Mar 2026 19:00:35 -0500 Subject: [PATCH] Remove admin/server pages; consolidate live list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete admelist.html and serverlist.html and update the site to use lists.html as the main live-backed list. README.md was edited to reflect the consolidation (references to serverlist/admelist replaced with lists.html and roulette.html, wording adjusted). lists.html: remove admin/server links, change page title to “FEDL List”, and drop the level column in the table. app.js: update status text to mention the live server list, remove admin editor code and serverlist-specific branches, simplify list rendering (remove level column output) and wire live updates to listPage.applyItems. Miscellaneous: remove unused escapeAttr helper. Overall this simplifies the UI by consolidating live functionality into lists.html and removing the separate admin/server pages. --- README.md | 39 +++------- admelist.html | 52 ------------- app.js | 201 ++---------------------------------------------- lists.html | 6 +- serverlist.html | 48 ------------ 5 files changed, 17 insertions(+), 329 deletions(-) delete mode 100644 admelist.html delete mode 100644 serverlist.html diff --git a/README.md b/README.md index 0b16c5e..8a5c946 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,18 @@ # GD FEDL -A Geometry Dash FEDL-style website with both a static list and a live editable server list. +A Geometry Dash FEDL-style website with a live server-backed main list. It includes: - a home page -- a static list page -- a live server-backed list page -- an admin editor page for the live list +- a main list page - a players page - a rules page ## Project Files - `index.html` - home page -- `lists.html` - static list view -- `serverlist.html` - live server-backed list view -- `admelist.html` - admin UI for editing the live list +- `lists.html` - main live list view - `players.html` - player manager - `rules.html` - submission rules and mod guidelines - `app.js` - client-side logic @@ -43,9 +39,8 @@ new|1|Flamewall|https://youtu.be/x4Io4zkWVRw ## Pages -- `lists.html` reads the static list. -- `serverlist.html` reads the live server list. -- `admelist.html` lets you edit the live server list with a UI. +- `lists.html` is the main live list page. +- `roulette.html` uses the same live server-backed list. ## Fallback Order @@ -55,7 +50,7 @@ The live list tries these in order: 2. `server/data.txt` 3. `data.txt` -That means `serverlist.html` can still show data even if the live API is down. +That means `lists.html` can still show data even if the live API is down. ## Running The Static Site @@ -73,7 +68,7 @@ http://localhost:8000 ## Running The Live Server -The live editor and live list use the Node server: +The live list uses the Node server: ```bash node server/server.js @@ -88,8 +83,8 @@ HOST=0.0.0.0 PORT=3000 node server/server.js Then open: ```txt -http://localhost:3000/serverlist.html -http://localhost:3000/admelist.html +http://localhost:3000/lists.html +http://localhost:3000/roulette.html ``` On macOS you can also use: @@ -98,27 +93,13 @@ On macOS you can also use: start-server.command ``` -## Editing The Live List - -Open `admelist.html` through the Node server. - -Features: - -- add a new row at the top as a draft -- give it a number when you want to place it -- automatic shifting of other rows when a number is reused -- delete rows only with the Delete button -- live refresh on connected list pages after saving - -Draft rows must be assigned a number before saving. - ## Hosting On Another Device If you want one device to host the live list for other devices: 1. Run the server with `HOST=0.0.0.0`. 2. Open or forward port `3000`. -3. Visit `http://YOUR-IP:3000/serverlist.html` or `http://YOUR-IP:3000/admelist.html`. +3. Visit `http://YOUR-IP:3000/lists.html` or `http://YOUR-IP:3000/roulette.html`. If you already have router port forwarding set up, point it to the machine running `server/server.js`. diff --git a/admelist.html b/admelist.html deleted file mode 100644 index 7c65a68..0000000 --- a/admelist.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - Edit List - GD fedl - - - -
-

fedl

- -
-
-
-
-
-

Editor

-

Manage the live list

-

Loading list data...

-
-
- - - -
-
- -
- - - - - - - - - - - -
#LevelTitleVideo URLDelete
-
-
-
- - - diff --git a/app.js b/app.js index 24c31a0..9384475 100644 --- a/app.js +++ b/app.js @@ -172,7 +172,7 @@ Promise.all([loadItems(), loadLevelMeta()]).then(([items, metaMap])=>{ if(!items.length){ statusEl.textContent = 'No demons found.'; - titleEl.textContent = 'Add demons to server/data.txt'; + titleEl.textContent = 'Add demons to the live server list'; idEl.textContent = 'Level ID: -'; noteEl.textContent = 'No list data was found.'; return; @@ -196,7 +196,7 @@ titleEl.textContent = 'Run the site on a local server'; rankEl.textContent = 'Rank: -'; idEl.textContent = 'Level ID: -'; - noteEl.textContent = 'The local file or API lookup failed.'; + noteEl.textContent = 'The live list or API lookup failed.'; console.error(err); }); }); @@ -295,12 +295,11 @@ const tr = document.createElement('tr'); const tdNum = document.createElement('td'); tdNum.textContent = it.position; const tdTitle = document.createElement('td'); tdTitle.textContent = it.title; - const tdLevel = document.createElement('td'); tdLevel.textContent = it.level; 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(tdLevel); tr.appendChild(tdAct); + tr.appendChild(tdNum); tr.appendChild(tdTitle); tr.appendChild(tdAct); tbody.appendChild(tr); }); } @@ -343,204 +342,14 @@ } // Lists page - if(page==='lists' || page==='serverlist'){ + if(page==='lists'){ const listPage = initListPage(); - if(page==='serverlist'){ - bindLiveUpdates(); - onLiveUpdate(function(items){ - const status = qs('live-status'); - if(status){ - status.textContent = 'Live data updated'; - } - listPage.applyItems(items); - }); - } - } - - if(page==='admelist'){ - const statusEl = qs('admin-status'); - const tbody = qs('admin-list-body'); - const addBtn = qs('add-row'); - const saveBtn = qs('save-list'); - const searchEl = qs('admin-search'); - let items = []; - - function setStatus(message, isError){ - if(!statusEl) return; - statusEl.textContent = message; - statusEl.classList.toggle('error-text', !!isError); - } - - function filteredItems(){ - const query = (searchEl && searchEl.value || '').trim().toLowerCase(); - if(!query) return items; - return items.filter(item=>{ - return [item.level, item.position, item.title, item.url].some(value=> - String(value || '').toLowerCase().includes(query) - ); - }); - } - - function normalizePositions(){ - let position = 1; - items.forEach(item=>{ - if(item._isDraft){ - item.position = ''; - return; - } - item.position = String(position); - position += 1; - }); - } - - function moveItemToPosition(index, rawPosition){ - if(!items[index]) return; - const parsedPosition = Number(rawPosition); - if(!Number.isFinite(parsedPosition) || parsedPosition < 1) return; - const nextPosition = Math.max(1, parsedPosition); - const [item] = items.splice(index, 1); - item._isDraft = false; - const drafts = items.filter(entry=>entry._isDraft); - const ranked = items.filter(entry=>!entry._isDraft); - const targetIndex = Math.min(ranked.length, nextPosition - 1); - ranked.splice(targetIndex, 0, item); - items = drafts.concat(ranked); - normalizePositions(); - } - - function renderAdminTable(){ - const rows = filteredItems(); - tbody.innerHTML = ''; - rows.forEach((item, index)=>{ - const actualIndex = items.indexOf(item); - const tr = document.createElement('tr'); - tr.innerHTML = ` - - - - - - `; - tbody.appendChild(tr); - }); - if(!rows.length){ - const tr = document.createElement('tr'); - tr.innerHTML = 'No rows match your search.'; - tbody.appendChild(tr); - } - } - - function saveItems(){ - const hasUnplacedDraft = items.some(item=>{ - const hasContent = String(item.title || '').trim() || String(item.url || '').trim() || String(item.level || '').trim(); - return item._isDraft && hasContent; - }); - if(hasUnplacedDraft){ - setStatus('Give each new row a number before saving.', true); - return Promise.resolve(); - } - items = items - .map(item=>({ - level: String(item.level || '').trim() || 'new', - position: String(item.position || '').trim(), - title: String(item.title || '').trim(), - url: String(item.url || '').trim() - })) - .filter(item=>item.title); - normalizePositions(); - return fetch(liveApiUrl, { - method:'PUT', - headers:{'Content-Type':'application/json'}, - body: JSON.stringify({text: formatData(items)}) - }).then(r=>{ - if(!r.ok) throw new Error('Save failed'); - clearItemsCache(); - renderAdminTable(); - setStatus('Saved. Live pages update automatically.'); - }).catch(err=>{ - console.error(err); - setStatus('Could not save. Start the Node server and try again.', true); - }); - } - - function loadAdmin(){ - loadItems().then(loaded=>{ - items = loaded.slice().sort((a,b)=>(Number(a.position) || 0) - (Number(b.position) || 0)).map(item=>({ - level: item.level, - position: item.position, - title: item.title, - url: item.url, - _isDraft: false - })); - normalizePositions(); - renderAdminTable(); - setStatus('Connected to live list data.'); - }).catch(err=>{ - console.error(err); - setStatus('Could not load list data. Start the Node server first.', true); - }); - } - - tbody.addEventListener('input', function(event){ - const target = event.target; - const field = target.getAttribute('data-field'); - const index = Number(target.getAttribute('data-index')); - if(!field || Number.isNaN(index) || !items[index]) return; - if(field === 'position'){ - moveItemToPosition(index, target.value); - renderAdminTable(); - }else{ - items[index][field] = target.value; - } - setStatus('Unsaved changes'); - }); - - tbody.addEventListener('click', function(event){ - const deleteButton = event.target.closest('[data-delete]'); - if(!deleteButton) return; - const deleteIndex = deleteButton.getAttribute('data-delete'); - if(deleteIndex == null) return; - const index = Number(deleteIndex); - if(Number.isNaN(index)) return; - items.splice(index, 1); - normalizePositions(); - renderAdminTable(); - setStatus('Row removed. Save when ready.'); - }); - - addBtn.addEventListener('click', function(){ - items.unshift({level:'new', position:'', title:'', url:'', _isDraft:true}); - normalizePositions(); - renderAdminTable(); - setStatus('New row added at the top. Give it a number when you want to place it.'); - }); - - saveBtn.addEventListener('click', function(){ - saveItems(); - }); - - if(searchEl){ - searchEl.addEventListener('input', renderAdminTable); - } - bindLiveUpdates(); onLiveUpdate(function(updatedItems){ - items = updatedItems.slice().sort((a,b)=>(Number(a.position) || 0) - (Number(b.position) || 0)).map(item=>({ - level: item.level, - position: item.position, - title: item.title, - url: item.url, - _isDraft: false - })); - normalizePositions(); - renderAdminTable(); - setStatus('List reloaded from live server.'); + listPage.applyItems(updatedItems); }); - - loadAdmin(); } // Utility function escapeHtml(s){return String(s).replace(/[&<>"']/g, c=>({"&":"&","<":"<",">":">","\"":""","'":"'"})[c])} - function escapeAttr(s){return escapeHtml(String(s == null ? '' : s))} })(); diff --git a/lists.html b/lists.html index 3141321..9852d27 100644 --- a/lists.html +++ b/lists.html @@ -13,8 +13,6 @@ Home Players Rules - Server List - Edit List Roulette @@ -28,7 +26,7 @@
-

All Videos

+

FEDL List

@@ -36,7 +34,7 @@
- +
#TitleLevelAction
#TitleAction
diff --git a/serverlist.html b/serverlist.html deleted file mode 100644 index 5c2f41a..0000000 --- a/serverlist.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - Server List - GD fedl - - - -
-

fedl

- -
-
- - -
-
-

Live Server List

- - -
- -
- - - - - -
#TitleLevelAction
-
-
-
- - -