diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 9d0625c..25a7283 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "Relative Fälligkeitsdaten" }, + "equal_height_cards": { + "message": "Gleiche Höhe" + }, "enter_multiple": { "message": "(Mehrere mit Komma eingeben)" }, diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 763e5c7..6aa66f7 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -122,6 +122,9 @@ "relative_due_dates": { "message": "Relative Due Dates" }, + "equal_height_cards": { + "message": "Equal Height" + }, "enter_multiple": { "message": "(Enter Multiple With A Comma)" }, diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 98f3a62..791af9e 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "Fechas pendientes relativas" }, + "equal_height_cards": { + "message": "Altura igual" + }, "enter_multiple": { "message": "(Ingrese varios con una coma)" }, diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index 9c7670b..3b9f03c 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "Dates d'échéance relatives" }, + "equal_height_cards": { + "message": "Hauteur égale" + }, "enter_multiple": { "message": "(Entrez plusieurs avec une virgule)" }, diff --git a/_locales/it/messages.json b/_locales/it/messages.json index e0ee3b2..3b84286 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "Date di scadenza relative" }, + "equal_height_cards": { + "message": "Altezza uguale" + }, "enter_multiple": { "message": "(Inserisci più numeri con una virgola)" }, diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index 2c2558b..7844d83 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "相対的な期日" }, + "equal_height_cards": { + "message": "高さを揃える" + }, "enter_multiple": { "message": "(カンマで複数入力)" }, diff --git a/_locales/pt_PT/messages.json b/_locales/pt_PT/messages.json index c34d903..615f8f5 100644 --- a/_locales/pt_PT/messages.json +++ b/_locales/pt_PT/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "Datas de vencimento relativas" }, + "equal_height_cards": { + "message": "Altura igual" + }, "enter_multiple": { "message": "(Digite vários com uma vírgula)" }, diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 330510d..a16213a 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "Относительные сроки выполнения" }, + "equal_height_cards": { + "message": "Одинаковая высота" + }, "enter_multiple": { "message": "(Введите несколько через запятую)" }, diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 391df5b..0e59384 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "Relativa förfallodatum" }, + "equal_height_cards": { + "message": "Jämn höjd" + }, "enter_multiple": { "message": "(Ange flera med komma)" }, diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json index f3506ed..72a9006 100644 --- a/_locales/zh_CN/messages.json +++ b/_locales/zh_CN/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "相对到期日" }, + "equal_height_cards": { + "message": "等高" + }, "enter_multiple": { "message": "(用逗号输入多个)" }, diff --git a/_locales/zh_TW/messages.json b/_locales/zh_TW/messages.json index f3506ed..72a9006 100644 --- a/_locales/zh_TW/messages.json +++ b/_locales/zh_TW/messages.json @@ -113,6 +113,9 @@ "relative_due_dates": { "message": "相对到期日" }, + "equal_height_cards": { + "message": "等高" + }, "enter_multiple": { "message": "(用逗号输入多个)" }, diff --git a/html/popup.html b/html/popup.html index 942208c..59530e5 100644 --- a/html/popup.html +++ b/html/popup.html @@ -120,6 +120,10 @@ +
+ + +
Max items to show: diff --git a/js/background.js b/js/background.js index 85aec37..a88bc2c 100644 --- a/js/background.js +++ b/js/background.js @@ -72,6 +72,7 @@ chrome.runtime.onInstalled.addListener(function () { // "todo_overdues": false, "card_overdues": false, "relative_dues": false, + "equal_height_cards": false, "hide_feedback": false, "dark_mode_fix": [], "assignment_states": {}, diff --git a/js/content.js b/js/content.js index 6af0c8a..0db3283 100644 --- a/js/content.js +++ b/js/content.js @@ -663,6 +663,11 @@ function applyOptionsChanges(changes) { cardAssignments = preloadAssignmentEls(); loadCardAssignments(); break; + case "equal_height_cards": + // No need to rebuild the assignment rows — just stretch (or reset) + // the card heights in place for a snappy toggle. + equalizeCardHeights(); + break; case "custom_cards": case "custom_cards_2": case "custom_cards_3": @@ -3537,6 +3542,51 @@ function createCardAssignment(assignment) { let cardAssignments; +/* +Equal Height Cards — when enabled, every dashboard card's assignment area is +stretched to match the tallest one so cards with fewer assignments don't end +up shorter than the rest. Uses min-height (never a fixed height) so cards can +still grow if their content exceeds the tallest card. +*/ +let equalHeightResizeTimer = null; + +function equalizeCardHeights() { + const cards = document.querySelectorAll(".ic-DashboardCard"); + if (cards.length === 0) return; + + const enabled = options.equal_height_cards === true && options.assignments_due === true; + + // Always clear any previously applied min-height first so we can either + // measure natural heights (when enabling) or fully reset (when disabling). + cards.forEach(card => { + const area = card.querySelector(".canvasrefined-card-assignment"); + if (area) area.style.removeProperty("min-height"); + }); + + if (!enabled) return; + + // Measure the natural height of each card's assignment area, then stretch + // every area to the tallest one. Card headers are uniform, so equalizing + // the assignment area makes all cards the same total height. + let maxHeight = 0; + cards.forEach(card => { + const area = card.querySelector(".canvasrefined-card-assignment"); + if (area) maxHeight = Math.max(maxHeight, area.offsetHeight); + }); + + if (maxHeight > 0) { + cards.forEach(card => { + const area = card.querySelector(".canvasrefined-card-assignment"); + if (area) area.style.minHeight = maxHeight + "px"; + }); + } +} + +window.addEventListener("resize", () => { + if (equalHeightResizeTimer) clearTimeout(equalHeightResizeTimer); + equalHeightResizeTimer = setTimeout(equalizeCardHeights, 150); +}); + function preloadAssignmentEls() { return new Promise((resolve, reject) => { let assignmentEls = {}; @@ -3569,6 +3619,7 @@ function loadCardAssignments() { document.querySelectorAll(".canvasrefined-card-assignment").forEach(card => { card.style.display = "none"; }); + equalizeCardHeights(); return; } setupCardAssignments(); @@ -3608,6 +3659,9 @@ function loadCardAssignments() { let assignmentDivLink = makeElement("a", assignmentContainer, { "className": "canvasrefined-assignment-link", "textContent": "None" }); } }); + // Wait one frame so the browser lays out the freshly appended + // assignment rows before measuring/equalizing card heights. + requestAnimationFrame(equalizeCardHeights); } catch (e) { logError(e); } diff --git a/js/popup.js b/js/popup.js index bed498c..dd7d206 100644 --- a/js/popup.js +++ b/js/popup.js @@ -6,6 +6,7 @@ const syncedSubOptions = [ "device_dark", "relative_dues", "card_overdues", + "equal_height_cards", // "todo_overdues", "gpa_calc_prepend", "auto_dark", @@ -112,6 +113,7 @@ const defaultOptions = { // "todo_overdues": false, "card_overdues": false, "relative_dues": false, + "equal_height_cards": false, "hide_feedback": false, "dark_mode_fix": [], "assignment_states": {}, @@ -412,6 +414,25 @@ function toggleBetterTodoSubOptions(betterTodoOn) { } } +// Hide the sub-options of a big toggle when it is turned off. +// For gpa_calc / assignments_due / better_todo the whole .sub-options block is +// hidden. For auto_dark ("schedule dark mode") only the start/end time clocks +// (.timesets) are hidden, leaving the device-dark checkbox visible. +function toggleSubOptionsVisibility(option, isOn) { + const togglesWithSubOptions = ["gpa_calc", "assignments_due", "better_todo", "auto_dark"]; + if (!togglesWithSubOptions.includes(option)) return; + const optionEl = document.getElementById(option); + if (!optionEl) return; + const subOptions = optionEl.parentElement.querySelector(":scope > .sub-options"); + if (!subOptions) return; + if (option === "auto_dark") { + const timesets = subOptions.querySelector(".timesets"); + if (timesets) timesets.style.display = isOn ? "" : "none"; + } else { + subOptions.style.display = isOn ? "" : "none"; + } +} + function setup() { const menu = { @@ -428,6 +449,7 @@ function setup() { "device_dark", "relative_dues", "card_overdues", + "equal_height_cards", // "todo_overdues", "gpa_calc_prepend", "auto_dark", @@ -563,10 +585,14 @@ function setup() { if (option === "better_todo") { toggleBetterTodoSubOptions(status); } + toggleSubOptionsVisibility(option, status); }); }); toggleBetterSidebarSubOptions(sync["better_sidebar"] === true); toggleBetterTodoSubOptions(sync["better_todo"] === true); + ["gpa_calc", "assignments_due", "better_todo", "auto_dark"].forEach(opt => { + toggleSubOptionsVisibility(opt, sync[opt] === true); + }); }); chrome.storage.sync.get(menu.checkboxes, sync => {