Files
encounterflow/battleflow/templates/admin.html
Peter van Arkel 644b207997 pre-push commit
2025-11-20 14:40:42 +01:00

236 lines
9.6 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>✦ {{ name }} Admin</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<style>
body{ font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, 'Helvetica Neue', Arial; background:#0b0d12; color:#e9eef4; margin:0; }
.topbar{ display:flex; justify-content:space-between; align-items:flex-start; gap:12px; padding:10px 16px 0; }
.left{ display:flex; flex-direction:column; gap:6px; }
.title{ opacity:.65;font-size:12px }
.subtitle{ opacity:.55; font-size:11px; margin-top:-2px; }
.globalbar{ display:flex; gap:8px; flex-wrap:wrap; }
.seg{ display:inline-flex; gap:6px; align-items:center; }
.seg .btn{ padding:4px 8px; font-size:12px; }
.seg .on{ outline:2px solid #334155; }
.wrap{ display:grid; grid-template-columns: 520px 1fr; gap:16px; padding:16px; }
.card{ background:#121621; border:1px solid #1f2535; border-radius:12px; padding:14px; }
h2{ margin:0 0 10px; font-size:16px; letter-spacing:0.4px; }
label{ font-size:12px; color:#9aa0aa; }
input, select{ width:100%; padding:8px; border-radius:8px; border:1px solid #293145; background:#0d111a; color:#e9eef4; }
.row{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
table{ width:100%; border-collapse:collapse; }
th,td{ border-bottom:1px solid #1f2535; padding:8px; font-size:14px; vertical-align:top; }
tr.active{ outline:2px solid #fde047; }
button{ padding:6px 8px; border-radius:10px; border:1px solid #293145; background:#0d111a; color:#e9eef4; cursor:pointer; }
.btn{ padding:6px 10px; border-radius:10px; border:1px solid #293145; background:#0d111a; color:#e9eef4; cursor:pointer; }
.btn-danger{ border-color:#7f1d1d; background:#1a0b0b; color:#fecaca; }
.btn-outline{ background:transparent; }
.pill{ display:inline-block; padding:2px 8px; border-radius:999px; font-size:12px; border:1px solid #293145; }
.tagType{ display:inline-block; padding:2px 8px; border-radius:999px; font-size:12px; border:1px solid transparent; font-weight:600; }
.tagType.pc{ background:#082f35; color:#7dd3fc; border-color:#0c4a59; }
.tagType.npc{ background:#1d1533; color:#c4b5fd; border-color:#352a5f; }
.tagType.monster{ background:#3b1111; color:#fca5a5; border-color:#5b1a1a; }
.bar{ display:flex; gap:8px; margin-top:8px; flex-wrap: wrap; }
.condbar button{ margin:2px; font-size:12px; display:inline-flex; align-items:center; gap:6px; }
.condbar button.on{ background:#1e293b; border-color:#334155; }
.presetlist{ max-height: 260px; overflow:auto; border:1px solid #1f2535; border-radius:10px; padding:6px; }
.preset{ display:flex; align-items:center; gap:8px; padding:6px; border-bottom:1px dashed #1f2535; }
.preset:last-child{ border-bottom:0; }
.pav{ width:22px; height:22px; border-radius:6px; object-fit:cover; background:#0d111a; }
.uploadrow{ display:grid; grid-template-columns: 1fr auto auto 68px; gap:8px; align-items:center; }
.preview{ width:64px; height:64px; border-radius:10px; background:#0d111a; border:1px solid #293145; object-fit:cover; }
.dropzone{ border:2px dashed #293145; border-radius:10px; padding:12px; text-align:center; color:#9aa0aa; }
.dropzone.drag{ background:#0f172a; border-color:#334155; color:#cbd5e1; }
.icoimg{ width:14px; height:14px; display:inline-block; vertical-align:-2px; }
.credit{ font-size:11px; color:#94a3b8; opacity:0.8; margin: 16px; text-align:center; }
.twocol{ display:grid; grid-template-columns:1fr 1fr; gap:16px; }
.scroll{ max-height:180px; overflow:auto; border:1px solid #1f2535; border-radius:10px; padding:8px; }
.muted{ color:#9aa0aa; font-size:12px; }
</style>
</head>
<body>
<div class="topbar">
<div class="left">
<div class="title">{{ name|upper }} ADMIN</div>
<div class="subtitle">{{ subtitle }}</div>
<div class="globalbar">
<button class="btn" onclick="clearAll()">Clear</button>
<button class="btn" onclick="toggleVisible()">Toggle Board</button>
<button class="btn" onclick="prev()">Prev</button>
<button class="btn" onclick="next()">Next</button>
<div class="seg" id="deadseg">
<span class="muted">Dead cards:</span>
<button class="btn" data-mode="normal" onclick="setDeadMode('normal')">Normal</button>
<button class="btn" data-mode="shrink" onclick="setDeadMode('shrink')">Shrink</button>
<button class="btn" data-mode="hide" onclick="setDeadMode('hide')">Hide</button>
</div>
</div>
</div>
<div style="display:flex; gap:8px; align-items:center;">
<form action="/admin/seed_icons?token={{ token }}" method="post" onsubmit="return confirm('Download curated icons from Game-Icons.net now?');" style="margin:0">
<button class="btn">Seed curated icon set</button>
</form>
<button class="btn" onclick="openBoard()">Open Player Board ↗</button>
</div>
</div>
<div class="wrap">
<div class="card">
<h2>Add Actor</h2>
<div class="row">
<div>
<label>Name</label>
<input id="name"/>
</div>
<div>
<label>Init</label>
<input id="init" type="number" step="0.1" />
</div>
</div>
<div class="row" style="margin-top:6px;">
<div>
<label>HP</label>
<input id="hp" type="number"/>
</div>
<div>
<label>AC</label>
<input id="ac" type="number"/>
</div>
</div>
<div class="row" style="margin-top:6px;">
<div>
<label>Type</label>
<select id="type">
<option value="pc">PC</option>
<option value="npc">NPC</option>
<option value="monster">Monster</option>
</select>
</div>
<div>
<label>Note</label>
<input id="note"/>
</div>
</div>
<div class="row" style="margin-top:6px;align-items:center;grid-template-columns:1fr auto auto 68px;">
<div>
<label>Avatar (filename in /avatars or full URL)</label>
<input id="avatar" placeholder="goblin.png or https://..."/>
</div>
<div class="dropzone" id="avatar_drop">Drop image here</div>
<button class="btn" onclick="uploadAvatar('avatar_file','avatar','avatar_preview')">Upload</button>
<img id="avatar_preview" class="preview" alt="preview"/>
</div>
<div class="uploadrow" style="margin-top:6px;">
<input type="file" id="avatar_file" accept="image/*" />
<div class="muted">or drag & drop ↑</div>
<div></div>
<div></div>
</div>
<div class="bar">
<button class="btn" onclick="add()">Add</button>
</div>
</div>
<div class="card">
<h2>Order (desc by init) — Round <span id="round">1</span></h2>
<table>
<thead>
<tr><th>#</th><th>Name</th><th>Init</th><th>HP</th><th>AC</th><th>Type</th><th>Flags</th><th></th></tr>
</thead>
<tbody id="rows"></tbody>
</table>
</div>
</div>
<div class="wrap">
<div class="card">
<h2>Add Preset</h2>
<div class="row">
<div>
<label>Name</label>
<input id="p_name"/>
</div>
<div>
<label>Type</label>
<select id="p_type">
<option value="pc">PC</option>
<option value="npc">NPC</option>
<option value="monster">Monster</option>
</select>
</div>
</div>
<div class="row" style="margin-top:6px;">
<div>
<label>HP</label>
<input id="p_hp" type="number"/>
</div>
<div>
<label>AC</label>
<input id="p_ac" type="number"/>
</div>
</div>
<div class="row" style="margin-top:6px;">
<div>
<label>Note</label>
<input id="p_note"/>
</div>
<div>
<label>Avatar</label>
<input id="p_avatar" placeholder="filename in /avatars or URL"/>
</div>
</div>
<div class="row" style="margin-top:6px;align-items:center;grid-template-columns:1fr auto auto 68px;">
<div class="dropzone" id="p_avatar_drop">Drop image here</div>
<button class="btn" onclick="uploadAvatar('p_avatar_file','p_avatar','p_avatar_preview')">Upload</button>
<img id="p_avatar_preview" class="preview" alt="preview"/>
<div></div>
</div>
<div class="uploadrow" style="margin-top:6px;">
<input type="file" id="p_avatar_file" accept="image/*" />
<div class="muted">or drag & drop ↑</div>
<div></div>
<div></div>
</div>
<div class="bar">
<button class="btn" onclick="presetAdd()">Save Preset</button>
</div>
</div>
<div class="card">
<h2>Presets</h2>
<div class="presetlist" id="presetlist"></div>
</div>
</div>
<div class="wrap">
<div class="card">
<h2>Create Preset Group (party)</h2>
<div class="twocol">
<div>
<label>Group name</label>
<input id="g_name" placeholder="Party Alpha" />
<div class="bar"><button class="btn" onclick="groupAdd()">Save Group</button></div>
</div>
<div>
<label>Select presets</label>
<div id="g_checks" class="scroll"></div>
</div>
</div>
</div>
<div class="card">
<h2>Preset Groups</h2>
<div class="presetlist" id="pg_list"></div>
</div>
</div>
<p class="credit">Icons live in <code>{{ data_dir }}/icons</code>. Curated set from <strong>Game-Icons.net</strong> (CCBY 3.0). Authors: Lorc, Delapouite, Skoll, sbed. Replace any icon by dropping an SVG with the same name (e.g., <code>poisoned.svg</code>).</p>
<script src="{{ url_for('static', filename='js/admin.js') }}"></script>
<script>
// initialise toggles/preview/dropzones and start polling
initAdmin('{{ token }}');
</script>
</body>
</html>