webs unified

This commit is contained in:
Priec
2026-08-03 13:32:25 +02:00
parent 35d85de556
commit c8afe99d79
59 changed files with 1991 additions and 952 deletions

View File

@@ -0,0 +1,13 @@
{#
Inline status blocks. Imported wherever a form reports its outcome:
{% import "ui/alert.html" as alert %}
{% call alert::error("Could not create the table", message) %}{% endcall %}
#}
{% macro error(title, message) %}
<div class="form-error"><strong>{{ title }}</strong><p>{{ message }}</p></div>
{% endmacro %}
{% macro success(title, message) %}
<div class="form-success"><strong>{{ title }}</strong><p>{{ message }}</p></div>
{% endmacro %}

View File

@@ -0,0 +1,6 @@
{#
Standalone swap target for every form POST — crate::ui::Alert.
Rendered into the page's #submission-status / #login-status div.
#}
{% import "ui/alert.html" as alert %}
{%- if success %}{% call alert::success(title, message) %}{% endcall %}{% else %}{% call alert::error(title, message) %}{% endcall %}{% endif -%}

View File

@@ -0,0 +1,22 @@
{#
The shell every full page extends. A page template overrides `title`,
optionally `head` (extra scripts) and `body_class`, and always `content`.
Every page struct must carry a `nav: crate::ui::Nav` field, because the
navbar component below reads it.
#}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}Komp Accounting{% endblock %} · Komp Accounting</title>
<link rel="stylesheet" href="/static/app.css">
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2/dist/htmx.min.js"></script>
{% block head %}{% endblock %}
</head>
<body>
{% include "ui/navbar.html" %}
{% block content %}{% endblock %}
</body>
</html>

View File

@@ -0,0 +1,14 @@
{# Load failures that are not worth a redirect — crate::ui::ErrorPage #}
{% extends "ui/base.html" %}
{% block title %}{{ heading }}{% endblock %}
{% block content %}
<main>
<div class="error-page">
<h1>{{ heading }}</h1>
<p>{{ message }}</p>
<a href="/admin">Back to the admin panel</a>
</div>
</main>
{% endblock %}

View File

@@ -0,0 +1,17 @@
{#
Card layout shared by every admin form page. A page supplies `eyebrow`,
`heading`, an optional `lead` paragraph, and the `form` itself.
#}
{% extends "ui/base.html" %}
{% block content %}
<main class="form-main">
<a class="back-link" href="/admin">← Admin panel</a>
<section class="form-card">
<p class="eyebrow">{% block eyebrow %}{% endblock %}</p>
<h1>{% block heading %}{% endblock %}</h1>
{% block lead %}{% endblock %}
{% block form %}{% endblock %}
</section>
</main>
{% endblock %}

View File

@@ -0,0 +1,21 @@
{#
Shared navbar, rendered on every page by base.html.
Reads the `nav` field of the surrounding page struct (crate::ui::Nav).
#}
<header class="topbar">
<div>
<strong>Komp Accounting</strong>
{% if !nav.role.is_empty() %}<span class="role">{{ nav.role }}</span>{% endif %}
</div>
<nav>
<a href="/admin" {% if nav.active == "admin" %}class="active"{% endif %}>Admin</a>
<a href="/" {% if nav.active == "analytics" %}class="active"{% endif %}>Analytics</a>
{% if nav.authenticated %}
<form hx-post="/logout" hx-swap="none">
<button class="link-button" type="submit">Log out</button>
</form>
{% else %}
<a href="/login" {% if nav.active == "login" %}class="active"{% endif %}>Login</a>
{% endif %}
</nav>
</header>

View File

@@ -0,0 +1,5 @@
{#
One-line inline notice — crate::ui::Notice. Used where a full alert card is
too heavy: analytics errors and the "log in first" prompts.
#}
<p class="{% if error %}error{% else %}hint{% endif %}">{{ message }}{% if login_link %} Please <a href="/login">log in</a> first.{% endif %}</p>