diff --git a/CHANGELOG.md b/CHANGELOG.md
index f185363..eefebd7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Added button routing to HR Zones config on the home screen
- Added info panel displaying the initial sync status
- Enabled account deletion
+- Added a toggle button to switch between time and percentage views for weekly summaries
#### Changed
- Changed time in zone calculation to be based on moving time instead of elapsed time
diff --git a/backend/api/templates/api/changelog.html b/backend/api/templates/api/changelog.html
index 9d1c64f..b5e4bec 100644
--- a/backend/api/templates/api/changelog.html
+++ b/backend/api/templates/api/changelog.html
@@ -76,6 +76,7 @@
Added
Button routing to HR Zones config on the home screen
Info panel displaying the initial sync status
Enabled account deletion
+
Added a toggle button to switch between time and percentage views for weekly summaries
Changed
diff --git a/extension/content.js b/extension/content.js
index 211972c..21eb407 100644
--- a/extension/content.js
+++ b/extension/content.js
@@ -1,6 +1,11 @@
const MONTHLY_SUMMARY_ID = 'hr-zones-monthly-summary-container';
const WEEKLY_SUMMARY_CLASS = 'injected-weekly-hr-summary';
+// --- State ---
+let showWeeklyAsPercentage = true;
+let currentMonthData = null; // To store data for re-renders
+
+
const PRODUCTION_DOMAIN = 'https://strava-zones.com';
const DEVELOPMENT_DOMAIN = 'https://localhost:8000';
const IS_PRODUCTION_BUILD = false; // Set to true for production builds
@@ -119,78 +124,124 @@ function renderMonthlySummary(monthKey, data) {
}
contentHtml += '';
summaryContainer.innerHTML = contentHtml;
+
+ // Add toggle for weekly view
+ const toggleContainer = document.createElement('div');
+ toggleContainer.className = 'strava-zones-toggle-container';
+ toggleContainer.innerHTML = `
+
+
+ `;
+ summaryContainer.appendChild(toggleContainer);
+
+ const toggleInput = document.getElementById('weekly-view-toggle-input');
+ const toggleLabel = document.getElementById('weekly-view-toggle-label');
+
+ function updateToggleLabel() {
+ if (toggleLabel) {
+ toggleLabel.textContent = showWeeklyAsPercentage ? 'Weekly: by %' : 'Weekly: by time';
+ }
+ }
+
+ if (toggleInput) {
+ updateToggleLabel(); // Set initial state
+ toggleInput.addEventListener('change', (event) => {
+ showWeeklyAsPercentage = event.target.checked;
+ updateToggleLabel();
+ if (currentMonthData) {
+ renderWeeklySummaries(currentMonthData);
+ }
+ });
+ }
+
console.log(`Monthly summary for ${monthKey} rendered.`);
}
function renderWeeklySummaries(data) {
+ // Clear previously injected weekly summaries to handle re-renders
+ document.querySelectorAll('.strava-zones-weekly-summary-cell').forEach(el => el.remove());
+
const weekRowSelector = 'table.month-calendar.marginless tbody tr';
const weekRows = document.querySelectorAll(weekRowSelector);
- if (!weekRows.length) {
- console.warn(`No week rows found with selector: '${weekRowSelector}'. Weekly summaries not rendered.`);
- return;
- }
-
- // Dynamically generate orderedSimplifiedZoneKeys from data.zoneDefinitions
- const simplifiedZoneKeys = Object.keys(data.zoneDefinitions || {});
- if (simplifiedZoneKeys.length === 0) {
- console.warn("No zone definitions found in data.zoneDefinitions for weekly summaries. Cannot render.");
+ if (!weekRows.length || !data.weeklySummaries) {
+ console.warn('ZoneLens: Calendar week rows or weekly summaries not found for rendering.');
return;
}
- simplifiedZoneKeys.sort((a, b) => {
+ const orderedSimplifiedZoneKeys = Object.keys(data.zoneDefinitions || {}).sort((a, b) => {
const numA = parseInt(a.replace('zone', ''), 10);
const numB = parseInt(b.replace('zone', ''), 10);
- return numA - numB;
+ return numB - numA; // descending
});
- const orderedSimplifiedZoneKeys = simplifiedZoneKeys.reverse();
- weekRows.forEach((row, index) => {
- if (data.weeklySummaries && data.weeklySummaries[index] && data.weeklySummaries[index].zone_times_seconds) {
- const weeklyActivityZoneTimes = data.weeklySummaries[index].zone_times_seconds;
+ if (orderedSimplifiedZoneKeys.length === 0) {
+ console.warn("No zone definitions found for weekly summaries.");
+ return;
+ }
- let totalWeekSeconds = 0;
- for (const key of orderedSimplifiedZoneKeys) {
- const actualName = data.zoneDefinitions[key];
- if (actualName && weeklyActivityZoneTimes[actualName]) {
- totalWeekSeconds += weeklyActivityZoneTimes[actualName];
+ let maxSingleZoneTimeInMonth = 0;
+ if (!showWeeklyAsPercentage) {
+ for (const week of data.weeklySummaries) {
+ if (week.zone_times_seconds) {
+ for (const time of Object.values(week.zone_times_seconds)) {
+ if (time > maxSingleZoneTimeInMonth) {
+ maxSingleZoneTimeInMonth = time;
+ }
}
}
+ }
+ }
- if (totalWeekSeconds > 0) {
- const panelContainer = document.createElement('div');
- panelContainer.className = WEEKLY_SUMMARY_CLASS;
+ weekRows.forEach((row, index) => {
+ if (data.weeklySummaries[index] && data.weeklySummaries[index].zone_times_seconds) {
+ const weeklyActivityZoneTimes = data.weeklySummaries[index].zone_times_seconds;
+ const totalWeekSeconds = Object.values(weeklyActivityZoneTimes).reduce((sum, time) => sum + time, 0);
- let panelHtml = '';
+ if (totalWeekSeconds > 0) {
+ let summaryHtml = '';
for (const simplifiedZoneKey of orderedSimplifiedZoneKeys) {
const zoneNumberStr = simplifiedZoneKey.replace('zone', '');
+ const zoneName = data.zoneDefinitions[simplifiedZoneKey] || `Zone ${zoneNumberStr}`;
+ const timeInZone = weeklyActivityZoneTimes[zoneName] || 0;
- const actualUserDefinedName = data.zoneDefinitions[simplifiedZoneKey];
- const timeSeconds = actualUserDefinedName ? (weeklyActivityZoneTimes[actualUserDefinedName] || 0) : 0;
+ const percentage = totalWeekSeconds > 0 ? (timeInZone / totalWeekSeconds) * 100 : 0;
+ const timeFormatted = formatSecondsToHms(timeInZone);
- const percentage = totalWeekSeconds > 0 ? (timeSeconds / totalWeekSeconds) * 100 : 0;
- const timeFormatted = formatSecondsToHms(timeSeconds);
+ let barWidthPercentage;
+ if (showWeeklyAsPercentage) {
+ barWidthPercentage = percentage;
+ } else {
+ barWidthPercentage = maxSingleZoneTimeInMonth > 0 ? (timeInZone / maxSingleZoneTimeInMonth) * 100 : 0;
+ }
- panelHtml += `
-