diff --git a/css/popup.css b/css/popup.css
index 95ad7d7..d305027 100644
--- a/css/popup.css
+++ b/css/popup.css
@@ -69,6 +69,10 @@ h2 {margin-top: 20px;font-weight:600}
#todo_progress_rings option {background:#1e1e1e;color:#e2e2e2;}
#todo_progress_rings option:checked,
#todo_progress_rings option:hover {background:#2e2e2e;color:#fff;}
+#todo_timeframe {font-size: 12px;background: var(--inputbg);color:#e2e2e2;border:none;border-radius:7px;padding:6px 8px;font-family:inherit;width:100%;box-sizing:border-box;margin-top:2px;color-scheme:dark;}
+#todo_timeframe option {background:#1e1e1e;color:#e2e2e2;}
+#todo_timeframe option:checked,
+#todo_timeframe option:hover {background:#2e2e2e;color:#fff;}
#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 10ac9e2..5c06f82 100644
--- a/html/popup.html
+++ b/html/popup.html
@@ -259,6 +259,16 @@
+
+
+
+
diff --git a/js/content.js b/js/content.js
index 578e52c..79c71a0 100644
--- a/js/content.js
+++ b/js/content.js
@@ -671,6 +671,10 @@ function applyOptionsChanges(changes) {
)
setupCardAssignments();
loadCardAssignments();
+ // The card overflow fix in applyAestheticChanges() depends on
+ // assignments_due, so re-run it when that option toggles to keep
+ // the overflow rule in sync without a page reload.
+ applyAestheticChanges();
break;
case "custom_assignments":
case "assignment_date_format":
@@ -692,6 +696,7 @@ function applyOptionsChanges(changes) {
case "todo_separate_scrollbar":
case "num_todo_items":
case "hover_preview":
+ case "todo_timeframe":
// case "todo_overdues":
case "todo_hide_feedback":
case "todo_full_height":
@@ -1524,6 +1529,17 @@ function updateIndicator(element) {
}
// better todo html
betterTodoFilter = "tasks";
+// Timeframe filter for the upcoming Tasks tab. "all" = no limit; otherwise
+// items are limited to those due on/before now+range (which also keeps
+// overdue items). Only affects the Tasks (upcoming) tab; announcements and
+// completed are unaffected because their dates are in the past.
+let betterTodoTimeframe = "all";
+const BETTER_TODO_TIMEFRAME_DAYS = {
+ "1week": 7,
+ "2week": 14,
+ "month": 30,
+ "2month": 60,
+};
// null = show every class; a string courseId = only that class's tasks.
let betterTodoProgressFilter = null;
let domContainers = {};
@@ -2656,6 +2672,15 @@ async function createTodoSections(location) {
announcements = displayData.filter(item => item.plannable_type == "announcement");
assignmentsDue = displayData.filter(item => (item.plannable_type == "assignment" || item.plannable_type == "planner_note") && !item.submissions?.submitted && !item.planner_override?.marked_complete);
completed = displayData.filter(item => (item.plannable_type == "assignment" || item.plannable_type == "planner_note") && (item.submissions?.submitted || item.planner_override?.marked_complete));
+ // The timeframe is a persisted Better Todo List sub-option set in the
+ // popup. Read the current value each render so popup changes apply on
+ // the next render. Keeps items due on/before now+range (overdue items
+ // are before now, so they are kept too). Only the Tasks tab is affected.
+ betterTodoTimeframe = (options.todo_timeframe && Object.prototype.hasOwnProperty.call(BETTER_TODO_TIMEFRAME_DAYS, options.todo_timeframe)) ? options.todo_timeframe : "all";
+ if (betterTodoTimeframe !== "all") {
+ const cutoff = Date.now() + (BETTER_TODO_TIMEFRAME_DAYS[betterTodoTimeframe] * 24 * 60 * 60 * 1000);
+ assignmentsDue = assignmentsDue.filter(item => new Date(item.plannable_date).getTime() <= cutoff);
+ }
// console.log("assignments", assignmentsDue);
// console.log("announcements", announcements);
// console.log("completed", completed);
@@ -5188,7 +5213,16 @@ function applyAestheticChanges() {
// Content-sized cards plus the dashboard reflow loop trigger Firefox scroll
// anchoring to yank the viewport back up while scrolling. A fixed height
// (even the default 250px) keeps layout stable.
- if (options.cardHeight !== undefined && options.cardHeight !== null && options.cardHeight !== "") style.textContent += `.ic-DashboardCard {height: ${options.cardHeight}px!important;}`;
+ if (options.cardHeight !== undefined && options.cardHeight !== null && options.cardHeight !== "") {
+ style.textContent += `.ic-DashboardCard {height: ${options.cardHeight}px!important;}`;
+ // Canvas sets overflow:hidden on .ic-DashboardCard. With a fixed
+ // height that clips the appended .canvasrefined-card-assignment area
+ // (the assignment rows live at the bottom of the card), making the
+ // .canvasrefined-assignment-link anchors unclickable for users with
+ // custom card styles enabled. Allow overflow so those rows stay
+ // visible and interactive when card assignments are shown.
+ if (options.assignments_due === true) style.textContent += `.ic-DashboardCard {overflow: visible!important;}`;
+ }
}
style.textContent += ".ic-app-nav-toggle-and-crumbs{display:none!important}";
diff --git a/js/popup.js b/js/popup.js
index cb9de34..62d72c8 100644
--- a/js/popup.js
+++ b/js/popup.js
@@ -4,6 +4,7 @@ const syncedSubOptions = [
"todo_full_height",
"todo_confetti",
"todo_progress_rings",
+ "todo_timeframe",
"device_dark",
"relative_dues",
"card_overdues",
@@ -49,7 +50,7 @@ const exportCardColorToggles = ["gradient_cards", "disable_color_overlay"];
const exportCardStyles = ["customCardStyles", "imageSize", "cardRoundness", "cardSpacing", "cardWidth", "cardHeight"];
const exportLayout = ["full_width", "center_cards", "condensed_cards", "equal_height_cards", "remlogo", "hide_new_canvas", "hide_feedback", "tab_icons"];
const exportSidebar = ["better_sidebar", "sidebar_scale"];
-const exportTodo = ["better_todo", "todo_hide_feedback", "todo_full_height", "todo_confetti", "todo_progress_rings", "todo_hr24", "todo_separate_scrollbar", "todo_alternate_colors", "hover_preview"];
+const exportTodo = ["better_todo", "todo_hide_feedback", "todo_full_height", "todo_confetti", "todo_progress_rings", "todo_timeframe", "todo_hr24", "todo_separate_scrollbar", "todo_alternate_colors", "hover_preview"];
const exportGpa = ["gpa_calc", "gpa_calc_prepend", "gpa_calc_cumulative", "gpa_calc_weighted"];
const exportBackground = ["customBackgroundLink", "customBackgroundScale", "customBackgroundDaily", "customBackgroundNasaDaily", "fitImageToScreen", "bg_opacity", "sidebar_opacity", "bg_blur", "sidebar_blur"];
// Master "On/off toggles" = every visual toggle (no GPA, no dark-mode schedule,
@@ -147,6 +148,7 @@ const defaultOptions = {
"todo_hide_feedback": false,
"todo_full_height": false,
"todo_progress_rings": "rings",
+ "todo_timeframe": "all",
"todo_confetti": true,
"device_dark": false,
"cumulative_gpa": { "name": "Cumulative GPA", "hidden": false, "weight": "dnc", "credits": 999, "gr": 3.21 },
@@ -308,6 +310,19 @@ function setupProgressRingsSelect(initial) {
});
}
+// Timeframe dropdown for the upcoming Tasks tab. Persisted so the Better Todo
+// List remembers the selected range across sessions.
+function setupTimeframeSelect(initial) {
+ const el = document.querySelector("#todo_timeframe");
+ if (!el) return;
+ const allowed = ["all", "1week", "2week", "month", "2month"];
+ let value = allowed.includes(initial) ? initial : "all";
+ el.value = value;
+ el.addEventListener("change", function () {
+ chrome.storage.sync.set({ "todo_timeframe": this.value });
+ });
+}
+
function setupAutoDarkInput(initial, time) {
let el = document.querySelector('#' + time);
el.value = initial.hour + ":" + initial.minute;
@@ -963,6 +978,10 @@ function setup() {
identifier: "todo_progress_rings",
setup: (initial) => setupProgressRingsSelect(initial),
},
+ {
+ identifier: "todo_timeframe",
+ setup: (initial) => setupTimeframeSelect(initial),
+ },
],
};
@@ -1658,6 +1677,7 @@ function saveCurrentTheme() {
"todo_full_height": current["todo_full_height"],
"todo_confetti": current["todo_confetti"],
"todo_progress_rings": current["todo_progress_rings"],
+ "todo_timeframe": current["todo_timeframe"],
"todo_hr24": current["todo_hr24"],
"todo_separate_scrollbar": current["todo_separate_scrollbar"],
"better_sidebar": current["better_sidebar"],