Files
bin/finance/app/templates/base.html
2026-07-20 11:30:58 +02:00

81 lines
2.9 KiB
HTML

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}Finanzberatung{% endblock %}</title>
<link rel="stylesheet" href="/static/style.css">
<script src="/static/htmx.min.js"></script>
</head>
<body>
<nav>
<a href="/">Übersicht</a>
<a href="/import">Import</a>
<a href="/buchungen">Buchungen</a>
<a href="/salden">Salden</a>
<a href="/planung">Planung</a>
<a href="/admin">Admin</a>
<a href="/hilfe">Hilfe</a>
<a href="http://{{ request.url.hostname or '127.0.0.1' }}:8097" target="_blank" rel="noopener">Grafana</a>
<form method="post" action="/logout">
<button type="submit">Logout</button>
</form>
</nav>
<main>
{% block content %}{% endblock %}
</main>
<script>
document.body.addEventListener('htmx:responseError', function (e) {
alert('Fehler: ' + (e.detail.xhr.responseText || e.detail.xhr.status));
});
// Minimale JSON-Kodierung für htmx-Formulare/Selects, die gegen die JSON-APIs
// (POST/PATCH /api/...) senden. Felder mit data-type="int" werden als Zahl
// kodiert, leere Werte als null, alles andere bleibt String.
htmx.defineExtension('json-form', {
onEvent: function (name, evt) {
if (name === 'htmx:configRequest') {
evt.detail.headers['Content-Type'] = 'application/json';
}
},
encodeParameters: function (xhr, parameters, elt) {
var out = {};
for (var k in parameters) {
var v = parameters[k];
var field = elt.matches && elt.matches('[name="' + k + '"]')
? elt
: elt.querySelector('[name="' + k + '"]');
var kind = field && field.dataset ? field.dataset.type : null;
if (v === '') {
out[k] = null;
} else if (kind === 'int') {
out[k] = parseInt(v, 10);
} else if (kind === 'amount') {
// Deutsche Betragseingabe: "1.234,56" -> "1234.56". Ohne Komma
// bleibt der Wert unveraendert (Punkt-Eingaben funktionieren weiter).
var s = String(v).replace(/[\s€]/g, '');
if (s.indexOf(',') !== -1) {
s = s.replace(/\./g, '').replace(',', '.');
}
out[k] = s;
} else {
out[k] = v;
}
}
// Checkboxen mit data-type="bool" werden unabhaengig vom parameters-Objekt
// ausgelesen, weil unmarkierte Checkboxen beim Serialisieren komplett
// fehlen wuerden (kein Feld => kein "false" moeglich).
if (elt.querySelectorAll) {
elt.querySelectorAll('[data-type="bool"]').forEach(function (field) {
out[field.name] = field.checked;
});
}
xhr.overrideMimeType('text/json');
return JSON.stringify(out);
}
});
</script>
<footer class="version">Finanzberatungs-Tool v{{ app_version }}</footer>
</body>
</html>