diff options
Diffstat (limited to 'internal/admin/templates')
| -rw-r--r-- | internal/admin/templates/courses.html | 14 | ||||
| -rw-r--r-- | internal/admin/templates/dashboard.html | 22 | ||||
| -rw-r--r-- | internal/admin/templates/drops.html | 18 | ||||
| -rw-r--r-- | internal/admin/templates/files.html | 81 | ||||
| -rw-r--r-- | internal/admin/templates/hazards.html | 14 | ||||
| -rw-r--r-- | internal/admin/templates/items.html | 45 | ||||
| -rw-r--r-- | internal/admin/templates/layout.html | 48 | ||||
| -rw-r--r-- | internal/admin/templates/login.html | 28 | ||||
| -rw-r--r-- | internal/admin/templates/map.html | 21 | ||||
| -rw-r--r-- | internal/admin/templates/mobs.html | 52 | ||||
| -rw-r--r-- | internal/admin/templates/modules.html | 14 | ||||
| -rw-r--r-- | internal/admin/templates/objects.html | 29 | ||||
| -rw-r--r-- | internal/admin/templates/players.html | 33 | ||||
| -rw-r--r-- | internal/admin/templates/techs.html | 14 |
14 files changed, 433 insertions, 0 deletions
diff --git a/internal/admin/templates/courses.html b/internal/admin/templates/courses.html new file mode 100644 index 0000000..60e07f8 --- /dev/null +++ b/internal/admin/templates/courses.html @@ -0,0 +1,14 @@ +{{define "body-courses"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search courses..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Course</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select a course to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script>initEditor('courses', [{key:'name',label:'Name',type:'text'},{key:'skill',label:'Skill',type:'text'},{key:'level',label:'Level',type:'number'},{key:'cost',label:'Cost',type:'number'},{key:'description',label:'Description',type:'textarea'}]);</script> +{{end}} diff --git a/internal/admin/templates/dashboard.html b/internal/admin/templates/dashboard.html new file mode 100644 index 0000000..198746d --- /dev/null +++ b/internal/admin/templates/dashboard.html @@ -0,0 +1,22 @@ +{{define "body-dashboard"}} +<div style="padding:20px"> + <h2>Dashboard</h2> + <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-top:16px" id="dashGrid"></div> +</div> +<script> +API.get('/api/dashboard').then(function(d){ + var grid = $('#dashGrid'); + var items = [ + {label:'Rooms',value:d.roomCount}, + {label:'Items',value:d.itemCount}, + {label:'Objects',value:d.objectCount}, + {label:'Mobs',value:d.mobCount}, + {label:'Players',value:d.playerCount}, + {label:'Accounts',value:d.accountCount} + ]; + grid.innerHTML = items.map(function(i){ + return '<div style="background:var(--panel);border:1px solid var(--border);padding:16px;border-radius:4px;text-align:center"><div style="font-size:28px;font-weight:bold">'+i.value+'</div><div style="font-size:11px;color:#888;margin-top:4px">'+i.label+'</div></div>'; + }).join(''); +}).catch(function(e){notify('Failed: '+e.message,'error')}); +</script> +{{end}} diff --git a/internal/admin/templates/drops.html b/internal/admin/templates/drops.html new file mode 100644 index 0000000..c040ef2 --- /dev/null +++ b/internal/admin/templates/drops.html @@ -0,0 +1,18 @@ +{{define "body-drops"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search drop tables..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Drop Table</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select a drop table to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script> +initEditor('drops', [ + {key:'drops',label:'Drops (JSON array)',type:'textarea',parser:function(v){try{return JSON.parse(v)}catch(e){return []}}} +]); +</script> +{{end}} diff --git a/internal/admin/templates/files.html b/internal/admin/templates/files.html new file mode 100644 index 0000000..b89a142 --- /dev/null +++ b/internal/admin/templates/files.html @@ -0,0 +1,81 @@ +{{define "body-files"}} +<div class="editor-container"> + <div class="editor-list" id="fileList"> + <div class="search-bar"><input placeholder="Filter files..." oninput="filterFiles(this.value)"></div> + <div id="listEntries"></div> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select a file to edit</p> + </div> +</div> +<script> +var currentPath = ''; +window._allFiles = []; + +function loadFiles(path) { + currentPath = path || ''; + API.get('/api/files' + (path ? '?path=' + encodeURIComponent(path) : '')).then(function(r){ + var files = r.files || r || []; + window._allFiles = files; + renderFileList(''); + }).catch(function(e){notify('Failed: '+e.message,'error')}); +} + +function renderFileList(filter){ + var el = $('#listEntries'); + var f = filter.toLowerCase(); + var items = window._allFiles.filter(function(x){ return !f || x.name.toLowerCase().indexOf(f) >= 0; }); + var html = '<div class="item" onclick="loadFiles(\'\')" style="color:#6cf">[root]</div>'; + if (currentPath) { + var parent = currentPath.split('/').slice(0,-1).join('/'); + html += '<div class="item" onclick="loadFiles(\''+escJs(parent)+'\')" style="color:#6cf">[..]</div>'; + } + items.forEach(function(x){ + if (x.dir) { + var sub = currentPath ? currentPath + '/' + x.name : x.name; + html += '<div class="item" onclick="loadFiles(\''+escJs(sub)+'\')" style="color:#fc6">'+escHtml(x.name)+'/</div>'; + } else { + var fp = currentPath ? currentPath + '/' + x.name : x.name; + html += '<div class="item" onclick="loadFileContent(\''+escJs(fp)+'\',\''+escJs(x.name)+'\')">'+escHtml(x.name)+'</div>'; + } + }); + el.innerHTML = html; +} + +function filterFiles(val) { renderFileList(val); } + +function loadFileContent(path, name) { + currentPath = path; + API.get('/api/files?path=' + encodeURIComponent(path)).then(function(r){ + var content = r.content || r.raw || JSON.stringify(r,null,2); + var html = '<h2>'+escHtml(name)+'</h2>'; + html += '<div class="form-group"><label>Path</label><span style="font-size:11px;color:#888">'+escHtml(path)+'</span></div>'; + html += '<textarea id="fileContent" rows="20" style="width:100%;font-family:monospace;font-size:12px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);padding:8px">'+escHtml(content)+'</textarea>'; + html += '<div class="btn-row"><button class="btn btn-primary" onclick="saveFile(\''+escJs(path)+'\')">Save</button></div>'; + $('#editorMain').innerHTML = html; + }).catch(function(e){notify('Failed: '+e.message,'error')}); +} + +function saveFile(path) { + var content = $('#fileContent').value; + fetch('/api/files?path=' + encodeURIComponent(path), { + method: 'PUT', + headers: {'Content-Type': 'text/plain'}, + body: content, + credentials: 'same-origin' + }).then(function(r) { + if (!r.ok) throw new Error('Save failed'); + return r.json(); + }).then(function() { + notify('File saved', 'success'); + updateUndoBar(); + }).catch(function(e) { notify('Save failed: '+e.message, 'error'); }); +} + +window.refreshPage = function() { loadFiles(currentPath); }; +function escHtml(s) { return String(s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); } +function escJs(s) { return String(s||'').replace(/\\/g,'\\\\').replace(/'/g,"\\'").replace(/"/g,'\\"'); } + +loadFiles(''); +</script> +{{end}} diff --git a/internal/admin/templates/hazards.html b/internal/admin/templates/hazards.html new file mode 100644 index 0000000..0d60df6 --- /dev/null +++ b/internal/admin/templates/hazards.html @@ -0,0 +1,14 @@ +{{define "body-hazards"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search hazards..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Hazard</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select a hazard to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script>initEditor('hazards', [{key:'name',label:'Name',type:'text'},{key:'damage',label:'Damage',type:'number'},{key:'speed',label:'Speed',type:'number'},{key:'required_item',label:'Required Item',type:'text'},{key:'message',label:'Message',type:'text'},{key:'lethal',label:'Lethal',type:'checkbox'}]);</script> +{{end}} diff --git a/internal/admin/templates/items.html b/internal/admin/templates/items.html new file mode 100644 index 0000000..f8f3b66 --- /dev/null +++ b/internal/admin/templates/items.html @@ -0,0 +1,45 @@ +{{define "body-items"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search items..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Item</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select an item to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script> +initEditor('items', [ + {key:'name',label:'Name',type:'text'}, + {key:'color',label:'Color',type:'color'}, + {key:'description',label:'Description',type:'textarea'}, + {key:'value',label:'Value',type:'number'}, + {key:'stackable',label:'Stackable',type:'checkbox'}, + {key:'equip_slot',label:'Equip Slot',type:'text'}, + {key:'weapon_type',label:'Weapon Type',type:'text'}, + {key:'attack_type',label:'Attack Type',type:'text'}, + {key:'speed',label:'Speed',type:'number'}, + {key:'tool_type',label:'Tool Type',type:'text'}, + {key:'tool_speed',label:'Tool Speed',type:'number'}, + {key:'burn_ticks',label:'Burn Ticks',type:'number'}, + {key:'fire_level',label:'Fire Level',type:'number'}, + {key:'fire_xp',label:'Fire XP',type:'number'}, + {key:'quality',label:'Quality',type:'number'}, + {key:'max_quality',label:'Max Quality',type:'number'}, + {key:'search_table',label:'Search Table',type:'text'}, + {key:'search_ticks',label:'Search Ticks',type:'number'}, + {key:'heal_value',label:'Heal Value',type:'number'}, + {key:'eat_message',label:'Eat Message',type:'text'}, + {key:'farm_patch_type',label:'Farm Patch',type:'text'}, + {key:'farm_level',label:'Farm Level',type:'number'}, + {key:'farm_stages',label:'Farm Stages',type:'number'}, + {key:'farm_product',label:'Farm Product',type:'text'}, + {key:'potion_effect',label:'Potion Effect',type:'text'}, + {key:'potion_bonus',label:'Potion Bonus',type:'number'}, + {key:'potion_duration',label:'Potion Duration',type:'number'}, + {key:'recoverable',label:'Recoverable',type:'checkbox'} +]); +</script> +{{end}} diff --git a/internal/admin/templates/layout.html b/internal/admin/templates/layout.html new file mode 100644 index 0000000..99c1f0d --- /dev/null +++ b/internal/admin/templates/layout.html @@ -0,0 +1,48 @@ +{{define "layout"}}<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>THOI Admin{{if .Page}} — {{.Page}}{{end}}</title> +<link rel="stylesheet" href="/static/admin.css"> +<script src="/static/admin.js"></script> +<script src="/static/colorpicker.js"></script> +</head> +<body> +<nav class="nav"> + <a href="/" class="{{if eq .Page "map"}}active{{end}}">Map</a> + <a href="/editor/objects" class="{{if eq .Page "objects"}}active{{end}}">Objects</a> + <a href="/editor/items" class="{{if eq .Page "items"}}active{{end}}">Items</a> + <a href="/editor/mobs" class="{{if eq .Page "mobs"}}active{{end}}">Mobs</a> + <a href="/editor/drops" class="{{if eq .Page "drops"}}active{{end}}">Drops</a> + <a href="/editor/hazards" class="{{if eq .Page "hazards"}}active{{end}}">Hazards</a> + <a href="/editor/techs" class="{{if eq .Page "techs"}}active{{end}}">Techs</a> + <a href="/editor/courses" class="{{if eq .Page "courses"}}active{{end}}">Courses</a> + <a href="/editor/modules" class="{{if eq .Page "modules"}}active{{end}}">Modules</a> + <a href="/editor/players" class="{{if eq .Page "players"}}active{{end}}">Players</a> + <a href="/editor/dashboard" class="{{if eq .Page "dashboard"}}active{{end}}">Dashboard</a> + <a href="/editor/files" class="{{if eq .Page "files"}}active{{end}}">Files</a> + <div class="undo-bar"> + <button class="undo-btn" onclick="doUndo()" title="">⟲ Undo</button> + <button class="redo-btn" onclick="doRedo()" title="">⟳ Redo</button> + <span class="undo-label"></span> + </div> + <span style="font-size:11px;color:#888">| {{.Account}}</span> + <a href="/logout" style="font-size:11px">Logout</a> +</nav> +{{if eq .Page "map"}}{{template "body-map" .}} +{{else if eq .Page "objects"}}{{template "body-objects" .}} +{{else if eq .Page "items"}}{{template "body-items" .}} +{{else if eq .Page "mobs"}}{{template "body-mobs" .}} +{{else if eq .Page "drops"}}{{template "body-drops" .}} +{{else if eq .Page "hazards"}}{{template "body-hazards" .}} +{{else if eq .Page "techs"}}{{template "body-techs" .}} +{{else if eq .Page "courses"}}{{template "body-courses" .}} +{{else if eq .Page "modules"}}{{template "body-modules" .}} +{{else if eq .Page "players"}}{{template "body-players" .}} +{{else if eq .Page "dashboard"}}{{template "body-dashboard" .}} +{{else if eq .Page "files"}}{{template "body-files" .}} +{{else}}<p style="color:#888;text-align:center;margin-top:60px">Unknown page: {{.Page}}</p>{{end}} +</body> +</html> +{{end}} diff --git a/internal/admin/templates/login.html b/internal/admin/templates/login.html new file mode 100644 index 0000000..ffc59c6 --- /dev/null +++ b/internal/admin/templates/login.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>THOI Admin — Login</title> +<link rel="stylesheet" href="/static/admin.css"> +</head> +<body> +<div class="login"> + <h1>THOI Admin Portal</h1> + {{if .Error}}<p style="color:var(--danger);text-align:center;margin-bottom:12px;font-size:13px">{{.Error}}</p>{{end}} + <form method="post" action="/login"> + <div class="form-group"> + <label>Account Name</label> + <input type="text" name="account" required autofocus autocomplete="username"> + </div> + <div class="form-group"> + <label>Password</label> + <input type="password" name="password" required autocomplete="current-password"> + </div> + <div class="btn-row"> + <button type="submit" class="btn btn-primary" style="width:100%">Login</button> + </div> + </form> +</div> +</body> +</html> diff --git a/internal/admin/templates/map.html b/internal/admin/templates/map.html new file mode 100644 index 0000000..7f8d5a1 --- /dev/null +++ b/internal/admin/templates/map.html @@ -0,0 +1,21 @@ +{{define "body-map"}} +<div class="layout"> + <div class="main" id="mapContainer"> + <div class="z-controls"> + <button onclick="changeZ(-1)">-</button> + <span class="z-label" id="zLabel">Z=0</span> + <button onclick="changeZ(1)">+</button> + <button onclick="changeZ(0)" style="width:auto;font-size:11px">Reset</button> + <select id="dirSelect" onchange="changeDir(this.value)" style="margin-left:8px;padding:3px 6px;font-size:11px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);border-radius:3px;font-family:monospace"></select> + </div> + <svg id="mapSvg" style="width:100%;height:100%"></svg> + <div class="room-tooltip" id="tooltip" style="display:none"></div> + </div> + <div class="panel" id="sidePanel"> + <div id="panelContent"> + <p style="color:#888;text-align:center;margin-top:40px">Click a room to view details</p> + </div> + </div> +</div> +<script src="/static/map.js"></script> +{{end}} diff --git a/internal/admin/templates/mobs.html b/internal/admin/templates/mobs.html new file mode 100644 index 0000000..d6191fa --- /dev/null +++ b/internal/admin/templates/mobs.html @@ -0,0 +1,52 @@ +{{define "body-mobs"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search mobs..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Mob</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select a mob to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script src="/static/talktree.js"></script> +<script> +initEditor('mobs', [ + {key:'name',label:'Name',type:'text'}, + {key:'description',label:'Description',type:'textarea'}, + {key:'attack',label:'Attack',type:'number'}, + {key:'strength',label:'Strength',type:'number'}, + {key:'defense',label:'Defense',type:'number'}, + {key:'hp',label:'HP',type:'number'}, + {key:'ranged',label:'Ranged',type:'number'}, + {key:'science',label:'Science',type:'number'}, + {key:'speed',label:'Speed',type:'number'}, + {key:'aggressive',label:'Aggressive',type:'checkbox'}, + {key:'protected',label:'Protected',type:'checkbox'}, + {key:'unique',label:'Unique',type:'checkbox'}, + {key:'respawn_ticks',label:'Respawn Ticks',type:'number'}, + {key:'attack_bonus',label:'Attack Bonus',type:'number'}, + {key:'strength_bonus',label:'Strength Bonus',type:'number'}, + {key:'attack_type',label:'Attack Type',type:'text'}, + {key:'stab_defense',label:'Stab Defense',type:'number'}, + {key:'slash_defense',label:'Slash Defense',type:'number'}, + {key:'crush_defense',label:'Crush Defense',type:'number'}, + {key:'science_defense',label:'Science Defense',type:'number'}, + {key:'ranged_defense',label:'Ranged Defense',type:'number'}, + {key:'weakness',label:'Weakness',type:'text'}, + {key:'steal_table',label:'Steal Table',type:'text'}, + {key:'steal_level',label:'Steal Level',type:'number'}, + {key:'steal_xp',label:'Steal XP',type:'number'}, + {key:'steal_speed',label:'Steal Speed',type:'number'}, + {key:'assassin_level',label:'Assassin Level',type:'number'}, + {key:'finishing_blow',label:'Finishing Blow',type:'text'}, + {key:'damage_without',label:'Damage Without',type:'text'}, + {key:'size',label:'Size',type:'text'}, + {key:'kind',label:'Kind',type:'text'}, + {key:'verb',label:'Verb',type:'text'}, + {key:'progress_noun',label:'Progress Noun',type:'text'}, + {key:'complete_message',label:'Complete Message',type:'text'} +]); +</script> +{{end}} diff --git a/internal/admin/templates/modules.html b/internal/admin/templates/modules.html new file mode 100644 index 0000000..0f8ca7c --- /dev/null +++ b/internal/admin/templates/modules.html @@ -0,0 +1,14 @@ +{{define "body-modules"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search modules..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Module</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select a module to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script>initEditor('modules', [{key:'name',label:'Name',type:'text'},{key:'type',label:'Type',type:'text'},{key:'effect',label:'Effect',type:'text'},{key:'description',label:'Description',type:'textarea'}]);</script> +{{end}} diff --git a/internal/admin/templates/objects.html b/internal/admin/templates/objects.html new file mode 100644 index 0000000..91aca09 --- /dev/null +++ b/internal/admin/templates/objects.html @@ -0,0 +1,29 @@ +{{define "body-objects"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search objects..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Object</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select an object to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script> +initEditor('objects', [ + {key:'name',label:'Name',type:'text'}, + {key:'color',label:'Color',type:'color'}, + {key:'aliases',label:'Aliases (comma sep)',type:'text'}, + {key:'hidden',label:'Hidden',type:'checkbox'}, + {key:'inroom_description',label:'In-Room Description',type:'text'}, + {key:'description',label:'Description',type:'textarea'}, + {key:'removal_item',label:'Removal Item ID',type:'text'}, + {key:'steal_table',label:'Steal Table ID',type:'text'}, + {key:'steal_level',label:'Steal Level',type:'number'}, + {key:'steal_xp',label:'Steal XP',type:'number'}, + {key:'steal_speed',label:'Steal Speed',type:'number'}, + {key:'guard_mob',label:'Guard Mob ID',type:'text'} +]); +</script> +{{end}} diff --git a/internal/admin/templates/players.html b/internal/admin/templates/players.html new file mode 100644 index 0000000..43627d8 --- /dev/null +++ b/internal/admin/templates/players.html @@ -0,0 +1,33 @@ +{{define "body-players"}} +<div style="padding:20px"> + <h2>Players</h2> + <div class="search-bar" style="max-width:400px"><input placeholder="Search players..." id="playerSearch" oninput="searchPlayers()"></div> + <table class="table" style="margin-top:12px"> + <thead><tr><th>Name</th><th>Level</th><th>Room</th><th>Account</th></tr></thead> + <tbody id="playerTableBody"></tbody> + </table> +</div> +<script> +API.get('/api/players').then(function(r){ + var tbody = $('#playerTableBody'); + var players = r.players || r || []; + window._players = players; + renderPlayerTable(''); +}).catch(function(e){notify('Failed: '+e.message,'error')}); +function searchPlayers(){ + var q = ($('#playerSearch').value||'').toLowerCase(); + renderPlayerTable(q); +} +function renderPlayerTable(q){ + var tbody = $('#playerTableBody'); + var rows = (window._players||[]).filter(function(p){ + var name = (p.name||p.Name||'').toLowerCase(); + return !q || name.indexOf(q) >= 0; + }).map(function(p){ + return '<tr><td>'+esc(p.name||p.Name)+'</td><td>'+esc(p.level||p.Level)+'</td><td>'+esc(p.room||p.Room)+'</td><td>'+esc(p.account||p.Account)+'</td></tr>'; + }); + tbody.innerHTML = rows.join('') || '<tr><td colspan="4" style="color:#888">No players found</td></tr>'; +} +function esc(s) { return String(s || '').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); } +</script> +{{end}} diff --git a/internal/admin/templates/techs.html b/internal/admin/templates/techs.html new file mode 100644 index 0000000..084d564 --- /dev/null +++ b/internal/admin/templates/techs.html @@ -0,0 +1,14 @@ +{{define "body-techs"}} +<div class="editor-container"> + <div class="editor-list" id="itemList"> + <div class="search-bar"><input placeholder="Search techs..." oninput="filterList(this.value)"></div> + <div id="listEntries"></div> + <button class="btn btn-primary btn-sm" style="margin-top:8px;width:100%" onclick="createNew()">+ New Tech</button> + </div> + <div class="editor-main" id="editorMain"> + <p style="color:#888;text-align:center;margin-top:60px">Select a tech to edit</p> + </div> +</div> +<script src="/static/editor.js"></script> +<script>initEditor('techs', [{key:'name',label:'Name',type:'text'},{key:'category',label:'Category',type:'text'},{key:'tier',label:'Tier',type:'number'},{key:'drain',label:'Drain Rate',type:'number'},{key:'bonus',label:'Bonus',type:'number'},{key:'description',label:'Description',type:'textarea'}]);</script> +{{end}} |
