feat: add landing page, Improved key rating page UI

This commit is contained in:
serversdwn
2026-03-08 21:17:50 +00:00
parent 4893f3deee
commit 289c45e233
7 changed files with 490 additions and 28 deletions

342
templates/keys.html Normal file
View File

@@ -0,0 +1,342 @@
<!doctype html>
<html>
<head>
<title>OnlyScavs Key Ratings</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
--bg: #121212;
--panel: #1a1a1a;
--text: #eee;
--muted: #999;
--border: #2a2a2a;
--accent: #9ccfff;
--accent2: #ffd580;
}
* { box-sizing: border-box; }
body {
font-family: sans-serif;
background: var(--bg);
color: var(--text);
margin: 0;
padding: 16px;
}
.page {
max-width: 980px;
margin: 0 auto;
}
nav {
display: flex;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 16px;
font-size: 0.9rem;
}
nav a {
color: var(--muted);
text-decoration: none;
padding: 4px 0;
border-bottom: 2px solid transparent;
transition: color 0.15s, border-color 0.15s;
}
nav a:hover { color: var(--text); }
nav a.active { color: var(--accent); border-bottom-color: var(--accent); }
h1 {
font-size: 1.4rem;
margin: 0 0 16px;
color: var(--accent);
letter-spacing: 0.02em;
}
/* ── filters ───────────────────────────────────────────── */
.filters {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 20px;
}
.filters label { color: var(--muted); font-size: 0.85rem; }
select, input[type="text"] {
background: #222;
color: var(--text);
border: 1px solid #3a3a3a;
border-radius: 6px;
padding: 7px 10px;
font-size: 0.9rem;
}
select:focus, input:focus { outline: 1px solid var(--accent); }
button {
background: #2a2a2a;
color: var(--text);
border: 1px solid #444;
cursor: pointer;
padding: 7px 14px;
border-radius: 6px;
font-size: 0.9rem;
transition: background 0.15s;
}
button:hover { background: #333; }
/* ── save-all bar ──────────────────────────────────────── */
.save-all {
margin: 4px 0 18px;
}
.save-all button {
background: #1d3a52;
border-color: #2d5a7a;
color: var(--accent);
font-weight: 600;
}
.save-all button:hover { background: #254a66; }
/* ── key card ──────────────────────────────────────────── */
.key {
display: grid;
grid-template-columns: 56px 1fr auto;
gap: 12px;
align-items: start;
padding: 14px 10px;
border-bottom: 1px solid var(--border);
transition: background 0.1s;
}
.key:hover { background: #161616; }
.key-thumb {
width: 56px;
height: 56px;
border-radius: 6px;
background: #1a1a1a;
object-fit: contain;
flex-shrink: 0;
}
/* left column: name + tags */
.key-info { min-width: 0; }
.key-title {
display: flex;
align-items: baseline;
gap: 8px;
flex-wrap: wrap;
}
.key-title strong { font-size: 0.95rem; line-height: 1.3; }
.key-title a { color: var(--accent); font-size: 0.8rem; }
.map-tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-top: 6px;
}
.map-tag {
background: #1e2e1e;
border: 1px solid #2a3f2a;
color: #8fbc8f;
border-radius: 999px;
padding: 1px 8px;
font-size: 0.75rem;
}
/* right column: controls */
.key-controls {
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
justify-content: flex-end;
min-width: 280px;
}
.priority-select {
min-width: 100px;
}
/* priority colour coding */
option[value="4"], select.p4 { color: #ff6b6b; }
option[value="3"], select.p3 { color: var(--accent2); }
option[value="2"], select.p2 { color: #9ccfff; }
option[value="1"], select.p1 { color: var(--muted); }
option[value="0"], select.p0 { color: #555; }
.quest-flag {
display: flex;
align-items: center;
gap: 5px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 6px;
padding: 5px 9px;
font-size: 0.82rem;
color: var(--muted);
white-space: nowrap;
cursor: pointer;
}
.quest-flag input { margin: 0; cursor: pointer; }
.note-input {
flex: 1 1 160px;
min-width: 120px;
max-width: 260px;
font-size: 0.85rem;
padding: 6px 9px;
}
.map-list {
display: flex;
flex-wrap: wrap;
gap: 4px;
width: 100%;
}
.map-checkbox {
display: flex;
align-items: center;
gap: 5px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 6px;
padding: 4px 8px;
font-size: 0.8rem;
cursor: pointer;
}
.map-checkbox input { margin: 0; cursor: pointer; }
.save-btn {
font-size: 0.82rem;
padding: 6px 12px;
white-space: nowrap;
}
a { color: var(--accent); }
@media (max-width: 720px) {
.key {
grid-template-columns: 48px 1fr;
grid-template-rows: auto auto;
}
.key-controls {
grid-column: 1 / -1;
min-width: unset;
justify-content: flex-start;
}
}
@media (max-width: 480px) {
.key { grid-template-columns: 1fr; }
.key-thumb { width: 48px; height: 48px; }
select, input, button { min-height: 38px; font-size: 0.95rem; }
}
</style>
</head>
<body>
<div class="page">
<nav>
<a href="/">Home</a>
<a href="/keys" class="active">Keys</a>
<a href="/collector">Collector</a>
<a href="/quests">Quests</a>
<a href="/loadout">Loadout</a>
<a href="/meds">Injectors</a>
</nav>
<h1>Key Ratings</h1>
<form method="get" class="filters">
<label for="map_id">Map</label>
<select id="map_id" name="map_id">
<option value="">All maps</option>
{% for map in maps %}
<option value="{{ map.id }}" {% if map_filter == map.id %}selected{% endif %}>
{{ map.name }}
</option>
{% endfor %}
</select>
<label for="show">Show</label>
<select id="show" name="show">
<option value="all" {% if show == "all" %}selected{% endif %}>All</option>
<option value="rated" {% if show == "rated" %}selected{% endif %}>Rated</option>
<option value="unrated" {% if show == "unrated" %}selected{% endif %}>Unrated</option>
<option value="quest" {% if show == "quest" %}selected{% endif %}>Quest keys</option>
</select>
<label for="sort">Sort</label>
<select id="sort" name="sort">
<option value="priority_desc" {% if sort == "priority_desc" %}selected{% endif %}>Priority ↓</option>
<option value="priority_asc" {% if sort == "priority_asc" %}selected{% endif %}>Priority ↑</option>
<option value="name_asc" {% if sort == "name_asc" %}selected{% endif %}>Name AZ</option>
<option value="name_desc" {% if sort == "name_desc" %}selected{% endif %}>Name ZA</option>
</select>
<button type="submit">Apply</button>
</form>
<form method="post" action="/rate_all">
{% if map_filter %}<input type="hidden" name="map_id" value="{{ map_filter }}">{% endif %}
{% if sort %}<input type="hidden" name="sort" value="{{ sort }}">{% endif %}
{% if show %}<input type="hidden" name="show" value="{{ show }}">{% endif %}
<div class="save-all">
<button type="submit" name="save_all" value="1">Save all changes</button>
</div>
{% for key in keys %}
{% set selected_maps = key_maps.get(key.id, []) %}
<div class="key" id="key-{{ key.id }}">
<img class="key-thumb" src="{{ key.grid_image_url }}" loading="lazy" alt="">
<div class="key-info">
<div class="key-title">
<strong>{{ key.name }}</strong>
{% if key.wiki_url %}<a href="{{ key.wiki_url }}" target="_blank">wiki ↗</a>{% endif %}
</div>
{% if selected_maps %}
<div class="map-tags">
{% for map in maps %}
{% if map.id in selected_maps %}
<span class="map-tag">{{ map.name }}</span>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
<div class="key-controls">
<input type="hidden" name="key_ids" value="{{ key.id }}">
<select name="priority_{{ key.id }}" class="priority-select">
<option value="" {% if key.priority is none %}selected{% endif %}>— unrated</option>
{% for i, label in [(0,'IGNORE'),(1,'LOW'),(2,'MED'),(3,'HIGH'),(4,'SUPER')] %}
<option value="{{ i }}" {% if key.priority == i %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<label class="quest-flag" title="Used in a quest?">
<input type="checkbox" name="used_in_quest_{{ key.id }}" {% if key.used_in_quest %}checked{% endif %}>
<span>Quest</span>
</label>
<input class="note-input" name="reason_{{ key.id }}" placeholder="note…" value="{{ key.reason or '' }}">
<div class="map-list">
{% for map in maps %}
<label class="map-checkbox">
<input type="checkbox" name="map_ids_{{ key.id }}" value="{{ map.id }}"
{% if map.id in selected_maps %}checked{% endif %}>
<span>{{ map.name }}</span>
</label>
{% endfor %}
</div>
<button class="save-btn" type="submit" name="save_one" value="{{ key.id }}">Save</button>
</div>
</div>
{% endfor %}
<div class="save-all">
<button type="submit" name="save_all" value="1">Save all changes</button>
</div>
</form>
</div>
</body>
</html>