From c5cb3ebe4a881bce879b4c4036ea8a496c6fec9c Mon Sep 17 00:00:00 2001 From: jasonMPM Date: Thu, 5 Mar 2026 17:10:30 -0600 Subject: [PATCH] Add files via upload --- .../components/Calendar/WorkloadHeatmap.jsx | 103 +++++++++++++++--- frontend/src/styles/globals.css | 2 +- 2 files changed, 89 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/Calendar/WorkloadHeatmap.jsx b/frontend/src/components/Calendar/WorkloadHeatmap.jsx index 27226fa..437f161 100644 --- a/frontend/src/components/Calendar/WorkloadHeatmap.jsx +++ b/frontend/src/components/Calendar/WorkloadHeatmap.jsx @@ -76,8 +76,8 @@ export default function WorkloadHeatmap() { return labels }, [weeks]) - const CELL = 18 - const GAP = 3 + const CELL = 16 + const GAP = 2 return (
@@ -92,22 +92,95 @@ export default function WorkloadHeatmap() {
- {/* Stat cards by status */} -
- {[ - { key: 'total', label: 'Total', color: 'text-text-primary' }, - { key: 'upcoming', label: 'Upcoming', color: 'text-blue-400' }, - { key: 'in_progress', label: 'In Progress', color: 'text-amber-400' }, - { key: 'completed', label: 'Completed', color: 'text-green-400' }, - { key: 'overdue', label: 'Overdue', color: 'text-red-400' }, - ].map(({ key, label, color }) => ( -
-

{stats[key]}

-

{label}

+ {/* Stat cards + aligned status heatmaps */} +
+ {STATUS_KEYS.map((statusKey) => ( +
+ {/* Stat card */} +
+

+ {stats[statusKey]} +

+

{STATUS_LABEL[statusKey]}

+
+ + {/* Heatmap for this status */} +
+
+ {/* Day labels */} +
+ {DAY_INIT.map((d, i) => ( +
+ {d} +
+ ))} +
+ + {/* Grid */} +
+ {/* Month labels */} +
+ {monthLabels.map(({ wi, label }) => ( + + {label} + + ))} +
+ +
+ {weeks.map((week, wi) => ( +
+ {week.map(({ date, key, items, statusCounts }) => { + const countForStatus = (statusCounts || {})[statusKey] || 0 + const baseDensity = countForStatus + const hoverRing = + statusKey === 'upcoming' ? 'hover:ring-blue-300/80 hover:shadow-[0_0_0_1px_rgba(147,197,253,0.8)]' : + statusKey === 'in_progress' ? 'hover:ring-amber-300/80 hover:shadow-[0_0_0_1px_rgba(252,211,77,0.8)]' : + statusKey === 'completed' ? 'hover:ring-green-300/80 hover:shadow-[0_0_0_1px_rgba(74,222,128,0.8)]' : + statusKey === 'overdue' ? 'hover:ring-red-400/90 hover:shadow-[0_0_0_1px_rgba(248,113,113,0.9)]' : + 'hover:ring-white/60'; + return ( +
{ + if (!items || !items.length) return + const match = items.find(({ deliverable }) => deliverable.status === statusKey) || items[0] + if (match) openFocus(match.project.id, match.deliverable.id) + }} + onMouseEnter={(e) => { + const filtered = (items || []).filter(({ deliverable }) => deliverable.status === statusKey) + const showItems = filtered.length ? filtered : items || [] + setTooltip({ + x: e.clientX, + y: e.clientY, + date, + statusKey, + items: showItems, + }) + }} + onMouseLeave={() => setTooltip(null)} + /> + ) + })} +
+ ))} +
+
+
+
))}
- {/* Multi-row heatmaps by status */}
{STATUS_KEYS.map((statusKey) => ( diff --git a/frontend/src/styles/globals.css b/frontend/src/styles/globals.css index fbd4f04..6fbb5c2 100644 --- a/frontend/src/styles/globals.css +++ b/frontend/src/styles/globals.css @@ -19,7 +19,7 @@ body { .animate-slide-up { animation: slide-up 0.2s ease-out forwards; } /* ── FullCalendar dark theme ── */ -.fc-toolbar.fc-header-toolbar { padding-left: 4.5rem !important; } +.fc-toolbar.fc-header-toolbar { padding-left: 6rem !important; } .fc { --fc-border-color: #2E2E2E;