PatchHub

← patchhub/habit-tracker

Weekly summary of habits at the top of the page

Published ✓ Safe by @theo 0 users2 votes 2 files changed (+100 −0)

Adds a "This week" box above your habits showing how many days you've done each habit so far this week (e.g. "4 of 7 days") with a green bar for easy comparison. It updates when you mark days and resets when a new week starts, using your region's usual first day of the week.

What it does

- Add a "This week" summary section placed above the habit list (below the add-habit form). Hidden when there are no habits. - Heading text: "This week". Below it, a subtitle showing the week's date range (start date – end date, using the app's existing pretty date format) followed by " · day N of 7", where N is how many days of the current week have elapsed including today (1-7). - The week's first day is determined from the browser locale (Intl.Locale of navigator.language, using getWeekInfo() or weekInfo.firstDay, where 7 means Sunday). If unavailable or on error, default to Monday. - For each habit, show one row: habit name, a horizontal progress bar, and text "<count> of 7 days" with the count in bold. The bar fill width is count/7 of the full width. - Count = number of days from the start of the current week through today on which the habit is marked done. Counts reset to zero automatically when a new week begins. - Each row has a tooltip: "<habit name>: done <count> day(s) this week" (singular "day" when count is 1). - Summary re-renders whenever the habit list re-renders (marking done today, toggling a square in the 30-day grid, adding, renaming, deleting). - Styling: card-like box matching existing cards (background, border, rounded corners, padding), rows separated by thin lines, bar uses the app's accent (green) color on the existing empty-color track. - Habit names are inserted as plain text, not HTML. - Add a README bullet "Weekly summary" describing the feature.

Safety check ✓ Safe

The changes are limited to display code, styling, and a README line. There are no network requests, new dependencies, or access to anything beyond the existing habit data, and habit names are inserted as plain text. The AI noted it hasn't tested the page in a browser, so a quick visual check is worthwhile.

