Files
ti/templates/analyse.html

285 lines
12 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="da">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Citti Analyse — Uge 23-25</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: #f5f2ed; --card: #ffffff; --border: #e2ddd6; --text: #1a1814;
--muted: #8a857c; --accent: #c84b2f; --green: #2d6a4f; --green-light: #e8f4ee;
--amber: #92580a; --amber-light: #fef3e2; --blue: #1d4e89; --blue-light: #e8f0f9;
--red-light: #fde8e3;
--mono: 'DM Mono', monospace; --sans: 'DM Sans', sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: var(--sans); background: var(--bg); color: var(--text); font-size: 15px; line-height: 1.5; padding: 1.5rem 1rem 4rem; }
.page { max-width: 860px; margin: 0 auto; }
header { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; padding-bottom: 1.25rem; border-bottom: 2px solid var(--text); }
h1 { font-size: 1.75rem; font-weight: 600; letter-spacing: -0.03em; }
h1 span { color: var(--accent); }
.btn-back { background: var(--text); color: white; border: none; border-radius: 8px; padding: 8px 14px; font-size: 13px; font-family: var(--sans); cursor: pointer; text-decoration: none; display: inline-block; font-weight: 500; }
.kpi-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 1.5rem; }
.kpi { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 1rem; }
.kpi-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px; }
.kpi-val { font-size: 1.75rem; font-weight: 600; font-family: var(--mono); letter-spacing: -0.02em; }
.kpi-val.green { color: var(--green); }
.kpi-val.red { color: var(--accent); }
.kpi-sub { font-size: 11px; color: var(--muted); margin-top: 2px; }
/* Category table */
.card { background: var(--card); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; margin-bottom: 1.5rem; }
.card-title { background: var(--text); color: white; padding: 0.6rem 1rem; font-size: 12px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { padding: 6px 12px; font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 500; text-align: left; background: #f0ece6; border-bottom: 1px solid var(--border); }
th.num { text-align: right; }
td { padding: 8px 12px; border-bottom: 1px solid var(--border); }
td.num { text-align: right; font-family: var(--mono); }
tr:last-child td { border-bottom: none; }
tr.total-row td { font-weight: 600; background: #faf9f7; border-top: 2px solid var(--border); }
.diff-pos { color: var(--accent); font-weight: 500; }
.diff-neg { color: var(--green); font-weight: 500; }
.no-data { color: var(--muted); font-style: italic; font-size: 12px; }
/* Bar chart */
.bar-wrap { padding: 1rem; }
.bar-row { display: grid; grid-template-columns: 140px 1fr 70px; align-items: center; gap: 10px; margin-bottom: 8px; }
.bar-label { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-track { background: #e8f4ee; border-radius: 4px; height: 10px; overflow: hidden; }
.bar-fill { height: 100%; border-radius: 4px; background: var(--green); transition: width 0.6s ease; }
.bar-fill.over { background: var(--accent); }
.bar-val { font-size: 11px; font-family: var(--mono); color: var(--muted); text-align: right; }
/* Item details */
.items-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; padding: 1rem; }
.item-card { border: 1px solid var(--border); border-radius: 8px; padding: 0.75rem; background: var(--bg); }
.item-card-name { font-size: 13px; font-weight: 500; margin-bottom: 4px; }
.item-card-prices { display: flex; gap: 12px; font-size: 12px; }
.item-card-est { color: var(--muted); font-family: var(--mono); }
.item-card-actual { color: var(--green); font-family: var(--mono); font-weight: 600; }
.item-card-diff { font-size: 11px; margin-top: 2px; }
/* Extra items grid */
.extras-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; padding: 1rem; }
.extra-card { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: white; }
.extra-card img { width: 100%; height: 120px; object-fit: cover; display: block; }
.extra-card-no-photo { width: 100%; height: 120px; background: var(--bg); display: flex; align-items: center; justify-content: center; font-size: 40px; }
.extra-card-body { padding: 0.6rem 0.75rem; }
.extra-card-name { font-size: 13px; font-weight: 500; }
.extra-card-price { font-size: 16px; font-weight: 600; font-family: var(--mono); color: var(--accent); margin-top: 2px; }
.extra-card-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }
.empty-state { padding: 2rem; text-align: center; color: var(--muted); font-size: 14px; }
@media (max-width: 600px) {
.kpi-row { grid-template-columns: repeat(2, 1fr); }
.bar-row { grid-template-columns: 90px 1fr 60px; }
}
</style>
</head>
<body>
<div class="page">
<header>
<div>
<h1>Citti <span>Analyse</span></h1>
<div style="font-size:12px;color:var(--muted);margin-top:4px">Uge 2325 · 03.0623.06.2026</div>
</div>
<a href="/" class="btn-back">← Indkøbsseddel</a>
</header>
{% set total_actual = total_actual or 0 %}
{% set total_est = total_est or 4065 %}
{% set diff = total_actual - total_est if total_actual else 0 %}
{% set pct = ((diff / total_est) * 100) if total_est else 0 %}
<div class="kpi-row">
<div class="kpi">
<div class="kpi-label">Faktisk betalt (Citti)</div>
{% if total_actual %}
<div class="kpi-val">{{ "{:,.0f}".format(total_actual).replace(",",".") }}</div>
<div class="kpi-sub">kr. registreret</div>
{% else %}
<div class="kpi-val" style="color:var(--muted)"></div>
<div class="kpi-sub">ingen priser indtastet endnu</div>
{% endif %}
</div>
<div class="kpi">
<div class="kpi-label">Estimeret</div>
<div class="kpi-val">{{ "{:,.0f}".format(total_est).replace(",",".") }}</div>
<div class="kpi-sub">kr. planlagt</div>
</div>
<div class="kpi">
<div class="kpi-label">Difference</div>
{% if total_actual %}
<div class="kpi-val {% if diff > 0 %}red{% else %}green{% endif %}">
{% if diff > 0 %}+{% endif %}{{ "{:,.0f}".format(diff).replace(",",".") }}
</div>
<div class="kpi-sub">kr. ({{ "{:+.1f}".format(pct) }}%)</div>
{% else %}
<div class="kpi-val" style="color:var(--muted)"></div>
<div class="kpi-sub">-</div>
{% endif %}
</div>
</div>
<!-- KATEGORI OVERSIGT -->
<div class="card">
<div class="card-title">Kategorioversigt</div>
<table>
<thead>
<tr>
<th>Kategori</th>
<th class="num">Estimat</th>
<th class="num">Faktisk</th>
<th class="num">Difference</th>
</tr>
</thead>
<tbody>
{% for r in rows %}
<tr>
<td>{{ r.emoji }} {{ r.title }}</td>
<td class="num">{{ "{:,.0f}".format(r.est).replace(",",".") }}</td>
<td class="num">{% if r.actual %}{{ "{:,.0f}".format(r.actual).replace(",",".") }}{% else %}<span class="no-data"></span>{% endif %}</td>
<td class="num">
{% if r.diff is not none %}
<span class="{{ 'diff-pos' if r.diff > 0 else 'diff-neg' }}">
{% if r.diff > 0 %}+{% endif %}{{ "{:,.0f}".format(r.diff).replace(",",".") }}
</span>
{% else %}
<span class="no-data"></span>
{% endif %}
</td>
</tr>
{% endfor %}
<tr class="total-row">
<td>Total Citti</td>
<td class="num">{{ "{:,.0f}".format(total_est).replace(",",".") }}</td>
<td class="num">{% if total_actual %}{{ "{:,.0f}".format(total_actual).replace(",",".") }}{% else %}—{% endif %}</td>
<td class="num">
{% if total_actual %}
<span class="{{ 'diff-pos' if diff > 0 else 'diff-neg' }}">
{% if diff > 0 %}+{% endif %}{{ "{:,.0f}".format(diff).replace(",",".") }}
</span>
{% else %}—{% endif %}
</td>
</tr>
</tbody>
</table>
</div>
<!-- STABDIAGRAM -->
{% if total_actual %}
<div class="card">
<div class="card-title">Faktisk vs. estimat per kategori</div>
<div class="bar-wrap">
{% for r in rows %}
{% if r.actual %}
{% set pct_bar = [((r.actual / r.est) * 100), 100]|min if r.est else 0 %}
<div class="bar-row">
<div class="bar-label" title="{{ r.title }}">{{ r.emoji }} {{ r.title.split('·')[0].strip() }}</div>
<div class="bar-track">
<div class="bar-fill {% if r.actual > r.est %}over{% endif %}" style="width:{{ pct_bar }}%"></div>
</div>
<div class="bar-val">{{ "{:,.0f}".format(r.actual).replace(",",".") }} / {{ "{:,.0f}".format(r.est).replace(",",".") }}</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
<!-- VARE-DETALJER -->
<div class="card">
<div class="card-title">Alle varer — est. vs. faktisk</div>
{% set has_items = saved|length > 0 %}
{% if has_items %}
<div class="items-grid">
{% for sec in sections %}
{% for item in sec.varer %}
{% set s = saved.get(item.key, {}) %}
{% if s.get('price') %}
{% set diff_item = s.price - item.est %}
<div class="item-card">
<div class="item-card-name">{{ item.name }}</div>
<div class="item-card-prices">
<span class="item-card-est">est. {{ "{:.0f}".format(item.est) }}</span>
<span class="item-card-actual">→ {{ "{:.0f}".format(s.price) }} kr.</span>
</div>
<div class="item-card-diff {% if diff_item > 2 %}diff-pos{% elif diff_item < -2 %}diff-neg{% endif %}">
{% if diff_item > 0.5 %}+{{ "{:.0f}".format(diff_item) }} kr. dyrere{% elif diff_item < -0.5 %}{{ "{:.0f}".format(diff_item) }} kr. billigere{% else %}som estimat{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% else %}
<div class="empty-state">Ingen priser registreret endnu.</div>
{% endif %}
</div>
<!-- EKSTRA VARER -->
<div class="card">
<div class="card-title">Ekstra varer tilføjet i butikken ({{ extras|length }})</div>
{% if extras %}
<div class="extras-grid">
{% for e in extras %}
<div class="extra-card">
{% if e.photo %}
<img src="/uploads/{{ e.photo }}" alt="{{ e.name }}">
{% else %}
<div class="extra-card-no-photo">📦</div>
{% endif %}
<div class="extra-card-body">
<div class="extra-card-name">{{ e.name }}</div>
{% if e.price %}<div class="extra-card-price">{{ "{:.2f}".format(e.price).replace(".",",") }} kr.</div>{% endif %}
<div class="extra-card-meta">
{% if e.category %}{{ e.category }}{% endif %}
{% if e.note %} · {{ e.note }}{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="empty-state">Ingen ekstra varer tilføjet.</div>
{% endif %}
</div>
{% if extras %}
<div class="card">
<div class="card-title">Ekstra varer — prissammenfatning</div>
<table>
<thead>
<tr><th>Vare</th><th>Kategori</th><th class="num">Pris</th><th>Note</th></tr>
</thead>
<tbody>
{% set extra_total = namespace(v=0) %}
{% for e in extras %}
<tr>
<td>{{ e.name }}</td>
<td style="color:var(--muted);font-size:12px">{{ e.category or '—' }}</td>
<td class="num">{% if e.price %}{{ "{:.2f}".format(e.price).replace(".",",") }}{% else %}—{% endif %}</td>
<td style="color:var(--muted);font-size:12px">{{ e.note or '' }}</td>
</tr>
{% if e.price %}{% set extra_total.v = extra_total.v + e.price %}{% endif %}
{% endfor %}
{% if extra_total.v > 0 %}
<tr class="total-row">
<td colspan="2">Total ekstra</td>
<td class="num">{{ "{:.2f}".format(extra_total.v).replace(".",",") }}</td>
<td></td>
</tr>
{% endif %}
</tbody>
</table>
</div>
{% endif %}
</div>
</body>
</html>