fix: match Project View grid lines to Resource View

The Project View used its own buildProjectRowGridBackground() which
rendered CSS gradients with hardcoded rgba colors (no dark mode).
The Resource View used shared gridLines from useTimelineLayout which
renders React div elements with proper dark: Tailwind classes.

Fix: replaced the CSS gradient approach with the shared gridLines
in both resource rows and open demand rows within the Project View.
Removed the now-unused buildProjectRowGridBackground function (~40 LOC).

Both views now use identical grid lines with:
- Brand-colored today marker
- Amber weekend highlights
- Proper dark mode colors via Tailwind classes

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-03-24 11:46:43 +01:00
parent c865a9e8cc
commit ea02ca7106
@@ -137,47 +137,6 @@ type ProjectFlatRow =
const EMPTY_DAY_METRICS: ProjectDayMetric[] = []; const EMPTY_DAY_METRICS: ProjectDayMetric[] = [];
const SVG_XMLNS = "http://www.w3.org/2000/svg"; const SVG_XMLNS = "http://www.w3.org/2000/svg";
function buildProjectRowGridBackground(dates: Date[], CELL_WIDTH: number, today: Date) {
const gradientLayers: string[] = [
`repeating-linear-gradient(to right, transparent 0, transparent ${Math.max(
CELL_WIDTH - 1,
0,
)}px, rgba(229, 231, 235, 1) ${Math.max(CELL_WIDTH - 1, 0)}px, rgba(229, 231, 235, 1) ${CELL_WIDTH}px)`,
];
dates.forEach((date, index) => {
const left = index * CELL_WIDTH;
const right = left + CELL_WIDTH;
const isToday = date.toDateString() === today.toDateString();
const isSaturday = date.getDay() === 6;
const isSunday = date.getDay() === 0;
if (isSaturday) {
gradientLayers.push(
`linear-gradient(to right, transparent ${left}px, rgba(254, 243, 199, 0.4) ${left}px, rgba(254, 243, 199, 0.4) ${right}px, transparent ${right}px)`,
);
} else if (isSunday) {
gradientLayers.push(
`linear-gradient(to right, transparent ${left}px, rgba(243, 244, 246, 0.6) ${left}px, rgba(243, 244, 246, 0.6) ${right}px, transparent ${right}px)`,
);
}
if (isToday) {
gradientLayers.push(
`linear-gradient(to right, transparent ${left}px, rgba(110, 231, 183, 0.95) ${left}px, rgba(110, 231, 183, 0.95) ${Math.min(
left + 2,
right,
)}px, transparent ${Math.min(left + 2, right)}px)`,
);
}
});
return {
backgroundImage: gradientLayers.join(", "),
backgroundRepeat: "no-repeat",
} as const;
}
// ─── Component ────────────────────────────────────────────────────────────── // ─── Component ──────────────────────────────────────────────────────────────
function TimelineProjectPanelInner({ function TimelineProjectPanelInner({
@@ -432,11 +391,6 @@ function TimelineProjectPanelInner({
const virtualItems = rowVirtualizer.getVirtualItems(); const virtualItems = rowVirtualizer.getVirtualItems();
const totalRowHeight = rowVirtualizer.getTotalSize(); const totalRowHeight = rowVirtualizer.getTotalSize();
const resourceRowGridStyle = useMemo(
() => buildProjectRowGridBackground(dates, CELL_WIDTH, today),
[CELL_WIDTH, dates, today],
);
const resourcesWithVacations = useMemo(() => { const resourcesWithVacations = useMemo(() => {
const result = new Set<string>(); const result = new Set<string>();
for (const [resourceId, vacations] of vacationsByResource) { for (const [resourceId, vacations] of vacationsByResource) {
@@ -713,7 +667,7 @@ function TimelineProjectPanelInner({
totalCanvasWidth, totalCanvasWidth,
toLeft, toLeft,
toWidth, toWidth,
resourceRowGridStyle, gridLines,
onOpenDemandClick, onOpenDemandClick,
onAllocMouseDown, onAllocMouseDown,
onAllocTouchStart, onAllocTouchStart,
@@ -750,7 +704,6 @@ function TimelineProjectPanelInner({
width: totalCanvasWidth, width: totalCanvasWidth,
height: ROW_HEIGHT, height: ROW_HEIGHT,
touchAction: "none", touchAction: "none",
...resourceRowGridStyle,
}} }}
onMouseDown={(e) => { onMouseDown={(e) => {
const rect = e.currentTarget.getBoundingClientRect(); const rect = e.currentTarget.getBoundingClientRect();
@@ -776,6 +729,7 @@ function TimelineProjectPanelInner({
}} }}
onMouseLeave={clearHoverTooltips} onMouseLeave={clearHoverTooltips}
> >
{gridLines}
{renderProjectUtilOverlay( {renderProjectUtilOverlay(
projectRowMetrics.get(row.metricsKey) ?? EMPTY_DAY_METRICS, projectRowMetrics.get(row.metricsKey) ?? EMPTY_DAY_METRICS,
CELL_WIDTH, CELL_WIDTH,
@@ -889,7 +843,7 @@ function renderOpenDemandRow(
totalCanvasWidth: number, totalCanvasWidth: number,
toLeft: (d: Date) => number, toLeft: (d: Date) => number,
toWidth: (s: Date, e: Date) => number, toWidth: (s: Date, e: Date) => number,
rowGridStyle: CSSProperties, rowGridLines: React.ReactNode,
_onOpenDemandClick: (demand: OpenDemandAssignment) => void, _onOpenDemandClick: (demand: OpenDemandAssignment) => void,
onAllocMouseDown: (e: React.MouseEvent, info: AllocMouseDownInfo) => void, onAllocMouseDown: (e: React.MouseEvent, info: AllocMouseDownInfo) => void,
onAllocTouchStart: (e: React.TouchEvent, info: AllocMouseDownInfo) => void, onAllocTouchStart: (e: React.TouchEvent, info: AllocMouseDownInfo) => void,
@@ -934,8 +888,9 @@ function renderOpenDemandRow(
<div <div
className="relative overflow-hidden bg-amber-50 touch-none dark:bg-slate-950" className="relative overflow-hidden bg-amber-50 touch-none dark:bg-slate-950"
style={{ width: totalCanvasWidth, height: rowHeight, ...rowGridStyle }} style={{ width: totalCanvasWidth, height: rowHeight }}
> >
{rowGridLines}
<div className="pointer-events-none absolute inset-x-0 inset-y-0 border-y border-dashed border-amber-200/70 dark:border-amber-800/80" /> <div className="pointer-events-none absolute inset-x-0 inset-y-0 border-y border-dashed border-amber-200/70 dark:border-amber-800/80" />
<div className="pointer-events-none absolute inset-x-0 inset-y-1 rounded-md bg-amber-100/25 dark:bg-amber-950/35" /> <div className="pointer-events-none absolute inset-x-0 inset-y-1 rounded-md bg-amber-100/25 dark:bg-amber-950/35" />
{openDemands.map((alloc) => { {openDemands.map((alloc) => {