style(mobile): responsiver Durchgang - Sidebar+Liste-Layouts brechen um
CI / backend-tests (push) Failing after 1m54s
CI / frontend-build (push) Successful in 17s

4 Admin-Sektionen (ObjektSection, MaterialSection, ZustaendigkeitSection,
ObjektPositionenPanel) hatten identisches fest-20rem/12rem-Sidebar-neben-
Liste-Layout ohne Umbruch - auf Mobile lagen beide Spalten nebeneinander
breiter als der Bildschirm. Neue global.css-Klassen .split-layout/
-sidebar/-sidebar-sm/-content lösen das inline-Style-Duplikat auf und
klappen unter 768px automatisch auf eine Spalte.

Zusätzlich: .page-wide/.topbar/.card-grid/.row bekommen eigene 768px-
Anpassungen (kleinere Paddings/Schrift, Kacheln volle Breite, automatischer
Zeilenumbruch). Tabellen (Historie/Lagerbewegungen) waren schon per
overflow-x:auto abgesichert, keine Änderung nötig dort.

Mitarbeiter-Mobilflow (ObjektListPage/KontrollPage, 640px-Spalte) unverändert
- war laut Nutzer-Feedback bereits gut.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
This commit is contained in:
2026-09-05 15:02:52 +02:00
co-authored by Claude Sonnet 5
parent 7ebbae802e
commit 985e80b59d
6 changed files with 99 additions and 15 deletions
+16
View File
@@ -4189,3 +4189,19 @@ Keine Commits in dieser Session.
- DEVLOG.md | 38 ++++++++++++++++++++++++++++++++++++++
---
## 2026-09-05 14:55 14:59 (4m)
**Beschreibung:** Claude Code Session
**Projekt:** asb-material
### Commits
- 7ebbae8 style: visuelles Redesign (Desktop), Design-Anleihe bei Resgrid/OpenFleet/EMCS
### Geänderte Dateien
- DEVLOG.md | 33 ++++++++++++
- frontend/src/pages/DashboardPage.tsx | 36 ++++++-------
- frontend/src/pages/FehlbestandListePage.tsx | 2 +-
- frontend/src/pages/MangelListePage.tsx | 4 +-
- frontend/src/pages/admin/QualifikationSection.tsx | 2 +-
- frontend/src/styles/global.css | 201 ++++++++++++++++++++++++++++++++++++++++++++++++--------------------
---
+3 -3
View File
@@ -78,8 +78,8 @@ export function MaterialSection({ materialien, onGeaendert, onFehler }: Props) {
return (
<section className="section">
<h2>Material</h2>
<div style={{ display: "flex", flexDirection: "row", alignItems: "flex-start", gap: "1.25rem" }}>
<div className="card" style={{ flex: "0 0 20rem", width: "20rem", boxSizing: "border-box" }}>
<div className="split-layout">
<div className="card split-layout-sidebar">
<h3 style={{ marginTop: 0 }}>{bearbeiteteId !== null ? "Material bearbeiten" : "Material anlegen"}</h3>
<div className="stack">
<div className="field">
@@ -137,7 +137,7 @@ export function MaterialSection({ materialien, onGeaendert, onFehler }: Props) {
</div>
</div>
<div style={{ flex: "1 1 0%", minWidth: 0 }}>
<div className="split-layout-content">
<input
className="input input-search"
style={{ marginBottom: "1rem" }}
@@ -152,12 +152,9 @@ export function ObjektPositionenPanel({ objektId, vorlageId, materialien, onFehl
const verfuegbareMaterialien = materialien.filter((m) => !vorhandeneMaterialIds.has(m.id));
return (
<div style={{ display: "flex", flexDirection: "row", alignItems: "flex-start", gap: "1.25rem" }}>
<div className="split-layout">
{positionen.length > 0 && (
<nav
className="card"
style={{ flex: "0 0 12rem", width: "12rem", boxSizing: "border-box", padding: "0.5rem" }}
>
<nav className="card split-layout-sidebar-sm">
<button
className={aktivesFach === null ? "btn btn-primary btn-block" : "btn btn-secondary btn-block"}
style={{ marginBottom: "0.3rem" }}
@@ -178,7 +175,7 @@ export function ObjektPositionenPanel({ objektId, vorlageId, materialien, onFehl
</nav>
)}
<div style={{ flex: "1 1 0%", minWidth: 0 }}>
<div className="split-layout-content">
<div className="row" style={{ flexWrap: "wrap", marginBottom: "1rem" }}>
<select
className="input"
+3 -3
View File
@@ -263,9 +263,9 @@ export function ObjektSection({
return (
<section className="section">
<h2>Objekte</h2>
<div style={{ display: "flex", flexDirection: "row", alignItems: "flex-start", gap: "1.25rem" }}>
<div className="split-layout">
{!nurPflegen && (
<div className="card" style={{ flex: "0 0 20rem", width: "20rem", boxSizing: "border-box" }}>
<div className="card split-layout-sidebar">
<h3 style={{ marginTop: 0 }}>Objekt aus Vorlage anlegen</h3>
{vorlagen.length === 0 ? (
<p className="text-muted">
@@ -342,7 +342,7 @@ export function ObjektSection({
</div>
)}
<div style={{ flex: "1 1 0%", minWidth: 0 }}>
<div className="split-layout-content">
<input
className="input input-search"
style={{ marginBottom: "1rem" }}
@@ -103,8 +103,8 @@ export function ZustaendigkeitSection({ standorte, objekte, benutzer, onFehler }
return (
<section className="section">
<h2>Zuständigkeit</h2>
<div style={{ display: "flex", flexDirection: "row", alignItems: "flex-start", gap: "1.25rem" }}>
<div className="card" style={{ flex: "0 0 20rem", width: "20rem", boxSizing: "border-box" }}>
<div className="split-layout">
<div className="card split-layout-sidebar">
<p className="text-muted" style={{ marginBottom: "1rem" }}>
Wer ist materialverantwortlich für welchen Standort/welches Objekt. Standort-Zuordnung
gilt für alle Objekte dort, Objekt-Zuordnung ist eine zusätzliche, feinere Ergänzung.
@@ -182,7 +182,7 @@ export function ZustaendigkeitSection({ standorte, objekte, benutzer, onFehler }
</div>
</div>
<div style={{ flex: "1 1 0%", minWidth: 0 }}>
<div className="split-layout-content">
<input
className="input input-search"
style={{ marginBottom: "1rem" }}
+71
View File
@@ -461,3 +461,74 @@ select.input:focus {
margin: 0.2rem 0 0.4rem;
line-height: 1;
}
/* -- Responsive: mobile Durchgang 2026-09-05 -----------------------------
Formular-Sidebar + Liste (Objekte/Material/Zuständigkeit/Positionen)
nutzten bisher fixe 20rem-Breite nebeneinander - bricht auf Mobile, da
beide Spalten dann zusammen breiter als der Bildschirm sind. */
.split-layout {
display: flex;
align-items: flex-start;
gap: 1.25rem;
}
.split-layout-sidebar {
flex: 0 0 20rem;
width: 20rem;
box-sizing: border-box;
}
.split-layout-sidebar-sm {
flex: 0 0 12rem;
width: 12rem;
box-sizing: border-box;
padding: 0.5rem;
}
.split-layout-content {
flex: 1 1 0%;
min-width: 0;
}
@media (max-width: 768px) {
.split-layout {
flex-direction: column;
}
.split-layout-sidebar,
.split-layout-sidebar-sm {
width: 100%;
flex: 1 1 auto;
}
.page-wide {
padding: 1.25rem 1rem 2rem;
}
.topbar {
padding: 0.6rem 0.9rem;
flex-wrap: wrap;
}
.topbar-nav {
gap: 0.15rem;
}
.topbar-nav a {
padding: 0.4rem 0.6rem;
font-size: 0.85rem;
}
h1 {
font-size: 1.35rem;
}
.card-grid > .card {
flex: 1 1 100%;
}
.row {
flex-wrap: wrap;
}
}