diff --git a/frontend/src/crm/customers/CustomerList.jsx b/frontend/src/crm/customers/CustomerList.jsx index 05f322a..95d690f 100644 --- a/frontend/src/crm/customers/CustomerList.jsx +++ b/frontend/src/crm/customers/CustomerList.jsx @@ -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 = ( diff --git a/frontend/src/crm/orders/OrderList.jsx b/frontend/src/crm/orders/OrderList.jsx index b6556ae..bb8033f 100644 --- a/frontend/src/crm/orders/OrderList.jsx +++ b/frontend/src/crm/orders/OrderList.jsx @@ -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)} diff --git a/frontend/src/crm/products/ProductList.jsx b/frontend/src/crm/products/ProductList.jsx index 3eae720..4e4b2dc 100644 --- a/frontend/src/crm/products/ProductList.jsx +++ b/frontend/src/crm/products/ProductList.jsx @@ -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)} diff --git a/frontend/src/crm/quotations/AllQuotationsList.jsx b/frontend/src/crm/quotations/AllQuotationsList.jsx index 974614c..04f54bf 100644 --- a/frontend/src/crm/quotations/AllQuotationsList.jsx +++ b/frontend/src/crm/quotations/AllQuotationsList.jsx @@ -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 */}
e.stopPropagation()}> @@ -406,7 +406,7 @@ export default function AllQuotationsList() { ))}
- {quotations.map(q => renderRow(q))} + {quotations.map((q, i) => renderRow(q, i))} )} diff --git a/frontend/src/crm/quotations/QuotationList.jsx b/frontend/src/crm/quotations/QuotationList.jsx index dbb6c31..37e565c 100644 --- a/frontend/src/crm/quotations/QuotationList.jsx +++ b/frontend/src/crm/quotations/QuotationList.jsx @@ -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 */}
@@ -659,7 +659,7 @@ export default function QuotationList({ customerId, onSend }) { {!loading && regular.length > 0 && (
0 ? 24 : 0 }}> - {regular.map(q => renderRow(q, false))} + {regular.map((q, i) => renderRow(q, false, i))}
)} @@ -681,7 +681,7 @@ export default function QuotationList({ customerId, onSend }) {
- {legacy.map(q => renderRow(q, true))} + {legacy.map((q, i) => renderRow(q, true, i))}
)} diff --git a/frontend/src/devices/DeviceList.jsx b/frontend/src/devices/DeviceList.jsx index 0eab768..39bd60d 100644 --- a/frontend/src/devices/DeviceList.jsx +++ b/frontend/src/devices/DeviceList.jsx @@ -465,14 +465,14 @@ export default function DeviceList() { - {pagedDevices.map((device) => ( + {pagedDevices.map((device, index) => ( 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) => ( 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)} diff --git a/frontend/src/index.css b/frontend/src/index.css index 3a678cc..34f3014 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -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; diff --git a/frontend/src/melodies/MelodyList.jsx b/frontend/src/melodies/MelodyList.jsx index 92779ff..a6a98db 100644 --- a/frontend/src/melodies/MelodyList.jsx +++ b/frontend/src/melodies/MelodyList.jsx @@ -1300,14 +1300,14 @@ export default function MelodyList() { - {pagedRows.map((row) => ( + {pagedRows.map((row, index) => ( 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) => ( - {archetypes.map((m) => { + {archetypes.map((m, index) => { const assignedCount = getVerifiedAssignedCount(m); return ( 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" }} > {m.name} diff --git a/frontend/src/settings/StaffList.jsx b/frontend/src/settings/StaffList.jsx index b625960..2e510fa 100644 --- a/frontend/src/settings/StaffList.jsx +++ b/frontend/src/settings/StaffList.jsx @@ -141,14 +141,14 @@ export default function StaffList() { - {staff.map((member) => ( + {staff.map((member, index) => ( 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")} > {member.name} diff --git a/frontend/src/users/UserList.jsx b/frontend/src/users/UserList.jsx index d923522..b895724 100644 --- a/frontend/src/users/UserList.jsx +++ b/frontend/src/users/UserList.jsx @@ -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)}