3.4 KiB
Plan 05-01: Streak, Stats, Weekend Styling, Week Start
Phase: 5 — Polish Requirements: POLI-01, POLI-02, POLI-03 + start-of-week preference Estimated tasks: 6
Goal
Add streak indicator, summary stats row, weekend cell styling, and configurable week start to the heatmap widget.
Tasks
Task 1: Add week start to PHP widget data
File: Widget/HeatmapWidget.php
Action: In getData(), read $user->getFirstDayOfWeek() and include it in the returned array as 'weekStart'.
File: Resources/views/widget/heatmap.html.twig
Action: Add data-week-start="{{ data.weekStart }}" to the #heatmap-container div.
Task 2: Make week start configurable in TypeScript
File: assets/src/heatmap.ts
Changes:
- In
init(), readdata-week-startattribute from container (default:'monday') - Pass
weekStartstring torenderHeatmap()via a new optional parameter - In
generateCells(), replace hardcodedtimeMondaywith the appropriate d3 time interval based onweekStart:'sunday'→timeSunday(import from d3-time)'monday'→timeMonday(existing)
- Update
DAY_LABELSto rotate based on week start - Update
dayOfWeekcalculation to match (row 0 = first day of week)
Task 3: Add weekend cell styling
File: assets/src/heatmap.ts
Changes:
- In
generateCells(), addisWeekend: booleantoDayCellinterface (Saturday=6, Sunday=0 in JSgetDay()) - In the cell rendering
.attr('class', ...), appendheatmap-weekendclass for weekend cells
File: Resources/public/heatmap.css
Add:
.heatmap-weekend {
opacity: 0.8;
}
.heatmap-weekend:hover {
opacity: 0.65;
}
Task 4: Add streak calculation
File: assets/src/heatmap.ts
Add function calculateStreak(days: DayEntry[]): number:
- Sort days by date descending
- Starting from today (or yesterday if today has no entry), count consecutive calendar days with entries
- Return the count
- A day with
hours > 0counts as tracked
Task 5: Add summary stats calculation
File: assets/src/heatmap.ts
Add function calculateStats(days: DayEntry[]): { totalHours: number, avgHours: number, busiestDay: { date: string, hours: number } | null }:
totalHours: sum of all hours, rounded to 1 decimalavgHours: total hours / number of days with entries, rounded to 1 decimalbusiestDay: day entry with maximum hours
Task 6: Render streak and stats below heatmap
File: assets/src/heatmap.ts
In init(), after renderHeatmap() resolves:
- Call
calculateStreak()andcalculateStats()with the fetched data - Create a stats row div below the SVG area with class
heatmap-stats - Content:
🔥 N days | Total: Xh | Avg: Xh/day | Busiest: Mon, Mar 15 — Xh - When filter changes and data reloads, recalculate and update stats
File: Resources/public/heatmap.css
Add:
.heatmap-stats {
display: flex;
gap: 16px;
padding: 8px 0 0;
font-size: 0.8125rem;
color: var(--tblr-secondary, #6c757d);
flex-wrap: wrap;
}
.heatmap-stats .stat-value {
color: var(--tblr-body-color);
font-weight: 600;
}
Verification
npm run buildsucceeds- Widget shows streak count, three stat values, weekend cells with reduced opacity
- Changing week start preference changes grid layout and labels
- Filter change recalculates stats
Commit
feat: add streak, stats, weekend styling, week-start preference