UI-Fixes: Wizard konsistent, Tabs uebersetzt/responsive, Set-Zeilen, leere Sets
Image bauen und in die Registry schieben / build (push) Successful in 8s
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:
1 parent
e91cd30479
commit
0ebaa8b132
2 files changed
+60
-20
No files matched your search
@@ -152,6 +152,7 @@ const LANG = {
|
|||||||
reorder_hint: "Übungen per Ziehen sortieren",
|
reorder_hint: "Übungen per Ziehen sortieren",
|
||||||
prev_week: "Vorige Woche", next_week: "Nächste Woche", week_of: "Woche vom",
|
prev_week: "Vorige Woche", next_week: "Nächste Woche", week_of: "Woche vom",
|
||||||
wizard_done: "Alles erledigt - die App ist bereit.",
|
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.",
|
logged_in: "Angemeldet.", user_created_toast: "Benutzer angelegt.",
|
||||||
app_load_fail: "App konnte nicht geladen werden: {m}",
|
app_load_fail: "App konnte nicht geladen werden: {m}",
|
||||||
},
|
},
|
||||||
@@ -261,6 +262,7 @@ const LANG = {
|
|||||||
reorder_hint: "Drag to reorder exercises",
|
reorder_hint: "Drag to reorder exercises",
|
||||||
prev_week: "Previous week", next_week: "Next week", week_of: "Week of",
|
prev_week: "Previous week", next_week: "Next week", week_of: "Week of",
|
||||||
wizard_done: "All done - the app is ready.",
|
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.",
|
logged_in: "Logged in.", user_created_toast: "User created.",
|
||||||
app_load_fail: "Could not load the app: {m}",
|
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) => ({
|
const sets = (model.exercises[exKey] || []).map((e, i) => ({
|
||||||
exercise: exKey, sort: i, weight: e.weight || "", reps: e.reps || "",
|
exercise: exKey, sort: i, weight: e.weight || "", reps: e.reps || "",
|
||||||
done: e.done ? 1 : 0,
|
done: e.done ? 1 : 0,
|
||||||
}));
|
})).filter(s => s.weight !== "" || s.reps !== "");
|
||||||
try {
|
try {
|
||||||
await api("/api/sessions/" + model.id, jsonOpts("PATCH", { sets }));
|
await api("/api/sessions/" + model.id, jsonOpts("PATCH", { sets }));
|
||||||
model.dirtyEx.delete(exKey);
|
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 e of s.entries || []) (byEx[e.exercise] = byEx[e.exercise] || []).push(e);
|
||||||
for (const exKey of Object.keys(byEx)) {
|
for (const exKey of Object.keys(byEx)) {
|
||||||
const li = el("li", "hist-entry");
|
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 + ": "));
|
li.appendChild(el("span", "ex-name", exKey + ": "));
|
||||||
const setsWrap = el("span", "hist-sets");
|
const setsWrap = el("span", "hist-sets");
|
||||||
const sorted = byEx[exKey].sort((x, y) => x.sort - y.sort);
|
|
||||||
sorted.forEach((e, idx) => {
|
sorted.forEach((e, idx) => {
|
||||||
const w = e.weight || t("empty_label");
|
const w = e.weight || t("empty_label");
|
||||||
const r = e.reps || t("empty_label");
|
const r = e.reps || t("empty_label");
|
||||||
@@ -1751,20 +1755,26 @@ function renderWizardStep() {
|
|||||||
grid.appendChild(solo);
|
grid.appendChild(solo);
|
||||||
box.appendChild(grid);
|
box.appendChild(grid);
|
||||||
if (wizard.multi === true) {
|
if (wizard.multi === true) {
|
||||||
const form = el("form", "auth-form");
|
if (wizard.userCreated && app.me && app.me.username) {
|
||||||
form.appendChild(authField(t("username"), "setup-user"));
|
const ok = el("div", "auth-register",
|
||||||
form.appendChild(authField(t("password"), "setup-pass"));
|
t("wizard_user_created", { u: app.me.username }));
|
||||||
const err = el("div", "auth-error", "");
|
box.appendChild(ok);
|
||||||
err.hidden = true;
|
} else {
|
||||||
const submit = el("button", "btn btn-primary btn-block", t("first_user"));
|
const form = el("form", "auth-form");
|
||||||
submit.type = "submit";
|
form.appendChild(authField(t("username"), "setup-user"));
|
||||||
form.appendChild(submit);
|
form.appendChild(authField(t("password"), "setup-pass"));
|
||||||
form.appendChild(err);
|
const err = el("div", "auth-error", "");
|
||||||
form.addEventListener("submit", ev => {
|
err.hidden = true;
|
||||||
ev.preventDefault();
|
const submit = el("button", "btn btn-primary btn-block", t("first_user"));
|
||||||
wizardRegister($("#setup-user").value, $("#setup-pass").value, err);
|
submit.type = "submit";
|
||||||
});
|
form.appendChild(submit);
|
||||||
box.appendChild(form);
|
form.appendChild(err);
|
||||||
|
form.addEventListener("submit", ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
wizardRegister($("#setup-user").value, $("#setup-pass").value, err);
|
||||||
|
});
|
||||||
|
box.appendChild(form);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Letzter Schritt: Darstellung (Theme + OLED + Akzent)
|
// Letzter Schritt: Darstellung (Theme + OLED + Akzent)
|
||||||
@@ -2328,6 +2338,10 @@ async function loadAppData() {
|
|||||||
app.cfg = await api("/api/config");
|
app.cfg = await api("/api/config");
|
||||||
app.settings = await api("/api/settings");
|
app.settings = await api("/api/settings");
|
||||||
applySettings(app.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);
|
$("#today-label").textContent = t("today_header") + fmtDateLong(app.meta.today);
|
||||||
setUserChip();
|
setUserChip();
|
||||||
await loadToday();
|
await loadToday();
|
||||||
|
|||||||
+30
-4
@@ -63,6 +63,10 @@ html[data-accent="violet"] { --accent: #9a6fd0; --accent-hover: #ab80e0; --accen
|
|||||||
html[data-accent="pink"] { --accent: #e0567f; --accent-hover: #eb6890; --accent-active: #c74b6e; --accent-ink: #141414; }
|
html[data-accent="pink"] { --accent: #e0567f; --accent-hover: #eb6890; --accent-active: #c74b6e; --accent-ink: #141414; }
|
||||||
html[data-accent="white"] { --accent: #ffffff; --accent-hover: #f2f2f2; --accent-active: #e6e6e6; --accent-ink: #141414; --accent-border: #9a9a9a; }
|
html[data-accent="white"] { --accent: #ffffff; --accent-hover: #f2f2f2; --accent-active: #e6e6e6; --accent-ink: #141414; --accent-border: #9a9a9a; }
|
||||||
|
|
||||||
|
html[data-theme="light"][data-accent="white"] .wp-step { border-color: #8a8a8a; }
|
||||||
|
html[data-theme="light"][data-accent="white"] .wp-step.is-done { border-color: #000; background: #000; }
|
||||||
|
html[data-theme="light"][data-accent="white"] .wp-step.is-current { border-color: #000; background: transparent; }
|
||||||
|
|
||||||
html[data-theme="dark"], html[data-theme="oled"] { color-scheme: dark; }
|
html[data-theme="dark"], html[data-theme="oled"] { color-scheme: dark; }
|
||||||
html[data-theme="light"] { color-scheme: light; }
|
html[data-theme="light"] { color-scheme: light; }
|
||||||
|
|
||||||
@@ -138,6 +142,18 @@ html, body {
|
|||||||
gap: 0;
|
gap: 0;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
border: 2px solid var(--border);
|
border: 2px solid var(--border);
|
||||||
|
overflow-x: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
.topbar { padding: 10px 12px; }
|
||||||
|
.tab { padding: 6px 12px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
@@ -199,6 +215,7 @@ h3 { font-size: 15px; font-weight: 700; }
|
|||||||
font: inherit;
|
font: inherit;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 7px 14px;
|
padding: 7px 14px;
|
||||||
|
min-width: 96px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +241,7 @@ h3 { font-size: 15px; font-weight: 700; }
|
|||||||
.btn-danger-ghost:hover { background: var(--bg-hover); }
|
.btn-danger-ghost:hover { background: var(--bg-hover); }
|
||||||
.btn-danger-ghost.is-armed { background: var(--danger); color: #fff; }
|
.btn-danger-ghost.is-armed { background: var(--danger); color: #fff; }
|
||||||
|
|
||||||
.btn-small { padding: 4px 10px; font-size: 13px; }
|
.btn-small { padding: 4px 10px; font-size: 13px; min-width: 64px; }
|
||||||
.btn-block { width: 100%; }
|
.btn-block { width: 100%; }
|
||||||
|
|
||||||
.icon-btn {
|
.icon-btn {
|
||||||
@@ -386,7 +403,7 @@ h3 { font-size: 15px; font-weight: 700; }
|
|||||||
|
|
||||||
.ex-grid {
|
.ex-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(460px, 1fr));
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
@@ -419,12 +436,14 @@ h3 { font-size: 15px; font-weight: 700; }
|
|||||||
|
|
||||||
.set-row {
|
.set-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: nowrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.set-rows { overflow-x: auto; }
|
||||||
|
|
||||||
.set-row.is-done { background: var(--bg-subtle); }
|
.set-row.is-done { background: var(--bg-subtle); }
|
||||||
|
|
||||||
/* Set-Abhaken: ganzer Button klickbar, mit Ankreuz-Box */
|
/* Set-Abhaken: ganzer Button klickbar, mit Ankreuz-Box */
|
||||||
@@ -491,6 +510,8 @@ h3 { font-size: 15px; font-weight: 700; }
|
|||||||
|
|
||||||
.field-input {
|
.field-input {
|
||||||
width: 74px;
|
width: 74px;
|
||||||
|
min-width: 60px;
|
||||||
|
height: 32px;
|
||||||
padding: 6px 4px 6px 8px;
|
padding: 6px 4px 6px 8px;
|
||||||
border: 0;
|
border: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@@ -919,9 +940,13 @@ body.boot #setup-gate { visibility: hidden; }
|
|||||||
width: 640px;
|
width: 640px;
|
||||||
max-width: calc(100vw - 32px);
|
max-width: calc(100vw - 32px);
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#setup-gate .auth-box { min-height: 560px; }
|
||||||
|
|
||||||
.auth-head {
|
.auth-head {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1038,7 +1063,8 @@ body.boot #setup-gate { visibility: hidden; }
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 20px;
|
margin-top: auto;
|
||||||
|
padding-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-nav-right {
|
.wizard-nav-right {
|
||||||
|
|||||||
Reference in new issue
Block a user