Files
pysatcalc/templates/index.html

141 lines
5.7 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Satisfactory Production Calculator</title>
<style>
:root { --bg: #0f172a; --card: #111827; --text: #e5e7eb; --muted:#94a3b8; --accent:#22d3ee; --ok:#4ade80; }
* { box-sizing: border-box; }
body { margin:0; font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; background: var(--bg); color: var(--text); }
.container { max-width: 960px; margin: 0 auto; padding: 24px; }
h1 { font-size: 1.75rem; margin: 0 0 8px; }
p { color: var(--muted); margin-top: 0; }
.card { background: var(--card); border: 1px solid #1f2937; border-radius: 10px; padding: 16px; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 800px) { .row { grid-template-columns: 1fr; } }
label { display:block; margin-bottom:8px; font-weight:600; }
select, input[type=number] { width: 100%; padding: 10px 12px; border-radius: 8px; border: 1px solid #334155; background: #0b1220; color: var(--text); }
button { padding: 10px 14px; border: 0; border-radius: 8px; background: var(--accent); color: #012b30; font-weight: 700; cursor: pointer; }
button:hover { filter: brightness(1.08); }
.mt { margin-top: 16px; }
.error { color: #fda4af; background: #451a1a; border: 1px solid #7f1d1d; padding: 10px; border-radius: 8px; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #1f2937; vertical-align: top; }
th { color: var(--muted); font-weight: 600; }
code { color: var(--accent); }
.mono { font-variant-numeric: tabular-nums; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.pill { display:inline-block; padding:2px 8px; border-radius: 999px; background:#0b1220; border:1px solid #334155; color: var(--muted); font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<h1>Satisfactory Production Calculator</h1>
<p>Compute buildings and raw inputs for a target output rate (items per minute). Data set includes a few early-game default recipes; you can extend it in <code>main.py</code>.</p>
<form class="card" method="get">
<div class="row">
<div>
<label for="item">Product</label>
<select id="item" name="item" required>
{% for it in items %}
<option value="{{ it }}" {% if selected_item and it==selected_item %}selected{% endif %}>{{ it }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="rate">Target rate (items/min)</label>
<input id="rate" name="rate" type="number" step="0.01" min="0" value="{{ selected_rate }}" required>
</div>
</div>
<div class="mt">
<button type="submit">Calculate</button>
</div>
{% if error %}
<div class="mt error">{{ error }}</div>
{% endif %}
</form>
{% if result %}
<div class="mt card">
<h2 style="margin-top:0">Results</h2>
<h3>Raw resource requirements</h3>
{% if result.raw %}
<table>
<thead>
<tr><th>Item</th><th class="mono">Rate (items/min)</th></tr>
</thead>
<tbody>
{% for item,rate in result.raw.items() %}
<tr>
<td>{{ item }}</td>
<td class="mono">{{ '%.2f'|format(rate) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="pill">No raw resources required (target is a raw resource).</p>
{% endif %}
<h3 class="mt">Production steps</h3>
{% if result.steps %}
<table>
<thead>
<tr>
<th>Output Item</th>
<th>Recipe</th>
<th>Building</th>
<th class="mono">Target rate</th>
<th class="mono">Per-building output</th>
<th class="mono">Buildings</th>
<th class="mono">Utilization</th>
</tr>
</thead>
<tbody>
{% for s in result.steps %}
<tr>
<td>{{ s.item }}</td>
<td>{{ s.recipe }}</td>
<td>{{ s.building }}</td>
<td class="mono">{{ '%.2f'|format(s.target_rate) }}</td>
<td class="mono">{{ '%.2f'|format(s.per_building_output) }}</td>
<td class="mono">{{ '%.2f'|format(s.buildings_float) }} (~ {{ s.buildings }})</td>
<td class="mono">{{ '%.1f'|format(s.utilization*100) }}%</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="pill">No production steps (target is a raw resource).</p>
{% endif %}
<h3 class="mt">Unused byproducts</h3>
{% if result.unused and result.unused|length > 0 %}
<table>
<thead>
<tr><th>Item</th><th class="mono">Unused rate (items/min)</th></tr>
</thead>
<tbody>
{% for item,rate in result.unused.items() %}
<tr>
<td>{{ item }}</td>
<td class="mono">{{ '%.2f'|format(rate) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="pill">No unused byproducts for this target.</p>
{% endif %}
</div>
{% endif %}
</div>
<script>
// Tiny helper to maintain selected item after submit if not handled by server
// (we already set it via Jinja, this is just progressive enhancement)
</script>
</body>
</html>