(dailyActivity: Record<string, number>, days: number)
| 224 | } |
| 225 | |
| 226 | function renderActivityHeatmap(dailyActivity: Record<string, number>, days: number) { |
| 227 | const termWidth = process.stdout.columns || 80 |
| 228 | const availableWidth = Math.min(termWidth - 10, 80) |
| 229 | const weeksToShow = Math.min(Math.ceil(days / 7), Math.floor(availableWidth / 2)) |
| 230 | const daysToShow = weeksToShow * 7 |
| 231 | |
| 232 | const today = new Date() |
| 233 | today.setHours(0, 0, 0, 0) |
| 234 | |
| 235 | const startDate = new Date(today) |
| 236 | startDate.setDate(startDate.getDate() - daysToShow + 1) |
| 237 | |
| 238 | // adjust to start on Sunday |
| 239 | const dayOfWeek = startDate.getDay() |
| 240 | if (dayOfWeek !== 0) { |
| 241 | startDate.setDate(startDate.getDate() - dayOfWeek) |
| 242 | } |
| 243 | |
| 244 | const maxValue = Math.max(1, ...Object.values(dailyActivity)) |
| 245 | |
| 246 | // build weeks array |
| 247 | const weeks: { date: Date; value: number; level: number }[][] = [] |
| 248 | let currentDate = new Date(startDate) |
| 249 | let currentWeek: { date: Date; value: number; level: number }[] = [] |
| 250 | |
| 251 | while (currentDate <= today) { |
| 252 | const dateKey = currentDate.toISOString().split("T")[0] |
| 253 | const value = dailyActivity[dateKey] || 0 |
| 254 | const level = value === 0 ? 0 : Math.min(4, Math.ceil((value / maxValue) * 4)) |
| 255 | |
| 256 | if (currentDate.getDay() === 0 && currentWeek.length > 0) { |
| 257 | weeks.push(currentWeek) |
| 258 | currentWeek = [] |
| 259 | } |
| 260 | |
| 261 | currentWeek.push({ date: new Date(currentDate), value, level }) |
| 262 | currentDate.setDate(currentDate.getDate() + 1) |
| 263 | } |
| 264 | |
| 265 | if (currentWeek.length > 0) { |
| 266 | weeks.push(currentWeek) |
| 267 | } |
| 268 | |
| 269 | // month labels |
| 270 | const monthLabels: { month: string; position: number }[] = [] |
| 271 | let lastMonth = -1 |
| 272 | for (let i = 0; i < weeks.length; i++) { |
| 273 | const week = weeks[i] |
| 274 | if (!week || week.length === 0) continue |
| 275 | const firstDay = week[0].date |
| 276 | const month = firstDay.getMonth() |
| 277 | if (month !== lastMonth) { |
| 278 | monthLabels.push({ |
| 279 | month: firstDay.toLocaleString("en-US", { month: "short" }), |
| 280 | position: i, |
| 281 | }) |
| 282 | lastMonth = month |
| 283 | } |
no test coverage detected