ui: added subtle tint for alternating rows on tables

This commit is contained in:
2026-03-14 11:09:32 +02:00
parent 15c419b7bf
commit dd607a04a1
12 changed files with 28 additions and 26 deletions

View File

@@ -839,13 +839,14 @@ export default function CustomerList() {
const isLast = index === pagedCustomers.length - 1;
const gradient = rowGradient(c, direction);
const rowBg = hoveredRow === c.id ? "var(--bg-card-hover)" : undefined;
const zebraBase = index % 2 === 1 ? "var(--bg-row-alt)" : "transparent";
const rowStyle = {
borderBottom: (!isLast && !(notesMode === "expanded" && hasStatus))
? "1px solid var(--border-secondary)"
: "none",
background: rowBg
? rowBg
: gradient || "transparent",
: gradient || zebraBase,
};
const mainRow = (

View File

@@ -163,7 +163,7 @@ export default function OrderList() {
className="cursor-pointer"
style={{
borderBottom: index < orders.length - 1 ? "1px solid var(--border-secondary)" : "none",
backgroundColor: hoveredRow === o.id ? "var(--bg-card-hover)" : "transparent",
backgroundColor: hoveredRow === o.id ? "var(--bg-card-hover)" : index % 2 === 1 ? "var(--bg-row-alt)" : "transparent",
}}
onMouseEnter={() => setHoveredRow(o.id)}
onMouseLeave={() => setHoveredRow(null)}

View File

@@ -150,7 +150,7 @@ export default function ProductList() {
className="cursor-pointer"
style={{
borderBottom: index < filtered.length - 1 ? "1px solid var(--border-primary)" : "none",
backgroundColor: hoveredRow === p.id ? "var(--bg-card-hover)" : "transparent",
backgroundColor: hoveredRow === p.id ? "var(--bg-card-hover)" : index % 2 === 1 ? "var(--bg-row-alt)" : "transparent",
}}
onMouseEnter={() => setHoveredRow(p.id)}
onMouseLeave={() => setHoveredRow(null)}

View File

@@ -234,7 +234,7 @@ export default function AllQuotationsList() {
// Grid columns: thumbnail | number | customer | title | date | status | total
const GRID = "90px 120px 180px minmax(0,1fr) 110px 120px 130px";
function renderRow(q) {
function renderRow(q, index = 0) {
const isDeleting = deleting === q.id;
const displayDate = q.is_legacy ? (q.legacy_date || q.created_at?.slice(0, 10) || "—") : (q.created_at?.slice(0, 10) || "—");
@@ -251,12 +251,12 @@ export default function AllQuotationsList() {
borderBottom: "1px solid var(--border-secondary)",
alignItems: "center",
minHeight: 110,
backgroundColor: "var(--bg-card)",
backgroundColor: index % 2 === 1 ? "color-mix(in srgb, var(--bg-card) 97%, white)" : "var(--bg-card)",
cursor: "pointer",
}}
onClick={() => navigate(`/crm/customers/${q.customer_id}?tab=Quotations`)}
onMouseEnter={e => e.currentTarget.style.backgroundColor = "var(--bg-card-hover)"}
onMouseLeave={e => e.currentTarget.style.backgroundColor = "var(--bg-card)"}
onMouseLeave={e => e.currentTarget.style.backgroundColor = index % 2 === 1 ? "color-mix(in srgb, var(--bg-card) 97%, white)" : "var(--bg-card)"}
>
{/* Thumbnail — stops row click */}
<div onClick={e => e.stopPropagation()}>
@@ -406,7 +406,7 @@ export default function AllQuotationsList() {
))}
</div>
{quotations.map(q => renderRow(q))}
{quotations.map((q, i) => renderRow(q, i))}
</div>
)}
</div>

View File

@@ -426,7 +426,7 @@ export default function QuotationList({ customerId, onSend }) {
// Delete button is a hover-only overlay — no dedicated column needed
const GRID = "90px 120px minmax(0,1fr) 130px 130px 130px 90px";
function renderRow(q, isLegacy = false) {
function renderRow(q, isLegacy = false, index = 0) {
const hasPdf = isLegacy ? !!q.legacy_pdf_path : !!q.nextcloud_pdf_url;
const displayDate = isLegacy ? (q.legacy_date || fmtDate(q.created_at)) : fmtDate(q.created_at);
const isDeleting = deleting === q.id;
@@ -444,10 +444,10 @@ export default function QuotationList({ customerId, onSend }) {
borderBottom: "1px solid var(--border-secondary)",
alignItems: "center",
minHeight: 110,
backgroundColor: "var(--bg-card)",
backgroundColor: index % 2 === 1 ? "color-mix(in srgb, var(--bg-card) 97%, white)" : "var(--bg-card)",
}}
onMouseEnter={e => e.currentTarget.style.backgroundColor = "var(--bg-card-hover)"}
onMouseLeave={e => e.currentTarget.style.backgroundColor = "var(--bg-card)"}
onMouseLeave={e => e.currentTarget.style.backgroundColor = index % 2 === 1 ? "color-mix(in srgb, var(--bg-card) 97%, white)" : "var(--bg-card)"}
>
{/* Thumbnail */}
<div>
@@ -659,7 +659,7 @@ export default function QuotationList({ customerId, onSend }) {
{!loading && regular.length > 0 && (
<div style={{ borderRadius: 8, border: "1px solid var(--border-primary)", overflow: "hidden", marginBottom: legacy.length > 0 ? 24 : 0 }}>
<TableHeader />
{regular.map(q => renderRow(q, false))}
{regular.map((q, i) => renderRow(q, false, i))}
</div>
)}
@@ -681,7 +681,7 @@ export default function QuotationList({ customerId, onSend }) {
</div>
<div style={{ borderRadius: 8, border: "1px solid var(--border-primary)", overflow: "hidden" }}>
<TableHeader />
{legacy.map(q => renderRow(q, true))}
{legacy.map((q, i) => renderRow(q, true, i))}
</div>
</div>
)}

View File

@@ -465,14 +465,14 @@ export default function DeviceList() {
</tr>
</thead>
<tbody>
{pagedDevices.map((device) => (
{pagedDevices.map((device, index) => (
<tr
key={device.id}
onClick={() => navigate(`/devices/${device.id}`)}
className="cursor-pointer transition-colors"
style={{ borderBottom: "1px solid var(--border-secondary)" }}
style={{ borderBottom: "1px solid var(--border-secondary)", backgroundColor: index % 2 === 1 ? "var(--bg-row-alt)" : "transparent" }}
onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = "var(--bg-card-hover)")}
onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = "transparent")}
onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = index % 2 === 1 ? "var(--bg-row-alt)" : "transparent")}
>
{activeColumns.map((col) => (
<td

View File

@@ -174,7 +174,7 @@ export default function NoteList() {
className="cursor-pointer"
style={{
borderBottom: index < items.length - 1 ? "1px solid var(--border-primary)" : "none",
backgroundColor: hoveredRow === note.id ? "var(--bg-card-hover)" : "transparent",
backgroundColor: hoveredRow === note.id ? "var(--bg-card-hover)" : index % 2 === 1 ? "var(--bg-row-alt)" : "transparent",
opacity: note.status === "completed" ? 0.6 : 1,
}}
onMouseEnter={() => setHoveredRow(note.id)}
@@ -282,7 +282,7 @@ export default function NoteList() {
key={msg.id}
style={{
borderBottom: index < filtered.length - 1 ? "1px solid var(--border-primary)" : "none",
backgroundColor: hoveredRow === msg.id ? "var(--bg-card-hover)" : "transparent",
backgroundColor: hoveredRow === msg.id ? "var(--bg-card-hover)" : index % 2 === 1 ? "var(--bg-row-alt)" : "transparent",
opacity: msg.acknowledged ? 0.6 : 1,
}}
onMouseEnter={() => setHoveredRow(msg.id)}

View File

@@ -9,6 +9,7 @@
--bg-input: #111827;
--bg-sidebar: #111827;
--bg-header: #1f2937;
--bg-row-alt: rgba(255, 255, 255, 0.03);
--border-primary: #374151;
--border-secondary: #2d3748;

View File

@@ -1300,14 +1300,14 @@ export default function MelodyList() {
</tr>
</thead>
<tbody>
{pagedRows.map((row) => (
{pagedRows.map((row, index) => (
<tr
key={row.id}
onClick={() => navigate(`/melodies/${row.id}`)}
className="cursor-pointer transition-colors"
style={{ borderBottom: "1px solid var(--border-secondary)" }}
style={{ borderBottom: "1px solid var(--border-secondary)", backgroundColor: index % 2 === 1 ? "var(--bg-row-alt)" : "transparent" }}
onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = "var(--bg-card-hover)")}
onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = "transparent")}
onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = index % 2 === 1 ? "var(--bg-row-alt)" : "transparent")}
>
{activeColumns.map((col) => (
<td

View File

@@ -465,14 +465,14 @@ export default function ArchetypeList() {
</tr>
</thead>
<tbody>
{archetypes.map((m) => {
{archetypes.map((m, index) => {
const assignedCount = getVerifiedAssignedCount(m);
return (
<tr
key={m.id}
onClick={() => navigate(`/melodies/archetypes/${m.id}`)}
className="border-b cursor-pointer transition-colors hover:bg-[var(--bg-card-hover)]"
style={{ borderColor: "var(--border-primary)" }}
style={{ borderColor: "var(--border-primary)", backgroundColor: index % 2 === 1 ? "var(--bg-row-alt)" : "transparent" }}
>
<td className="px-4 py-3 font-medium" style={{ color: "var(--text-heading)" }}>
{m.name}

View File

@@ -141,14 +141,14 @@ export default function StaffList() {
</tr>
</thead>
<tbody>
{staff.map((member) => (
{staff.map((member, index) => (
<tr
key={member.id}
onClick={() => navigate(`/settings/staff/${member.id}`)}
className="cursor-pointer transition-colors"
style={{ borderBottom: "1px solid var(--border-secondary)" }}
style={{ borderBottom: "1px solid var(--border-secondary)", backgroundColor: index % 2 === 1 ? "var(--bg-row-alt)" : "transparent" }}
onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = "var(--bg-card-hover)")}
onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = "transparent")}
onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = index % 2 === 1 ? "var(--bg-row-alt)" : "transparent")}
>
<td className="px-4 py-3">
<span className="font-medium" style={{ color: "var(--text-heading)" }}>{member.name}</span>

View File

@@ -156,7 +156,7 @@ export default function UserList() {
className="cursor-pointer"
style={{
borderBottom: index < users.length - 1 ? "1px solid var(--border-primary)" : "none",
backgroundColor: hoveredRow === user.id ? "var(--bg-card-hover)" : "transparent",
backgroundColor: hoveredRow === user.id ? "var(--bg-card-hover)" : index % 2 === 1 ? "var(--bg-row-alt)" : "transparent",
}}
onMouseEnter={() => setHoveredRow(user.id)}
onMouseLeave={() => setHoveredRow(null)}