UI-Fixes: Wizard konsistent, Tabs uebersetzt/responsive, Set-Zeilen, leere Sets
Image bauen und in die Registry schieben / build (push) Successful in 8s

- Setup-Wizard: feste Mindesthoehe (#setup-gate), Navigation unten
  verankert -> Hoehe springt nicht mehr zwischen den Schritten
- Wizard Benutzer-Anlage: nach Erfolg Bestaetigung statt leerem Formular
  (kein erneutes Eingeben), 'Weiter' aktiv
- Tabs: Labels werden uebersetzt (t()-i18n), Topbar/Tabs horizontal
  scrollbar + kompakter auf Mobil -> 'Einstellungen' wird nicht mehr
  abgeschnitten
- Button-Min-Breite (.btn 96px, .btn-small 64px) fuer Sprach-Konsistenz
- Fortschrittssegmente: bei weissem Akzent auf hellem Theme schwarz
  (statt unsichtbar weiss)
- Set-Zeile: eine horizontale Reihe (nowrap) mit einheitlicher
  Eingabe-Mindestbreite/-hoehe; Grid-Spalten auf 460px angepasst
- Leere Saetze (ohne Gewicht UND Reps) werden nicht mehr persistiert und
  im Verlauf ausgeblendet (kein 'empty kg x empty reps'-Wand)
- Tests: 158 Checks gruen (39+18+43+32+26)
This commit is contained in:
AI-Agent committed 2026-10-02 19:16:52 +00:00
1 parent e91cd30479
commit 0ebaa8b132
2 files changed
+60 -20

No files matched your search

+30 -16
View File
@@ -152,6 +152,7 @@ const LANG = {
reorder_hint: "Übungen per Ziehen sortieren",
prev_week: "Vorige Woche", next_week: "Nächste Woche", week_of: "Woche vom",
wizard_done: "Alles erledigt - die App ist bereit.",
wizard_user_created: "Benutzer '{u}' angelegt. Weiter mit 'Weiter'.",
logged_in: "Angemeldet.", user_created_toast: "Benutzer angelegt.",
app_load_fail: "App konnte nicht geladen werden: {m}",
},
@@ -261,6 +262,7 @@ const LANG = {
reorder_hint: "Drag to reorder exercises",
prev_week: "Previous week", next_week: "Next week", week_of: "Week of",
wizard_done: "All done - the app is ready.",
wizard_user_created: "User '{u}' created. Continue with 'Next'.",
logged_in: "Logged in.", user_created_toast: "User created.",
app_load_fail: "Could not load the app: {m}",
},
@@ -1033,7 +1035,7 @@ async function flushAutosave(activity) {
const sets = (model.exercises[exKey] || []).map((e, i) => ({
exercise: exKey, sort: i, weight: e.weight || "", reps: e.reps || "",
done: e.done ? 1 : 0,
}));
})).filter(s => s.weight !== "" || s.reps !== "");
try {
await api("/api/sessions/" + model.id, jsonOpts("PATCH", { sets }));
model.dirtyEx.delete(exKey);
@@ -1262,9 +1264,11 @@ function renderSetSummary(s, a) {
for (const e of s.entries || []) (byEx[e.exercise] = byEx[e.exercise] || []).push(e);
for (const exKey of Object.keys(byEx)) {
const li = el("li", "hist-entry");
const sorted = byEx[exKey].sort((x, y) => x.sort - y.sort)
.filter(e => e.weight || e.reps);
if (!sorted.length) continue;
li.appendChild(el("span", "ex-name", exKey + ": "));
const setsWrap = el("span", "hist-sets");
const sorted = byEx[exKey].sort((x, y) => x.sort - y.sort);
sorted.forEach((e, idx) => {
const w = e.weight || t("empty_label");
const r = e.reps || t("empty_label");
@@ -1751,20 +1755,26 @@ function renderWizardStep() {
grid.appendChild(solo);
box.appendChild(grid);
if (wizard.multi === true) {
const form = el("form", "auth-form");
form.appendChild(authField(t("username"), "setup-user"));
form.appendChild(authField(t("password"), "setup-pass"));
const err = el("div", "auth-error", "");
err.hidden = true;
const submit = el("button", "btn btn-primary btn-block", t("first_user"));
submit.type = "submit";
form.appendChild(submit);
form.appendChild(err);
form.addEventListener("submit", ev => {
ev.preventDefault();
wizardRegister($("#setup-user").value, $("#setup-pass").value, err);
});
box.appendChild(form);
if (wizard.userCreated && app.me && app.me.username) {
const ok = el("div", "auth-register",
t("wizard_user_created", { u: app.me.username }));
box.appendChild(ok);
} else {
const form = el("form", "auth-form");
form.appendChild(authField(t("username"), "setup-user"));
form.appendChild(authField(t("password"), "setup-pass"));
const err = el("div", "auth-error", "");
err.hidden = true;
const submit = el("button", "btn btn-primary btn-block", t("first_user"));
submit.type = "submit";
form.appendChild(submit);
form.appendChild(err);
form.addEventListener("submit", ev => {
ev.preventDefault();
wizardRegister($("#setup-user").value, $("#setup-pass").value, err);
});
box.appendChild(form);
}
}
} else {
// Letzter Schritt: Darstellung (Theme + OLED + Akzent)
@@ -2328,6 +2338,10 @@ async function loadAppData() {
app.cfg = await api("/api/config");
app.settings = await api("/api/settings");
applySettings(app.settings);
for (const tab of $$(".tab")) {
const key = "tab_" + tab.dataset.view;
if (LANG[lang()][key]) tab.textContent = t(key);
}
$("#today-label").textContent = t("today_header") + fmtDateLong(app.meta.today);
setUserChip();
await loadToday();