Add bilingual UI and improve event actions layout

Add persistent German/English switching, translated UI messages and English 12-hour times. Align desktop event actions while preserving mobile layouts and record bilingual project guidance.

Include pending diary deletion exclusions. Validate both languages with nine tests.
This commit is contained in:
kai
2026-09-14 15:31:56 +02:00
parent b2af6c6857
commit b2af866cf0
28 changed files with 1339 additions and 506 deletions
+13 -11
View File
@@ -1,9 +1,9 @@
<!DOCTYPE html>
<html lang="de">
<html lang="{{ language() }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Patch-Bilder · MetalCircle</title>
<title>{{ _('Patch-Bilder · MetalCircle') }}</title>
<link rel="icon" type="image/png" href="/static/images/metalcircle-circle.png">
<link rel="stylesheet" href="/static/css/style.css">
<style>
@@ -18,28 +18,30 @@
.patch-upload { display: grid; gap: 8px; }
.patch-upload-status { min-height: 1.2em; color: var(--muted); font-size: .85rem; }
</style>
<link rel="stylesheet" href="/static/css/language.css">
</head>
<body>
<header><div class="header-inner"><a href="/" class="logo"><img class="brand-logo" src="/static/images/metalcircle-full.png" alt="MetalCircle"></a>{% include '_user_menu.html' %}</div></header>
<header><div class="header-inner"><a href="/" class="logo"><img class="brand-logo" src="/static/images/metalcircle-full.png" alt="MetalCircle"></a>{% include '_user_menu.html' %}</div> {% include '_language_switch.html' %}
</header>
<main>
<div class="page-title"><h1>🧵 Patch-Bilder</h1><p>Grafiken für die Patches auf der virtuellen Kutte verwalten.</p></div>
<div class="page-title"><h1>{{ _('🧵 Patch-Bilder') }}</h1><p>{{ _('Grafiken für die Patches auf der virtuellen Kutte verwalten.') }}</p></div>
{% set admin_section = 'patches' %}{% include '_admin_nav.html' %}
<section class="admin-section">
<div class="patch-admin-groups">
{% for group in patch_groups %}
<details class="patch-admin-group">
<summary>{{ group.label }} · {{ group.patches|length }}</summary>
<summary>{{ group.label | t }} · {{ group.patches|length }}</summary>
<div class="patch-admin-grid">
{% for patch in group.patches %}
<article class="admin-row patch-admin-card">
{% if patch.image_path %}<img class="patch-preview" src="{{ patch.image_path }}" alt="{{ patch.name }}">{% else %}<div class="patch-preview patch-placeholder">{{ patch.icon }}</div>{% endif %}
<div><strong>{{ patch.name }}</strong><div class="admin-meta">{{ patch.description }} · {{ patch.code }}</div></div>
{% if patch.image_path %}<img class="patch-preview" src="{{ patch.image_path }}" alt="{{ patch.name | t }}">{% else %}<div class="patch-preview patch-placeholder">{{ patch.icon }}</div>{% endif %}
<div><strong>{{ patch.name | t }}</strong><div class="admin-meta">{{ patch.description | t }} · {{ patch.code }}</div></div>
<form class="patch-upload" method="post" action="/admin/patches/{{ patch.code }}" enctype="multipart/form-data">
<input type="file" name="image" accept="image/jpeg,image/png,image/webp" required>
<span class="patch-upload-status">Das Bild wird vor dem Upload automatisch optimiert.</span>
<button class="button" type="submit">{% if patch.image_path %}Bild ersetzen{% else %}Bild hochladen{% endif %}</button>
<span class="patch-upload-status">{{ _('Das Bild wird vor dem Upload automatisch optimiert.') }}</span>
<button class="button" type="submit">{% if patch.image_path %}{{ _('Bild ersetzen') }}{% else %}{{ _('Bild hochladen') }}{% endif %}</button>
</form>
{% if patch.image_path %}<form method="post" action="/admin/patches/{{ patch.code }}/delete" onsubmit="return confirm('Patch-Bild entfernen und wieder das Symbol verwenden?');"><button class="admin-danger" type="submit">Bild entfernen</button></form>{% endif %}
{% if patch.image_path %}<form method="post" action="/admin/patches/{{ patch.code }}/delete" onsubmit="return confirm({{ _('Patch-Bild entfernen und wieder das Symbol verwenden?') | tojson | forceescape }});"><button class="admin-danger" type="submit">{{ _('Bild entfernen') }}</button></form>{% endif %}
</article>
{% endfor %}
</div>
@@ -99,7 +101,7 @@ patchForms.forEach(form => {
form.requestSubmit();
} catch (error) {
console.error("Patch image optimization failed:", error);
status.textContent = "Das Bild konnte nicht optimiert werden. Bitte ein kleineres JPG, PNG oder WebP wählen.";
status.textContent = {{ _('Das Bild konnte nicht optimiert werden. Bitte ein kleineres JPG, PNG oder WebP wählen.') | tojson }};
button.disabled = false;
}
});