Tabellen werden bei wenig Platz zu Karten statt seitwaerts zu scrollen
Waagerechtes Scrollen in einem Block war die falsche Antwort auf zu wenig
Platz - man sieht nicht, dass es weitergeht, und auf dem Trackpad ist es
muehsam. Das Scrollen ist ersatzlos weg.
Stattdessen stellt sich jede Tabelle unter 700px verfuegbarer Breite auf
Karten um: eine Karte je Zeile, jede Angabe mit ihrer Beschriftung davor.
Die Beschriftung kommt aus data-label an der Zelle, die Kopfzeile wird
ausgeblendet. Zellen ohne Beschriftung (Vorschaubild, Aktionsknoepfe) bleiben
ohne eigene Zeile.
Ausgeloest wird das per Container-Abfrage, nicht per Bildschirmbreite. Damit
richtet sich die Darstellung nach dem Platz, den die Tabelle wirklich hat -
sie stellt sich also auch um, wenn das Fenster nur die halbe Bildschirmbreite
einnimmt oder ein Block danebensteht.
Dazu die Aufteilung neben dem Block: Die Tabelle hat mehr Spalten als der
Block und bekommt jetzt den groesseren Anteil (1,5 zu 1, Block mindestens
340px). Vorher waren beide gleich breit, wodurch die Tabelle unnoetig frueh in
die Kartenansicht gerutscht waere, obwohl daneben Platz frei war.
Durchgerechnet: Bei 1920 voller Breite bleibt es eine Tabelle (802px) mit
komfortablem Block daneben (534px). Bei halber Bildschirmbreite stapelt sich
die Seite und die Tabelle wird zur Karte. In keinem Fall wird etwas
abgeschnitten und nirgends muss seitwaerts gescrollt werden.
Lange Zeichenketten in Zellen brechen jetzt um (overflow-wrap), da kein
Scrollen mehr auffaengt, was hinauslaeuft.
Dabei aufgefallen: In der Produkttabelle stand nach dem Ergaenzen der
Kategorie-Spalte noch colSpan={7} statt 8 - die Zeile "Keine Produkte
gefunden" ueberspannte die Tabelle nicht mehr ganz. Alle colSpan-Angaben sind
jetzt gegen die Spaltenzahl gegengeprueft.
Getestet: Web-Build laeuft durch, Spaltenzahl und colSpan stimmen in allen
fuenf betroffenen Tabellen ueberein, die Umbruchpunkte sind durchgerechnet.
Die Darstellung im Browser habe ich nicht selbst angesehen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -103,7 +103,7 @@ export default function Categories() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{tree.map((c) => (
|
{tree.map((c) => (
|
||||||
<tr key={c.id}>
|
<tr key={c.id}>
|
||||||
<td>
|
<td data-label="Kategorie">
|
||||||
<span style={{ display: "flex", alignItems: "center", gap: 8,
|
<span style={{ display: "flex", alignItems: "center", gap: 8,
|
||||||
paddingLeft: c.depth * 22 }}>
|
paddingLeft: c.depth * 22 }}>
|
||||||
{c.depth > 0 && <span className="muted">↳</span>}
|
{c.depth > 0 && <span className="muted">↳</span>}
|
||||||
@@ -119,7 +119,7 @@ export default function Categories() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="num muted">{c.product_count}</td>
|
<td data-label="Artikel" className="num muted">{c.product_count}</td>
|
||||||
<td className="num">
|
<td className="num">
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<button className="btn-icon danger" onClick={() => remove(c)} title="Löschen">
|
<button className="btn-icon danger" onClick={() => remove(c)} title="Löschen">
|
||||||
|
|||||||
@@ -84,15 +84,15 @@ export default function Dashboard() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{expiring.map((it) => (
|
{expiring.map((it) => (
|
||||||
<tr key={it.lot_id} className={it.days_left < 0 ? "row-danger" : "row-warn"}>
|
<tr key={it.lot_id} className={it.days_left < 0 ? "row-danger" : "row-warn"}>
|
||||||
<td>{it.product_name}</td>
|
<td data-label="Produkt">{it.product_name}</td>
|
||||||
<td className="num">
|
<td data-label="Menge" className="num">
|
||||||
{articlePrimary(it)}
|
{articlePrimary(it)}
|
||||||
{articleSecondary(it) && (
|
{articleSecondary(it) && (
|
||||||
<div className="muted small">{articleSecondary(it)}</div>
|
<div className="muted small">{articleSecondary(it)}</div>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td>{formatBestBefore(it.best_before, it.best_before_precision)}</td>
|
<td data-label="MHD">{formatBestBefore(it.best_before, it.best_before_precision)}</td>
|
||||||
<td>
|
<td data-label="Frist">
|
||||||
<span className={`badge ${it.days_left < 0 ? "danger" : "warn"}`}>
|
<span className={`badge ${it.days_left < 0 ? "danger" : "warn"}`}>
|
||||||
{relativeExpiry(it.days_left)}
|
{relativeExpiry(it.days_left)}
|
||||||
</span>
|
</span>
|
||||||
@@ -120,16 +120,16 @@ export default function Dashboard() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{groupShopping.map((it) => (
|
{groupShopping.map((it) => (
|
||||||
<tr key={`g${it.group_id}`}>
|
<tr key={`g${it.group_id}`}>
|
||||||
<td><span className="badge accent">Gruppe</span> {it.name}</td>
|
<td data-label="Bedarf"><span className="badge accent">Gruppe</span> {it.name}</td>
|
||||||
<td className="num">{fmt(it.stock)} {it.unit_name}</td>
|
<td data-label="Bestand" className="num">{fmt(it.stock)} {it.unit_name}</td>
|
||||||
<td className="num strong">{fmt(it.deficit)} {it.unit_name}</td>
|
<td data-label="Fehlt" className="num strong">{fmt(it.deficit)} {it.unit_name}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
{shopping.map((it) => (
|
{shopping.map((it) => (
|
||||||
<tr key={`p${it.product_id}`}>
|
<tr key={`p${it.product_id}`}>
|
||||||
<td>{it.name}</td>
|
<td data-label="Bedarf">{it.name}</td>
|
||||||
<td className="num">{amountText(it.stock, it.package_size, it.base_unit)}</td>
|
<td data-label="Bestand" className="num">{amountText(it.stock, it.package_size, it.base_unit)}</td>
|
||||||
<td className="num strong">{amountText(it.deficit, it.package_size, it.base_unit)}</td>
|
<td data-label="Fehlt" className="num strong">{amountText(it.deficit, it.package_size, it.base_unit)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export default function Groups() {
|
|||||||
const low = g.min_stock != null && g.stock < g.min_stock;
|
const low = g.min_stock != null && g.stock < g.min_stock;
|
||||||
return (
|
return (
|
||||||
<tr key={g.id}>
|
<tr key={g.id}>
|
||||||
<td>
|
<td data-label="Gruppe">
|
||||||
{isAdmin ? (
|
{isAdmin ? (
|
||||||
<input defaultValue={g.name} style={{ marginTop: 0, minWidth: 130 }}
|
<input defaultValue={g.name} style={{ marginTop: 0, minWidth: 130 }}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
@@ -114,9 +114,9 @@ export default function Groups() {
|
|||||||
) : <span className="strong">{g.name}</span>}
|
) : <span className="strong">{g.name}</span>}
|
||||||
{low && <span className="badge warn" style={{ marginLeft: 6 }}>niedrig</span>}
|
{low && <span className="badge warn" style={{ marginLeft: 6 }}>niedrig</span>}
|
||||||
</td>
|
</td>
|
||||||
<td className="num muted">{g.product_count}</td>
|
<td data-label="Produkte" className="num muted">{g.product_count}</td>
|
||||||
<td className="num">{fmt(g.stock)} {g.min_stock_unit_name || ""}</td>
|
<td data-label="Bestand" className="num">{fmt(g.stock)} {g.min_stock_unit_name || ""}</td>
|
||||||
<td>
|
<td data-label="Mindestbestand">
|
||||||
{isAdmin ? (
|
{isAdmin ? (
|
||||||
<input type="number" step="any" defaultValue={g.min_stock ?? ""}
|
<input type="number" step="any" defaultValue={g.min_stock ?? ""}
|
||||||
style={{ marginTop: 0, minWidth: 90 }}
|
style={{ marginTop: 0, minWidth: 90 }}
|
||||||
@@ -128,7 +128,7 @@ export default function Groups() {
|
|||||||
}} />
|
}} />
|
||||||
) : (g.min_stock != null ? fmt(g.min_stock) : "–")}
|
) : (g.min_stock != null ? fmt(g.min_stock) : "–")}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="Einheit">
|
||||||
{isAdmin ? (
|
{isAdmin ? (
|
||||||
<select value={g.min_stock_unit_id ?? ""} style={{ marginTop: 0 }}
|
<select value={g.min_stock_unit_id ?? ""} style={{ marginTop: 0 }}
|
||||||
onChange={(e) => patch(g, {
|
onChange={(e) => patch(g, {
|
||||||
@@ -139,7 +139,7 @@ export default function Groups() {
|
|||||||
</select>
|
</select>
|
||||||
) : (g.min_stock_unit_name || "–")}
|
) : (g.min_stock_unit_name || "–")}
|
||||||
</td>
|
</td>
|
||||||
<td className="num">
|
<td data-label="EAN-Codes" className="num">
|
||||||
<button className="link-btn" onClick={() => setSelectedId(g.id)}>
|
<button className="link-btn" onClick={() => setSelectedId(g.id)}>
|
||||||
{/* Beide Herkünfte zählen, sonst steht bei einer Gruppe
|
{/* Beide Herkünfte zählen, sonst steht bei einer Gruppe
|
||||||
mit Artikeln irreführend eine 0. */}
|
mit Artikeln irreführend eine 0. */}
|
||||||
|
|||||||
@@ -38,21 +38,21 @@ export default function History() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{movements.map((m) => (
|
{movements.map((m) => (
|
||||||
<tr key={m.id}>
|
<tr key={m.id}>
|
||||||
<td className="muted">{new Date(m.created_at).toLocaleString("de-DE")}</td>
|
<td data-label="Zeitpunkt" className="muted">{new Date(m.created_at).toLocaleString("de-DE")}</td>
|
||||||
<td>
|
<td data-label="Aktion">
|
||||||
<span className={`badge ${m.type === "in" ? "ok" : m.type === "out" ? "warn" : ""}`}>
|
<span className={`badge ${m.type === "in" ? "ok" : m.type === "out" ? "warn" : ""}`}>
|
||||||
<Icon name={m.type === "in" ? "checkin" : m.type === "out" ? "checkout" : "edit"} size={13} />
|
<Icon name={m.type === "in" ? "checkin" : m.type === "out" ? "checkout" : "edit"} size={13} />
|
||||||
{TYPE_LABEL[m.type] || m.type}
|
{TYPE_LABEL[m.type] || m.type}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{m.product_name}</td>
|
<td data-label="Produkt">{m.product_name}</td>
|
||||||
<td className="num">
|
<td data-label="Menge" className="num">
|
||||||
{articlePrimary(m)}
|
{articlePrimary(m)}
|
||||||
{articleSecondary(m) && (
|
{articleSecondary(m) && (
|
||||||
<div className="muted small">{articleSecondary(m)}</div>
|
<div className="muted small">{articleSecondary(m)}</div>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="muted">{m.username || "–"}</td>
|
<td data-label="Benutzer" className="muted">{m.username || "–"}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
{movements.length === 0 && (
|
{movements.length === 0 && (
|
||||||
|
|||||||
@@ -541,7 +541,7 @@ function LotsCard({ product, lots, baseShort, warnDays, isAdmin, imageUrl, onCha
|
|||||||
const editing = editId === l.id;
|
const editing = editId === l.id;
|
||||||
return (
|
return (
|
||||||
<tr key={l.id} className={cls}>
|
<tr key={l.id} className={cls}>
|
||||||
<td className="num">
|
<td data-label="Menge" className="num">
|
||||||
{editing ? (
|
{editing ? (
|
||||||
<div className="field-inline" style={{ justifyContent: "flex-end" }}>
|
<div className="field-inline" style={{ justifyContent: "flex-end" }}>
|
||||||
<input type="number" step="any" min="0" value={draft.quantity}
|
<input type="number" step="any" min="0" value={draft.quantity}
|
||||||
@@ -566,7 +566,7 @@ function LotsCard({ product, lots, baseShort, warnDays, isAdmin, imageUrl, onCha
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="MHD">
|
||||||
{editing ? (
|
{editing ? (
|
||||||
<input type={draft.precision === "month" ? "month" : "date"}
|
<input type={draft.precision === "month" ? "month" : "date"}
|
||||||
value={draft.best_before}
|
value={draft.best_before}
|
||||||
@@ -584,7 +584,7 @@ function LotsCard({ product, lots, baseShort, warnDays, isAdmin, imageUrl, onCha
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="muted">{new Date(l.created_at).toLocaleDateString("de-DE")}</td>
|
<td data-label="Eingelagert" className="muted">{new Date(l.created_at).toLocaleDateString("de-DE")}</td>
|
||||||
<td className="num">
|
<td className="num">
|
||||||
{isAdmin && (editing ? (
|
{isAdmin && (editing ? (
|
||||||
<div className="btn-pair">
|
<div className="btn-pair">
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export default function Products() {
|
|||||||
? <img className="thumb" src={p.image_url} alt="" />
|
? <img className="thumb" src={p.image_url} alt="" />
|
||||||
: <span className="thumb thumb-fallback"><Icon name="box" size={16} /></span>}
|
: <span className="thumb thumb-fallback"><Icon name="box" size={16} /></span>}
|
||||||
</td>
|
</td>
|
||||||
<td className="strong">
|
<td data-label="Name" className="strong">
|
||||||
{p.name}
|
{p.name}
|
||||||
{p.expired_count > 0 && (
|
{p.expired_count > 0 && (
|
||||||
<span className="badge danger" style={{ marginLeft: 6 }}>
|
<span className="badge danger" style={{ marginLeft: 6 }}>
|
||||||
@@ -107,18 +107,18 @@ export default function Products() {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="muted">{p.brand || "–"}</td>
|
<td data-label="Marke" className="muted">{p.brand || "–"}</td>
|
||||||
<td className="muted">{p.category_name || "–"}</td>
|
<td data-label="Kategorie" className="muted">{p.category_name || "–"}</td>
|
||||||
<td>
|
<td data-label="Einheit">
|
||||||
{p.unit_name || unitShort(p.base_unit)}
|
{p.unit_name || unitShort(p.base_unit)}
|
||||||
{p.package_size
|
{p.package_size
|
||||||
? ` · ${p.package_label || "Packung"} ${fmt(p.package_size)} ${unitShort(p.base_unit)}`
|
? ` · ${p.package_label || "Packung"} ${fmt(p.package_size)} ${unitShort(p.base_unit)}`
|
||||||
: ""}
|
: ""}
|
||||||
</td>
|
</td>
|
||||||
<td className="num">
|
<td data-label="Bestand" className="num">
|
||||||
{fmt(p.stock / (p.unit_factor || 1))} {p.unit_name || unitShort(p.base_unit)}
|
{fmt(p.stock / (p.unit_factor || 1))} {p.unit_name || unitShort(p.base_unit)}
|
||||||
</td>
|
</td>
|
||||||
<td className="num">
|
<td data-label="Einheiten" className="num">
|
||||||
{fmt(p.stock / unitCount(p))}
|
{fmt(p.stock / unitCount(p))}
|
||||||
{p.min_stock != null ? ` / ${fmt(p.min_stock / unitCount(p))}` : ""}{" "}
|
{p.min_stock != null ? ` / ${fmt(p.min_stock / unitCount(p))}` : ""}{" "}
|
||||||
{countLabel(p)}
|
{countLabel(p)}
|
||||||
@@ -129,7 +129,7 @@ export default function Products() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{products.length === 0 && (
|
{products.length === 0 && (
|
||||||
<tr><td colSpan={7} className="empty">Keine Produkte gefunden.</td></tr>
|
<tr><td colSpan={8} className="empty">Keine Produkte gefunden.</td></tr>
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export default function Transfer() {
|
|||||||
<section className="card">
|
<section className="card">
|
||||||
<div className="card-head"><Icon name="package" /><h2>CSV-Aufbau</h2></div>
|
<div className="card-head"><Icon name="package" /><h2>CSV-Aufbau</h2></div>
|
||||||
<div className="table-wrap">
|
<div className="table-wrap">
|
||||||
<table className="table">
|
<table className="table table-compact">
|
||||||
<thead><tr><th>Spalte</th><th>Bedeutung</th></tr></thead>
|
<thead><tr><th>Spalte</th><th>Bedeutung</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><td className="strong">barcode</td><td>optional; dient zum Wiedererkennen vorhandener Produkte</td></tr>
|
<tr><td className="strong">barcode</td><td>optional; dient zum Wiedererkennen vorhandener Produkte</td></tr>
|
||||||
|
|||||||
@@ -70,9 +70,9 @@ export default function Units() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{units.map((u) => (
|
{units.map((u) => (
|
||||||
<tr key={u.id}>
|
<tr key={u.id}>
|
||||||
<td className="strong">{u.name}{u.is_builtin && <span className="badge" style={{ marginLeft: 6 }}>eingebaut</span>}</td>
|
<td data-label="Name" className="strong">{u.name}{u.is_builtin && <span className="badge" style={{ marginLeft: 6 }}>eingebaut</span>}</td>
|
||||||
<td className="muted">{KIND_LABEL[u.kind] || u.kind}</td>
|
<td data-label="Art" className="muted">{KIND_LABEL[u.kind] || u.kind}</td>
|
||||||
<td className="num">{fmt(u.factor)} {baseUnitOfKind[u.kind]}</td>
|
<td data-label="Faktor" className="num">{fmt(u.factor)} {baseUnitOfKind[u.kind]}</td>
|
||||||
<td className="num">
|
<td className="num">
|
||||||
{!u.is_builtin && (
|
{!u.is_builtin && (
|
||||||
<button className="btn-icon danger" onClick={() => remove(u)} title="Löschen">
|
<button className="btn-icon danger" onClick={() => remove(u)} title="Löschen">
|
||||||
|
|||||||
@@ -79,10 +79,10 @@ export default function Users() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{users.map((u) => (
|
{users.map((u) => (
|
||||||
<tr key={u.id}>
|
<tr key={u.id}>
|
||||||
<td className="strong">
|
<td data-label="Name" className="strong">
|
||||||
{u.username}{u.id === me.id && <span className="muted"> (du)</span>}
|
{u.username}{u.id === me.id && <span className="muted"> (du)</span>}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="Rolle">
|
||||||
<select value={u.role} onChange={(e) => changeRole(u, e.target.value)}
|
<select value={u.role} onChange={(e) => changeRole(u, e.target.value)}
|
||||||
disabled={u.id === me.id}>
|
disabled={u.id === me.id}>
|
||||||
<option value="user">Benutzer</option>
|
<option value="user">Benutzer</option>
|
||||||
|
|||||||
@@ -159,15 +159,16 @@ h2 { font-size: 0.95rem; font-weight: 650; margin: 0 0 var(--sp-3); letter-spaci
|
|||||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
|
||||||
gap: var(--sp-4);
|
gap: var(--sp-4);
|
||||||
}
|
}
|
||||||
/* Ohne min-width:0 schrumpfen Grid-Kinder nie unter ihre Inhaltsbreite. Genau
|
/* Ohne min-width:0 schrumpfen Grid-Kinder nie unter ihre Inhaltsbreite -
|
||||||
daran scheiterte das overflow-x der Tabelle: Sie wurde abgeschnitten,
|
dadurch lief die Tabelle aus ihrer Karte heraus und wurde abgeschnitten. */
|
||||||
statt zu scrollen. */
|
|
||||||
.grid-2 > * { min-width: 0; }
|
.grid-2 > * { min-width: 0; }
|
||||||
.form-narrow { max-width: 600px; }
|
.form-narrow { max-width: 600px; }
|
||||||
/* Seiten mit einem inhaltsreichen Block daneben (EAN-Codes) brauchen mehr
|
/* Tabelle plus Block daneben: Die Tabelle hat mehr Spalten und bekommt
|
||||||
Mindestbreite und stapeln deshalb frueher. */
|
deshalb den groesseren Anteil - sonst rutscht sie unnoetig frueh in die
|
||||||
.grid-2.wide-aside {
|
Kartenansicht, obwohl daneben Platz frei waere. */
|
||||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 520px), 1fr));
|
.grid-2.wide-aside { grid-template-columns: minmax(0, 1.5fr) minmax(340px, 1fr); }
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.grid-2.wide-aside { grid-template-columns: minmax(0, 1fr); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Forms ---------- */
|
/* ---------- Forms ---------- */
|
||||||
@@ -235,11 +236,15 @@ td select { width: auto; min-width: 132px; max-width: 100%; }
|
|||||||
.link-btn:hover { text-decoration: underline; }
|
.link-btn:hover { text-decoration: underline; }
|
||||||
|
|
||||||
/* ---------- Tables ---------- */
|
/* ---------- Tables ---------- */
|
||||||
.table-wrap { overflow-x: auto; max-width: 100%; }
|
/* container-type: Die Tabelle richtet sich nach dem Platz, den sie wirklich
|
||||||
/* min-width: Lieber waagerecht scrollen als Spalten so weit quetschen, dass
|
hat - nicht nach der Bildschirmbreite. So stellt sie sich auch um, wenn das
|
||||||
Text abgeschnitten wird. */
|
Fenster nur die halbe Bildschirmbreite einnimmt oder ein Block danebensteht. */
|
||||||
.table { width: 100%; min-width: 640px; border-collapse: collapse; font-size: 0.875rem; }
|
.table-wrap { max-width: 100%; container-type: inline-size; }
|
||||||
.table th, .table td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--border); }
|
.table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
|
||||||
|
.table th, .table td {
|
||||||
|
text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--border);
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
.table thead th {
|
.table thead th {
|
||||||
color: var(--muted); font-weight: 600; font-size: 0.72rem;
|
color: var(--muted); font-weight: 600; font-size: 0.72rem;
|
||||||
text-transform: uppercase; letter-spacing: 0.04em;
|
text-transform: uppercase; letter-spacing: 0.04em;
|
||||||
@@ -324,6 +329,43 @@ td select { width: auto; min-width: 132px; max-width: 100%; }
|
|||||||
.precision-pick { display: flex; align-items: center; gap: var(--sp-2); margin: 0; font-weight: 400; }
|
.precision-pick { display: flex; align-items: center; gap: var(--sp-2); margin: 0; font-weight: 400; }
|
||||||
.precision-pick select { margin: 0; width: auto; padding-top: 3px; padding-bottom: 3px; font-size: 0.8rem; }
|
.precision-pick select { margin: 0; width: auto; padding-top: 3px; padding-bottom: 3px; font-size: 0.8rem; }
|
||||||
/* Hinweis beim Einlagern: welche Kategorie automatisch zugeordnet wird */
|
/* Hinweis beim Einlagern: welche Kategorie automatisch zugeordnet wird */
|
||||||
|
/* Wird es eng, ist eine Tabelle das falsche Mittel: Spalten quetschen sich,
|
||||||
|
Text wird abgeschnitten, und waagerechtes Scrollen in einem Block ist
|
||||||
|
unbrauchbar. Stattdessen wird jede Zeile zu einer Karte, in der jede Angabe
|
||||||
|
ihre Beschriftung aus data-label bekommt. */
|
||||||
|
@container (max-width: 700px) {
|
||||||
|
.table thead { display: none; }
|
||||||
|
.table, .table tbody, .table tr, .table td { display: block; width: 100%; }
|
||||||
|
.table tr {
|
||||||
|
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
||||||
|
padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-3);
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
.table td {
|
||||||
|
border: none; padding: 5px 0;
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
gap: var(--sp-3); text-align: left;
|
||||||
|
}
|
||||||
|
.table td::before {
|
||||||
|
content: attr(data-label);
|
||||||
|
flex: 0 0 auto;
|
||||||
|
color: var(--muted); font-size: 0.7rem; font-weight: 600;
|
||||||
|
text-transform: uppercase; letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
/* Zellen ohne Beschriftung (Bild, Aktionen) brauchen keine Zeile fuer sich. */
|
||||||
|
.table td:not([data-label])::before { content: none; }
|
||||||
|
.table td:not([data-label]) { justify-content: flex-end; }
|
||||||
|
.table td.num { text-align: left; }
|
||||||
|
.table td input, .table td select { width: auto; max-width: 60%; margin-top: 0; }
|
||||||
|
.table .empty { text-align: center; }
|
||||||
|
/* Reine Nachschlagelisten (Begriff -> Erklaerung) bleiben zweispaltig,
|
||||||
|
dort waere eine Karte je Zeile nur Laerm. */
|
||||||
|
.table.table-compact, .table.table-compact tbody, .table.table-compact tr,
|
||||||
|
.table.table-compact td { display: revert; }
|
||||||
|
.table.table-compact thead { display: table-header-group; }
|
||||||
|
.table.table-compact td::before { content: none; }
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- EAN-Code-Zeile ---------- */
|
/* ---------- EAN-Code-Zeile ---------- */
|
||||||
.code-row { display: flex; align-items: center; gap: var(--sp-2); flex: 1; min-width: 0; flex-wrap: wrap; }
|
.code-row { display: flex; align-items: center; gap: var(--sp-2); flex: 1; min-width: 0; flex-wrap: wrap; }
|
||||||
.code-row code { flex: 0 0 auto; }
|
.code-row code { flex: 0 0 auto; }
|
||||||
|
|||||||
Reference in New Issue
Block a user