diff --git a/src/components/HeatMap.tsx b/src/components/HeatMap.tsx new file mode 100644 index 0000000..51922dc --- /dev/null +++ b/src/components/HeatMap.tsx @@ -0,0 +1,130 @@ +import React from "react"; +import * as dFns from "date-fns"; +import * as R from "ramda"; + +interface DateValue { + date: Date; + count: number; +} + +interface Props { + startDate: Date; + endDate: Date; + data: DateValue[]; +} + +const GitHubCalendarHeatmap: React.FC = ({ + startDate, + endDate, + data, + }) => { + // const numDays = dFns.differenceInDays(endDate, startDate); + + // Calculate the number of days in the range + const numDays = Math.ceil( + (endDate.getTime() - startDate.getTime()) / (1000 * 3600 * 24) + ); + + // Calculate the number of weeks in the range + const numWeeks = Math.ceil(numDays / 7); + + // Calculate the size of each square in the heatmap and the padding between each square + const squareSize = 15; + const padding = 2; + const weekTotalPadding = 10; // Extra padding for the week total row + const totalWidth = numWeeks * (squareSize + padding); + const totalHeight = 8 * (squareSize + padding) + weekTotalPadding; // Added an extra row for week total + + // Goal times for the daily and weekly squares + const dayGoalTime = 24; + const weekGoalTime = 5 * dayGoalTime; + + const getColorForValue = (value: number, goalTime: number): string => { + const saturation = Math.min(Math.max(value / goalTime, 0), 1) * 100; // Normalize value to range [0, 1] and then convert to percentage + const color = + saturation === 0 ? "lightgray" : `hsl(180, ${saturation}%, 50%)`; // Hue is fixed at 180 for a pleasant color. You can adjust this as needed. + return color; + }; + + const getWeekTotal = (weekIndex: number): number => { + const weekStart = new Date(startDate); + weekStart.setDate(weekStart.getDate() + weekIndex * 7); + const weekEnd = new Date(weekStart); + weekEnd.setDate(weekEnd.getDate() + 6); + + return data.reduce((total, { + date, + count + }) => { + if (date >= weekStart && date <= weekEnd) { + return total + count; + } + return total; + }, 0); + }; + + const dateValues: DateValue[] = []; + + for ( + let date = new Date(startDate); + date <= endDate; + date.setDate(date.getDate() + 1) + ) { + const foundData = data.find( + ({date: dataDate}) => + dataDate.toISOString().slice(0, 10) === date.toISOString().slice(0, 10) + ); + dateValues.push({ + date: new Date(date), + count: foundData ? foundData.count : 0, + }); + } + + return ( + + {dateValues.map(({ + date, + count + }) => { + const weekIndex = Math.floor( + (date.getTime() - startDate.getTime()) / (1000 * 3600 * 24 * 7) + ); + const dayOfWeek = date.getDay(); + const x = weekIndex * (squareSize + padding); + const y = dayOfWeek * (squareSize + padding); + const color = getColorForValue(count, dayGoalTime); + + return ( + + ); + })} + {Array(numWeeks) + .fill(0) + .map((_, weekIndex) => { + const x = weekIndex * (squareSize + padding); + const y = 7 * (squareSize + padding) + weekTotalPadding; // Position for the week total + const color = getColorForValue(getWeekTotal(weekIndex), weekGoalTime); + + return ( + + ); + })} + + ); +}; + +export default GitHubCalendarHeatmap; diff --git a/src/components/cards/calendarOverviewCard.tsx b/src/components/cards/calendarOverviewCard.tsx index b5692c2..481419d 100644 --- a/src/components/cards/calendarOverviewCard.tsx +++ b/src/components/cards/calendarOverviewCard.tsx @@ -7,6 +7,7 @@ import 'react-calendar-heatmap/dist/styles.css'; import '../../app/calendar-styles.css' import {Tooltip} from 'react-tooltip'; import {Data} from "@/data/fetchData"; +import HeatMap from "@/components/HeatMap"; const granularity = 4; @@ -69,18 +70,20 @@ export function CalendarOverviewCard({ return Overview - `color-github-${computeCompletionShade(value?.count ?? 0, goal)}`} - tooltipDataAttrs={(value: any) => { - return value.date ? { - 'data-tooltip-id': `calendar-tooltip`, - 'data-tooltip-content': value.count ? `${dFns.format(value.date, 'EEE do')}: ${value.count.toFixed(2)} hours` : `${dFns.format(value.date, 'EEE do')}` - } : undefined - }} - /> + + + {/* `color-github-${computeCompletionShade(value?.count ?? 0, goal)}`}*/} + {/* tooltipDataAttrs={(value: any) => {*/} + {/* return value.date ? {*/} + {/* 'data-tooltip-id': `calendar-tooltip`,*/} + {/* 'data-tooltip-content': value.count ? `${dFns.format(value.date, 'EEE do')}: ${value.count.toFixed(2)} hours` : `${dFns.format(value.date, 'EEE do')}`*/} + {/* } : undefined*/} + {/* }}*/} + {/*/>*/} }