Conversation that created this patch
@theo
Add a weekly summary showing how many days each habit was done this week.
AI
I've added a "This week" box at the top of the page, above your habits. It lists every habit with how many days you've done it this week, like "4 of 7 days", plus a green bar so you can compare habits at a glance. It also shows the week's dates and which day of the week you're on. It updates as soon as you mark a day done or fill one in on the 30-day grid. When a new week begins, the counts go back to zero. The week starts on the usual day for your region, Sunday or Monday, based on your browser's settings. If the browser can't tell, it uses Monday. I also added a line about the summary to the README. I checked the code for errors, but I couldn't open the page in a browser here, so please give it a quick look on your end.
Code changes (for the curious, 2 files) · raw
README.md +1 −0
@@ -8,6 +8,7 @@ A simple habit tracker that runs entirely in your web browser. No installation,
- **Check them off** – click **Mark done today** each day you do the habit. Click it again to undo.
- **See your streak** – each habit shows how many days in a row you've kept it up. If you haven't checked it off yet today, your streak from yesterday still counts until the day is over.
- **30-day grid** – a row of squares shows the last 30 days (oldest on the left, today on the right). Green means done. Click any square to fix a day you forgot to mark.
+- **Weekly summary** – a "This week" box at the top shows how many days each habit was done so far this week (for example "4 of 7 days"), with a bar to compare at a glance. The week starts on the usual day for your region (Sunday or Monday) and resets automatically.
- **Rename or delete** habits with the buttons next to each one.
## How to start it
index.html +99 −0
@@ -138,6 +138,33 @@
font-size: 0.8rem;
margin-top: 4px;
}
+ .week-summary {
+ background: var(--card);
+ border: 1px solid var(--border);
+ border-radius: 12px;
+ padding: 16px;
+ margin-bottom: 20px;
+ }
+ .week-summary h2 { margin: 0; font-size: 1.15rem; }
+ .week-range { color: var(--muted); font-size: 0.9rem; margin: 2px 0 12px; }
+ .week-row {
+ display: grid;
+ grid-template-columns: minmax(80px, 1.2fr) 2fr auto;
+ align-items: center;
+ gap: 12px;
+ padding: 6px 0;
+ }
+ .week-row + .week-row { border-top: 1px solid var(--border); }
+ .week-name { font-weight: 600; word-break: break-word; }
+ .week-bar {
+ height: 10px;
+ border-radius: 5px;
+ background: var(--empty);
+ overflow: hidden;
+ }
+ .week-bar-fill { height: 100%; background: var(--accent); border-radius: 5px; }
+ .week-count { color: var(--muted); font-size: 0.95rem; white-space: nowrap; }
+ .week-count strong { color: var(--text); }
.hint {
color: var(--muted);
font-size: 0.85rem;
@@ -160,6 +187,8 @@
<button type="submit" class="primary">Add habit</button>
</form>
+ <section class="week-summary" id="weekSummary" hidden></section>
+
<div id="habitList"></div>
<p class="hint">Tip: click any square in the 30-day grid to mark or unmark that day.
@@ -234,6 +263,28 @@
}
return count;
}
+ // First day of the week for the user's region (0 = Sunday, 1 = Monday, ...).
+ // Uses the browser's regional settings when available, otherwise Monday.
+ function weekStartDay() {
+ try {
+ var loc = new Intl.Locale(navigator.language || "en");
+ var info = typeof loc.getWeekInfo === "function" ? loc.getWeekInfo() : loc.weekInfo;
+ if (info && info.firstDay >= 1 && info.firstDay <= 7) return info.firstDay % 7;
+ } catch (e) { /* fall through */ }
+ return 1;
+ }
+ var WEEK_START = weekStartDay();
+ // How many days of the current week have passed, counting today (1-7).
+ function daysIntoWeek() {
+ return ((daysAgo(0).getDay() - WEEK_START + 7) % 7) + 1;
+ }
+ function doneThisWeek(habit) {
+ var count = 0;
+ for (var i = 0; i < daysIntoWeek(); i++) {
+ if (habit.done[dateKey(daysAgo(i))]) count++;
+ }
+ return count;
+ }
function toggleDay(habit, key) {
if (habit.done[key]) delete habit.done[key];
else habit.done[key] = true;
@@ -253,6 +304,7 @@
});
listEl.innerHTML = "";
+ renderWeekSummary();
if (habits.length === 0) {
var empty = document.createElement("div");
@@ -358,6 +410,53 @@
});
}
+ function renderWeekSummary() {
+ var box = document.getElementById("weekSummary");
+ box.innerHTML = "";
+ if (habits.length === 0) { box.hidden = true; return; }
+ box.hidden = false;
+
+ var soFar = daysIntoWeek();
+ var heading = document.createElement("h2");
+ heading.textContent = "This week";
+ var range = document.createElement("p");
+ range.className = "week-range";
+ range.textContent = prettyDate(daysAgo(soFar - 1)) + " – " + prettyDate(daysAgo(soFar - 7)) +
+ " · day " + soFar + " of 7";
+ box.appendChild(heading);
+ box.appendChild(range);
+
+ habits.forEach(function (habit) {
+ var count = doneThisWeek(habit);
+ var row = document.createElement("div");
+ row.className = "week-row";
+
+ var name = document.createElement("div");
+ name.className = "week-name";
+ name.textContent = habit.name;
+
+ var bar = document.createElement("div");
+ bar.className = "week-bar";
+ var fill = document.createElement("div");
+ fill.className = "week-bar-fill";
+ fill.style.width = (count / 7 * 100) + "%";
+ bar.appendChild(fill);
+
+ var countEl = document.createElement("div");
+ countEl.className = "week-count";
+ var strong = document.createElement("strong");
+ strong.textContent = count;
+ countEl.appendChild(strong);
+ countEl.appendChild(document.createTextNode(" of 7 days"));
+
+ row.title = habit.name + ": done " + count + (count === 1 ? " day" : " days") + " this week";
+ row.appendChild(name);
+ row.appendChild(bar);
+ row.appendChild(countEl);
+ box.appendChild(row);
+ });
+ }
+
// ---------- Adding habits ----------
document.getElementById("addForm").addEventListener("submit", function (e) {
e.preventDefault();