From d16a91e7c900fa6f45b3b5f2b4fcaf4a0d35da32 Mon Sep 17 00:00:00 2001 From: Guy Sandler Date: Sat, 3 Oct 2026 16:02:08 -0700 Subject: [PATCH] popup organizing+2digit%+hide tasks when complete on card tasks --- _locales/de/messages.json | 7 ++- _locales/en/messages.json | 3 ++ _locales/es/messages.json | 7 ++- _locales/fr/messages.json | 7 ++- _locales/it/messages.json | 7 ++- _locales/ja/messages.json | 7 ++- _locales/pt_PT/messages.json | 7 ++- _locales/ru/messages.json | 7 ++- _locales/sv/messages.json | 7 ++- _locales/zh_CN/messages.json | 7 ++- _locales/zh_TW/messages.json | 7 ++- css/popup.css | 10 ++++ html/popup.html | 89 +++++++++++++++++++++--------------- js/background.js | 1 + js/content.js | 30 ++++++------ js/popup.js | 39 ++++++++++++++++ 16 files changed, 171 insertions(+), 71 deletions(-) diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 218cee7..be8bbce 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -75,7 +75,7 @@ "message": "Nur beim Hover anzeigen" }, "card_letter": { - "message": "Notenbuchstaben anzeigen" + "message": "Notenbuchstaben anzeigen" }, "due": { "message": "Fällig" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "Neues Canvas ausblenden" + }, + "hide_completed_cards": { + "message": "Abgeschlossene ausblenden" } -} \ No newline at end of file +} diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 99c03d3..b72bcab 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -337,5 +337,8 @@ }, "grade_analytics_zones": { "message": "Colored grade zones" + }, + "hide_completed_cards": { + "message": "Hide Completed" } } diff --git a/_locales/es/messages.json b/_locales/es/messages.json index ef44f8c..0340175 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -75,7 +75,7 @@ "message": "Mostrar solo al pasar el mouse" }, "card_letter": { - "message": "Mostrar letra de la nota" + "message": "Mostrar letra de la nota" }, "due": { "message": "Pendiente" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "Ocultar nuevo Canvas" + }, + "hide_completed_cards": { + "message": "Ocultar completadas" } -} \ No newline at end of file +} diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index 6d0c726..de97d66 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -75,7 +75,7 @@ "message": "Afficher uniquement au survol" }, "card_letter": { - "message": "Afficher la note en lettres" + "message": "Afficher la note en lettres" }, "due": { "message": "Exigible" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "Masquer le nouveau Canvas" + }, + "hide_completed_cards": { + "message": "Masquer les devoirs terminés" } -} \ No newline at end of file +} diff --git a/_locales/it/messages.json b/_locales/it/messages.json index 4ee0715..80221b2 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -75,7 +75,7 @@ "message": "Mostra solo al passaggio del mouse" }, "card_letter": { - "message": "Mostra voto in lettere" + "message": "Mostra voto in lettere" }, "due": { "message": "Dovuto" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "Nascondi nuovo Canvas" + }, + "hide_completed_cards": { + "message": "Nascondi completati" } -} \ No newline at end of file +} diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index bae057a..620b59c 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -75,7 +75,7 @@ "message": "ホバー時のみ表示" }, "card_letter": { - "message": "成績をアルファベットで表示" + "message": "成績をアルファベットで表示" }, "due": { "message": "期限" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "新しい Canvas を非表示" + }, + "hide_completed_cards": { + "message": "完了した課題を非表示" } -} \ No newline at end of file +} diff --git a/_locales/pt_PT/messages.json b/_locales/pt_PT/messages.json index cd539e3..5e21f1d 100644 --- a/_locales/pt_PT/messages.json +++ b/_locales/pt_PT/messages.json @@ -75,7 +75,7 @@ "message": "Mostrar apenas ao passar o mouse" }, "card_letter": { - "message": "Mostrar nota em letra" + "message": "Mostrar nota em letra" }, "due": { "message": "Devido" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "Ocultar novo Canvas" + }, + "hide_completed_cards": { + "message": "Ocultar concluídas" } -} \ No newline at end of file +} diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 775451f..d8a1e40 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -75,7 +75,7 @@ "message": "Показывать только при наведении" }, "card_letter": { - "message": "Показывать буквенную оценку" + "message": "Показывать буквенную оценку" }, "due": { "message": "Должный" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "Скрыть новый Canvas" + }, + "hide_completed_cards": { + "message": "Скрыть выполненные" } -} \ No newline at end of file +} diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 1cb656c..6af3c05 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -75,7 +75,7 @@ "message": "Visa endast vid svävning" }, "card_letter": { - "message": "Visa bokstavsbetyg" + "message": "Visa bokstavsbetyg" }, "due": { "message": "Förfaller" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "Dölj ny Canvas" + }, + "hide_completed_cards": { + "message": "Dölj färdiga" } -} \ No newline at end of file +} diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json index ab34cd8..87db05e 100644 --- a/_locales/zh_CN/messages.json +++ b/_locales/zh_CN/messages.json @@ -75,7 +75,7 @@ "message": "仅在悬停时显示" }, "card_letter": { - "message": "显示字母成绩" + "message": "显示字母成绩" }, "due": { "message": "到期的" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "隐藏新版 Canvas" + }, + "hide_completed_cards": { + "message": "隐藏已完成的作业" } -} \ No newline at end of file +} diff --git a/_locales/zh_TW/messages.json b/_locales/zh_TW/messages.json index ea07424..32eb7aa 100644 --- a/_locales/zh_TW/messages.json +++ b/_locales/zh_TW/messages.json @@ -75,7 +75,7 @@ "message": "仅在悬停时显示" }, "card_letter": { - "message": "顯示字母成績" + "message": "顯示字母成績" }, "due": { "message": "到期的" @@ -253,5 +253,8 @@ }, "hide_new_canvas": { "message": "隱藏新版 Canvas" + }, + "hide_completed_cards": { + "message": "隱藏已完成的作業" } -} \ No newline at end of file +} diff --git a/css/popup.css b/css/popup.css index 97c5431..8c47183 100644 --- a/css/popup.css +++ b/css/popup.css @@ -84,6 +84,16 @@ h2 {margin-top: 20px;font-weight:600} #todo_timeframe option {background:#1e1e1e;color:#e2e2e2;} #todo_timeframe option:checked, #todo_timeframe option:hover {background:#2e2e2e;color:#fff;} +/* Collapsible "More options" section for the Better Todo List sub-options */ +.todo-more-options {margin-top: 7px;} +.todo-more-toggle {display: flex;align-items:center;gap:5px;font-size:12px;color:#a7a7a7;cursor:pointer;user-select:none;padding:3px 0;border-radius:5px;transition:color .1s;} +.todo-more-toggle:hover {color:#e2e2e2;} +.todo-more-toggle svg {flex:none;transition:transform .15s ease;} +.todo-more-options.expanded .todo-more-toggle svg {transform: rotate(90deg);} +.todo-more-toggle .todo-expanded-label {display:none;} +.todo-more-options.expanded .todo-expanded-label {display:inline;} +.todo-more-items {display:none;flex-direction:column;} +.todo-more-options.expanded .todo-more-items {display:flex;padding-left:2px;} #advanced-settings, #gpa-bounds-btn, #custom-font-btn, #customize-dark-btn, #card-colors-btn {width: 100%;} .back-btn {width: 120px;height:100%;margin-top:0} .big-button {border: none;border-radius: 7px;background: var(--containerbg);color: #fff;font-family: inherit;padding: 12px 10px;font-weight:600} diff --git a/html/popup.html b/html/popup.html index 91f2cda..c4dc8dd 100644 --- a/html/popup.html +++ b/html/popup.html @@ -122,6 +122,10 @@ +
+ + +
@@ -268,26 +272,7 @@ Better Todo List
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
+
- - -
- -
- - -
-
- - -
-
- - + +
+
+ + +
+
+ + +
Max items to show:
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+
diff --git a/js/background.js b/js/background.js index 9af703a..7cc4865 100644 --- a/js/background.js +++ b/js/background.js @@ -53,6 +53,7 @@ chrome.runtime.onInstalled.addListener(function () { "grade_hover": false, "card_letter": true, // "hide_completed": false, + "hide_completed_cards": false, "num_todo_items": 10, "custom_font": { "link": "", "family": "" }, "hover_preview": true, diff --git a/js/content.js b/js/content.js index 46110ad..eb84c5b 100644 --- a/js/content.js +++ b/js/content.js @@ -1071,6 +1071,10 @@ function applyOptionsChanges(changes) { // Stretch or reset card heights in place instead of rebuilding rows. equalizeCardHeights(); break; + case "hide_completed_cards": + // Assignment elements are already preloaded; just re-filter the render. + loadCardAssignments(); + break; case "custom_cards": customizeCards(); // Hiding/unhiding a card changes which courses appear in the todo @@ -9374,9 +9378,9 @@ function renderGaStats() { // graded assignments (green climbing, red falling, grey steady). let trendVal = "-", trendColor = "var(--bctext-0)"; if (gaData.trend != null) { - if (gaData.trend > 0.05) { trendVal = "\u25B2 +" + gaData.trend.toFixed(1) + "%"; trendColor = "#16a34a"; } - else if (gaData.trend < -0.05) { trendVal = "\u25BC " + gaData.trend.toFixed(1) + "%"; trendColor = "#dc2626"; } - else { trendVal = "\u25BA " + gaData.trend.toFixed(1) + "%"; trendColor = "var(--bctext-1)"; } + if (gaData.trend > 0.05) { trendVal = "\u25B2 +" + gaData.trend.toFixed(2) + "%"; trendColor = "#16a34a"; } + else if (gaData.trend < -0.05) { trendVal = "\u25BC " + gaData.trend.toFixed(2) + "%"; trendColor = "#dc2626"; } + else { trendVal = "\u25BA " + gaData.trend.toFixed(2) + "%"; trendColor = "var(--bctext-1)"; } } // Grade goal card from the Final Calculator tab: the score needed on the // final to hit the stored target grade. @@ -9387,11 +9391,11 @@ function renderGaStats() { let val, color; if (needed <= 0) { val = "\u2713 Secured"; color = "#16a34a"; } else if (needed > 100) { val = "Out of reach"; color = "#dc2626"; } - else { val = "\u2265 " + needed.toFixed(1) + "%"; color = gaNeededColor(needed); } + else { val = "\u2265 " + needed.toFixed(2) + "%"; color = gaNeededColor(needed); } goalStat = stat("Final Exam", val, color); } stats.innerHTML = - stat("Overall grade", gaData.current == null ? "-" : gaData.current.toFixed(1) + "%") + + stat("Overall grade", gaData.current == null ? "-" : gaData.current.toFixed(2) + "%") + stat("Grade trend (last 5)", trendVal, trendColor) + stat("Graded", gaData.graded) + stat("Ungraded", gaData.ungraded) + @@ -9511,12 +9515,12 @@ function renderGaCalculator() { let head, sub; if (needed <= 0) { head = `You're already there!`; - sub = `Even a 0 on the final leaves you at ${withZero.toFixed(1)}%, which is above your ${target}% goal.`; + sub = `Even a 0 on the final leaves you at ${withZero.toFixed(2)}%, which is above your ${target}% goal.`; } else if (needed > 100) { head = `Out of reach`; - sub = `Even a perfect final only gets you to ${withPerfect.toFixed(1)}%, which is below your ${target}% goal.`; + sub = `Even a perfect final only gets you to ${withPerfect.toFixed(2)}%, which is below your ${target}% goal.`; } else { - head = `You need ≥ ${needed.toFixed(1)}% on the final`; + head = `You need ≥ ${needed.toFixed(2)}% on the final`; sub = `You got this!`; } box.innerHTML = head + `
${sub}
`; @@ -9626,8 +9630,8 @@ function gaBuildHeatmapData() { function gaHeatmapShowTip(tip, e, cell, avg) { const d = cell.date; const rows = cell.items.map(p => - `
${gaEscHtml(p.title)} — ${p.pct.toFixed(1)}%
`).join(""); - tip.innerHTML = `${months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()} — avg ${avg.toFixed(1)}%
${cell.items.length} assignment${cell.items.length === 1 ? "" : "s"}:
${rows}`; + `
${gaEscHtml(p.title)} — ${p.pct.toFixed(2)}%
`).join(""); + tip.innerHTML = `${months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()} — avg ${avg.toFixed(2)}%
${cell.items.length} assignment${cell.items.length === 1 ? "" : "s"}:
${rows}`; tip.style.display = "block"; const host = tip.offsetParent || tip.parentNode; const hostRect = host.getBoundingClientRect(); @@ -9850,7 +9854,7 @@ function gaDrawLine(canvas, tooltip) { } // Y grid: 5 evenly spaced lines across the current range. ctx.textAlign = "right"; ctx.textBaseline = "middle"; - const decimals = (yMax - yMin) <= 10 ? 1 : 0; + const decimals = (yMax - yMin) <= 1 ? 2 : (yMax - yMin) <= 10 ? 1 : 0; for (let i = 0; i <= 5; i++) { const v = yMin + (yMax - yMin) * (i / 5); const y = pad.t + (1 - (v - yMin) / (yMax - yMin)) * (h - pad.t - pad.b); @@ -10001,7 +10005,7 @@ function gaDrawLine(canvas, tooltip) { } const p = pts[best]; gaShowTooltip(tooltip, X(best), Y(p.grade), - `${p.title}
Overall: ${p.grade == null ? "-" : p.grade.toFixed(1) + "%"}
This: ${p.score}/${p.points} (${p.pct.toFixed(1)}%)${p.due ? `
Due: ${p.due}` : ""}`); + `${p.title}
Overall: ${p.grade == null ? "-" : p.grade.toFixed(2) + "%"}
This: ${p.score}/${p.points} (${p.pct.toFixed(2)}%)${p.due ? `
Due: ${p.due}` : ""}`); }; canvas._gaLeave = () => { tooltip.style.display = "none"; @@ -10149,7 +10153,7 @@ function gaComputeImagineTotal() { // restates the real grade. function gaImagineTotalHtml(pct) { const letter = gaLetterFor(pct); - const pctText = pct == null || !isFinite(pct) ? "—" : pct.toFixed(1) + "%"; + const pctText = pct == null || !isFinite(pct) ? "—" : pct.toFixed(2) + "%"; // The wrapper is an inline-flex row with align-items:center so the // badge pill sits vertically centered with the grade text. No // flex-wrap: the narrow score cell would stack the items instead. diff --git a/js/popup.js b/js/popup.js index e153cdb..b79ef07 100644 --- a/js/popup.js +++ b/js/popup.js @@ -11,6 +11,7 @@ const syncedSubOptions = [ "device_dark", "relative_dues", "card_overdues", + "hide_completed_cards", "equal_height_cards", // "todo_overdues", "gpa_calc_prepend", @@ -174,6 +175,7 @@ const defaultOptions = { }, // "todo_overdues": false, "card_overdues": false, + "hide_completed_cards": false, "relative_dues": false, "equal_height_cards": false, "hide_new_canvas": true, @@ -188,6 +190,7 @@ const defaultOptions = { "todo_full_height": false, "todo_progress_rings": "rings", "todo_timeframe": "all", + "todo_more_expanded": false, "todo_confetti": true, "device_dark": false, "cumulative_gpa": { "name": "Cumulative GPA", "hidden": false, "weight": "dnc", "credits": 999, "gr": 3.21 }, @@ -375,6 +378,31 @@ function setupProgressRingsSelect(initial) { }); } +// Collapsible "More options" section for the Better Todo List sub-options. +// Persists whether it's expanded so the popup reopens in the same state. +function setupTodoMoreOptions(initial) { + const wrap = document.getElementById("todo-more-options"); + const toggle = document.getElementById("todo-more-toggle"); + if (!wrap || !toggle) return; + const setExpanded = (expanded) => { + wrap.classList.toggle("expanded", expanded === true); + toggle.setAttribute("aria-expanded", expanded === true ? "true" : "false"); + }; + setExpanded(initial === true); + const flip = () => { + const expanded = !wrap.classList.contains("expanded"); + setExpanded(expanded); + chrome.storage.sync.set({ "todo_more_expanded": expanded }); + }; + toggle.addEventListener("click", flip); + toggle.addEventListener("keydown", (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + flip(); + } + }); +} + // Timeframe dropdown for the upcoming Tasks tab. Persisted so the Better Todo // List remembers the selected range across sessions. function setupTimeframeSelect(initial) { @@ -857,6 +885,12 @@ function setupFeatureSearch(menu) { if (node.style && node.style.display === "none") node.style.display = ""; node = node.parentElement; } + // Expand the Better Todo "More options" collapsible if the target lives inside it. + const moreWrap = el.closest ? el.closest("#todo-more-options") : null; + if (moreWrap && !moreWrap.classList.contains("expanded")) { + const toggle = document.getElementById("todo-more-toggle"); + if (toggle) toggle.click(); + } } function highlight(el) { @@ -1125,6 +1159,7 @@ function setup() { "device_dark", "relative_dues", "card_overdues", + "hide_completed_cards", "equal_height_cards", // "todo_overdues", "gpa_calc_prepend", @@ -1304,6 +1339,10 @@ function setup() { identifier: "todo_timeframe", setup: (initial) => setupTimeframeSelect(initial), }, + { + identifier: "todo_more_expanded", + setup: (initial) => setupTodoMoreOptions(initial), + }, ], };