UI-Ueberarbeitung: responsives Grid, konsistente Buttons, Wizard-Breite, Kontrast

- Uebungen in responsivem Grid (2-3 Spalten auf Desktop, 1 Spalte mobil)
- Setup-Modal feste Breite 640px (capped am Viewport) - kein Sprung beim
  Sprachwechsel
- Button-Konsistenz: .btn-primary nutzt --accent-border (weisser Akzent
  bekommt sichtbare graue Umrandung, auch auf hellem Theme); Secondary =
  transparent/dunkelgrau
- Fortschrittssegmente: groesser (40x6, gap 8); Semantik wie gewuenscht -
  erledigt = voll gefuellt, aktuell = nur Umrandung, kommend = graue
  Umrandung
- Session-Kopf: 'Alles zuruecksetzen' + 'Session abschliessen' gebuendelt,
  'Verwerfen' abgesetzt und bestaetigungsgeschuetzt
- Wizard: Appearance-Untertitel korrigiert (nicht mehr 'default accent'),
  Sprach-Buttons mit mehr Abstand
- Settings: Formular-Zeilen ausgerichtet (Inputs gestreckt, Button rechts),
  muted heller (bessere Lesbarkeit), Checkbox groesser
- Tests: 158 Checks gruen (39+18+43+32+26)
This commit is contained in:
AI-Agent committed 2026-10-02 00:17:00 +00:00
1 parent a2c4fdc1bd
commit ba599fcbf5
2 files changed
+75 -33

No files matched your search

+22 -16
View File
@@ -141,6 +141,7 @@ const LANG = {
system: "System",
oled_toggle: "OLED-Dark",
oled_desc: "Reines Schwarz für den dunklen Modus.",
appearance_desc: "Theme, Akzentfarbe und OLED-Dark für deine App.",
last_workout: "Letztes Training vorbefüllen",
last_workout_desc: "Neue Session startet mit dem letzten abgeschlossenen Workout der Kategorie (nur ausgefüllte Sätze).",
plan_prefill: "Plan-Gewichte vorbefüllen",
@@ -249,6 +250,7 @@ const LANG = {
system: "System",
oled_toggle: "OLED dark",
oled_desc: "Pure black for the dark mode.",
appearance_desc: "Theme, accent color and OLED dark for your app.",
last_workout: "Prefill last workout",
last_workout_desc: "New sessions start with the last completed workout of the category (only filled sets).",
plan_prefill: "Prefill plan weights",
@@ -594,12 +596,15 @@ function renderStrengthSession(card, a, model) {
}
const dayKeys = day.exercises.map(x => x.key);
const grid = el("div", "ex-grid");
model.exGrid = grid;
card.appendChild(grid);
for (const k of model.exKeys) {
const ex = model.exByKey[k] || {
key: k, name: k, sets: { count: 0 }, target: "", startKg: "",
info: "", tags: [],
};
card.appendChild(buildExBlock(a, model, ex, !dayKeys.includes(k)));
grid.appendChild(buildExBlock(a, model, ex, !dayKeys.includes(k)));
}
}
@@ -668,20 +673,23 @@ function sessionHead(a, model, dayTitle, day) {
noteBox.appendChild(noteInput);
head.appendChild(noteBox);
const actions = el("div", "session-actions");
if (a.type === "strength") {
const resetAll = el("button", "btn btn-small", t("reset_all"));
resetAll.type = "button";
resetAll.title = t("reset_all_title");
resetAll.addEventListener("click", () => resetAllSets(a, model));
head.appendChild(resetAll);
actions.appendChild(resetAll);
}
const fin = el("button", "btn btn-primary", t("finish_session"));
fin.type = "button";
fin.addEventListener("click", () => finishSession(a, model));
head.appendChild(fin);
actions.appendChild(fin);
head.appendChild(actions);
head.appendChild(discardBtn(a, model));
const disc = discardBtn(a, model);
disc.classList.add("session-discard");
head.appendChild(disc);
return head;
}
@@ -720,8 +728,8 @@ function addExercise(a, model, exKey) {
const count = cfg.list ? cfg.list.length : (cfg.count || 1);
model.exercises[exKey] = Array.from({ length: count },
() => ({ id: null, weight: "", reps: "", done: 0 }));
const card = app.cards[model.activity];
if (card) card.appendChild(buildExBlock(a, model, ex, true));
const target = model.exGrid || app.cards[model.activity];
if (target) target.appendChild(buildExBlock(a, model, ex, true));
model.dirtyEx.add(exKey);
scheduleAutosave(model);
}
@@ -746,10 +754,10 @@ function reorderExercise(a, model, fromKey, toKey) {
if (from < 0 || to < 0) return;
keys.splice(from, 1);
keys.splice(to, 0, fromKey);
const card = app.cards[model.activity];
if (card) {
const target = model.exGrid || app.cards[model.activity];
if (target) {
const blocks = keys.map(k => model.exBlocks[k]).filter(Boolean);
for (const b of blocks) card.appendChild(b);
for (const b of blocks) target.appendChild(b);
}
model.fields = Object.assign({}, model.fields, { exerciseOrder: keys.slice() });
model.metaDirty = true;
@@ -1761,9 +1769,7 @@ function renderWizardStep() {
} else {
// Letzter Schritt: Darstellung (Theme + OLED + Akzent)
box.appendChild(el("h3", "wizard-title", t("appearance")));
if (wizard.mode === "setup") {
box.appendChild(el("p", "auth-sub", t("color_server")));
}
box.appendChild(el("p", "auth-sub", t("appearance_desc")));
box.appendChild(el("div", "picker-label", t("theme_label")));
const themeRow = el("div", "day-picker");
for (const [key, label] of [["dark", t("dark")], ["system", t("system")], ["light", t("light")]]) {
@@ -2110,7 +2116,7 @@ function renderAccountSection() {
sec.appendChild(el("h3", "", t("account")));
const body = el("div", "data-body");
body.appendChild(el("p", "", t("account_desc", { u: app.me.username })));
const row = el("div", "data-row");
const row = el("div", "form-row");
const cur = el("input", "file-input");
cur.type = "password";
cur.placeholder = t("current_pw");
@@ -2147,7 +2153,7 @@ function renderSetupUsersSection() {
sec.appendChild(el("h3", "", t("setup_users")));
const body = el("div", "data-body");
body.appendChild(el("p", "", t("users_solo_desc")));
const row = el("div", "data-row");
const row = el("div", "form-row");
const name = el("input", "file-input");
name.type = "text";
name.placeholder = t("username");
@@ -2247,7 +2253,7 @@ function renderOwnerUsersSection() {
}
};
reload();
const row = el("div", "data-row");
const row = el("div", "form-row");
const name = el("input", "file-input");
name.type = "text";
name.placeholder = t("username");