Compare commits

...

2 Commits

Author SHA1 Message Date
Guy Sandler
765ecbf2fa todolist preview 2026-08-23 21:45:29 -07:00
Guy Sandler
f26cac0e9c alternate colors 2026-08-23 19:23:01 -07:00
15 changed files with 194 additions and 26 deletions

View File

@ -54,7 +54,7 @@
"message": "Max. Anzahl Elemente: "
},
"hover_preview": {
"message": "Bewegen Sie den Mauszeiger, um Details in der Vorschau anzuzeigen"
"message": "Vorschau beim Überfahren"
},
"hide_completed": {
"message": "Abgeschlossene ausblenden"

View File

@ -84,7 +84,7 @@
"message": "Max Items: "
},
"hover_preview": {
"message": "Hover To Preview Details"
"message": "Previews on hover"
},
"hide_completed": {
"message": "Hide Completed"
@ -146,6 +146,9 @@
"todo_full_height": {
"message": "Force Full Height"
},
"todo_alternate_colors": {
"message": "Alternate colors"
},
"relative_due_dates": {
"message": "Relative Due Dates"
},

View File

@ -54,7 +54,7 @@
"message": "Artículos máximos: "
},
"hover_preview": {
"message": "Pasa el cursor para obtener una vista previa de los detalles"
"message": "Vista previa al pasar el cursor"
},
"hide_completed": {
"message": "Ocultar completado"

View File

@ -54,7 +54,7 @@
"message": "Nombre maximal d'articles : "
},
"hover_preview": {
"message": "Survolez pour prévisualiser les détails"
"message": "Aperçu au survol"
},
"hide_completed": {
"message": "Masquer terminé"

View File

@ -54,7 +54,7 @@
"message": "Numero massimo di articoli: "
},
"hover_preview": {
"message": "Passa il mouse per visualizzare l'anteprima dei dettagli"
"message": "Anteprima al passaggio del mouse"
},
"hide_completed": {
"message": "Nascondi Completato"

View File

@ -54,7 +54,7 @@
"message": "最大アイテム数: "
},
"hover_preview": {
"message": "詳細をプレビューするにはマウスを移動します"
"message": "ホバーでプレビュー"
},
"hide_completed": {
"message": "完了を非表示"

View File

@ -54,7 +54,7 @@
"message": "Itens máximos: "
},
"hover_preview": {
"message": "Passe o mouse para visualizar os detalhes"
"message": "Pré-visualização ao passar o cursor"
},
"hide_completed": {
"message": "Ocultar Concluído"

View File

@ -54,7 +54,7 @@
"message": "Максимальное количество предметов: "
},
"hover_preview": {
"message": "Наведите курсор, чтобы просмотреть детали"
"message": "Предпросмотр при наведении"
},
"hide_completed": {
"message": "Скрыть Завершено"

View File

@ -54,7 +54,7 @@
"message": "Max artiklar: "
},
"hover_preview": {
"message": "Håll muspekaren för att förhandsgranska detaljer"
"message": "Förhandsgranskning vid hover"
},
"hide_completed": {
"message": "Göm slutförd"

View File

@ -54,7 +54,7 @@
"message": "最大物品数: "
},
"hover_preview": {
"message": "将鼠标悬停预览详细信息"
"message": "悬停预览"
},
"hide_completed": {
"message": "隐藏已完成"

View File

@ -54,7 +54,7 @@
"message": "最大物品数: "
},
"hover_preview": {
"message": "将鼠标悬停以预览详细信息"
"message": "懸停預覽"
},
"hide_completed": {
"message": "隐藏已完成"

View File

@ -125,10 +125,10 @@
#canvasrefined-announcement-list {margin-bottom:1.0625rem;}
.canvasrefined-todo-item-loader {margin-top: 18px;}
.canvasrefined-todo-item-loader .canvasrefined-skeleton-text {height:12px;margin-top: 8px;margin-bottom:0;margin-left:25px}
.canvasrefined-hover-preview {position: absolute;top: -6px;left: -400px;display: none; background: #fff; color: #000; max-height: 300%; width: 350px; padding:12px;border-radius:5px; overflow: hidden;box-shadow: 0 2px 5px rgba(0,0,0,.3)}
.canvasrefined-preview-text {text-overflow: ellipsis;}
.canvasrefined-preview-title {font-weight:bold;font-size:14px;}
.canvasrefined-hover-preview::after {content:'';position:absolute;width:100%;height: 18px;bottom:0;left:0;background:linear-gradient(0deg, #fff 50%, transparent)}
.canvasrefined-hover-preview {position: absolute;top: -6px;left: -400px;display: none; background: var(--bcbackground-0, #fff); color: var(--bctext-0, #000); max-height: 300%; width: 350px; padding:12px;border-radius:5px; overflow: hidden;box-shadow: 0 2px 5px rgba(0,0,0,.3)}
.canvasrefined-preview-text {text-overflow: ellipsis;color: var(--bctext-0, #000);}
.canvasrefined-preview-title {font-weight:bold;font-size:14px;color: var(--bctext-0, #000);}
.canvasrefined-hover-preview::after {content:'';position:absolute;width:100%;height: 18px;bottom:0;left:0;background:linear-gradient(0deg, var(--bcbackground-0, #fff) 50%, transparent)}
.canvasrefined-link-image {height: 21px; width: 21px;padding: 0px}
.canvasrefined-link-image:hover {filter: brightness(66%)}
.canvasrefined-gpa-header {font-size:16px;font-weight: bold;padding: 0;margin: 0;}

View File

@ -215,11 +215,6 @@
<span class="option-name" data-i18n="better_todo">Better Todo List</span>
</div>
<div class="sub-options">
<div class="sub-option" style="display:none;">
<input type="checkbox" id="hover_preview" name="hover_preview">
<label for="hover_preview" class="sub-text" data-i18n="hover_preview">Hover to preview
details</label> <!-- TODO: Later -->
</div>
<div class="sub-option">
<input type="checkbox" id="todo_separate_scrollbar" name="todo_separate_scrollbar">
<label for="todo_separate_scrollbar" class="sub-text" data-i18n="todo_separate_scrollbar">Separate Scrollbar</label>
@ -232,6 +227,10 @@
<input type="checkbox" id="todo_full_height" name="todo_full_height">
<label for="todo_full_height" class="sub-text" data-i18n="todo_full_height">Force Full Height</label> <!-- TO REMOVE and replace with full height -->
</div>
<div class="sub-option">
<input type="checkbox" id="hover_preview" name="hover_preview">
<label for="hover_preview" class="sub-text" data-i18n="hover_preview">Previews on hover</label>
</div>
<div class="sub-option">
<input type="checkbox" id="todo_hide_feedback" name="todo_hide_feedback">
<label for="todo_hide_feedback" class="sub-text" data-i18n="todo_hide_feedback">Hide Recent Feedback</label>
@ -250,6 +249,10 @@
<input type="checkbox" id="todo_confetti" name="todo_confetti">
<label for="todo_confetti" class="sub-text">Show confetti on complete</label>
</div>
<div class="sub-option" id="todo_alternate_colors_wrap" style="display:none;">
<input type="checkbox" id="todo_alternate_colors" name="todo_alternate_colors">
<label for="todo_alternate_colors" class="sub-text" data-i18n="todo_alternate_colors">Alternate colors</label>
</div>
<div style="margin-top: 5px">
<span class="sub-text" data-i18n="max_items">Max items to show: </span><span
id="numTodoItems"></span>

View File

@ -565,6 +565,7 @@ function startExtension() {
chrome.storage.sync.get(null, result => {
options = { ...options, ...result };
applyTodoAlternateColors();
toggleAutoDarkMode();
// toggleScheduledReminders();
getApiData();
@ -608,6 +609,10 @@ function applyOptionsChanges(changes) {
case "dark_preset":
case "device_dark":
toggleDarkMode();
applyTodoAlternateColors();
break;
case "todo_alternate_colors":
applyTodoAlternateColors();
break;
case "auto_dark":
case "auto_dark_start":
@ -2723,6 +2728,146 @@ function clearTodoList() {
});
}
// "Alternate colors" (Better Todo List, light mode only): recolors the main
// todo-list icon fill to white instead of the default --bctext-0, so icons
// stay visible on lighter course-color strips. Implemented through a CSS
// variable so toggling the option or dark mode recolors existing icons live
// without a re-render.
const TODO_ALT_ICON_COLOR = "#ffffff";
let todoAltStyleEl = null;
function applyTodoAlternateColors() {
const altOn = options.todo_alternate_colors === true && options.dark_mode !== true;
const color = altOn ? TODO_ALT_ICON_COLOR : "var(--bctext-0)";
if (!todoAltStyleEl) {
todoAltStyleEl = document.createElement("style");
todoAltStyleEl.id = "crtodoaltcss";
document.documentElement.append(todoAltStyleEl);
}
todoAltStyleEl.textContent = `:root{--cr-todo-icon:${color};}`;
}
// --- Hover preview (Better Todo List: "Previews on hover") ---
// The todo list is rendered by createTodoSections -> populateAssignments /
// populateAnnouncements (the old loadBetterTodo renderer is no longer called).
// A single shared, body-level tooltip is reused across items so it is never
// clipped by the sidebar's scroll/overflow containers. It reuses the
// .canvasrefined-hover-preview class so existing light/dark styling applies.
let todoPreviewDelay = null;
let todoPreviewToken = 0;
const todoPreviewCache = new Map();
function stripHtmlPreview(html) {
if (!html) return "";
return String(html).replace(/<\/?[^>]+(>|$)/g, " ").replace(/&nbsp;/g, " ").replace(/\s+/g, " ").trim();
}
function getTodoPreviewEl() {
let el = document.getElementById("canvasrefined-todo-preview");
if (el) return el;
el = document.createElement("div");
el.id = "canvasrefined-todo-preview";
el.className = "canvasrefined-hover-preview";
el.innerHTML = '<p class="canvasrefined-preview-title"></p><p class="canvasrefined-preview-text"></p>';
el.style.position = "fixed";
el.style.zIndex = "100001";
el.style.width = "300px";
el.style.maxWidth = "90vw";
el.style.maxHeight = "260px";
document.body.append(el);
return el;
}
function positionTodoPreview(el, anchor) {
const r = anchor.getBoundingClientRect();
const gap = 10;
const pw = el.offsetWidth || 300;
const ph = el.offsetHeight || 160;
let left = r.left - pw - gap;
let top = r.top;
if (left < gap) {
left = r.right + gap;
if (left + pw > window.innerWidth - gap) left = Math.max(gap, window.innerWidth - pw - gap);
}
if (top + ph > window.innerHeight - gap) top = Math.max(gap, window.innerHeight - ph - gap);
el.style.left = left + "px";
el.style.top = top + "px";
}
async function getTodoPreviewText(item) {
const type = item.plannable_type;
const id = item.plannable_id;
const key = type + ":" + id;
if (todoPreviewCache.has(key)) return todoPreviewCache.get(key);
// Custom task (planner note): the description is already on the planner
// item as item.plannable.details, so no API call is needed.
if (type === "planner_note" || (item.planner_override && item.planner_override.custom === true)) {
const raw = item.plannable && item.plannable.details ? item.plannable.details : "";
const text = stripHtmlPreview(raw) || "No details given";
todoPreviewCache.set(key, text);
return text;
}
let url = null;
let field = "description";
if (type === "assignment") {
url = `${domain}/api/v1/courses/${item.course_id}/assignments/${id}`;
} else if (type === "quiz") {
url = `${domain}/api/v1/courses/${item.course_id}/quizzes/${id}`;
} else if (type === "discussion_topic" || type === "announcement") {
url = `${domain}/api/v1/courses/${item.course_id}/discussion_topics/${id}`;
field = "message";
}
if (!url) {
const text = "No preview available";
todoPreviewCache.set(key, text);
return text;
}
try {
const data = await getData(url);
const raw = data && data[field] ? data[field] : "";
const text = stripHtmlPreview(raw) || "No details given";
todoPreviewCache.set(key, text);
return text;
} catch (e) {
return "Couldn't load preview";
}
}
function hideTodoPreview() {
todoPreviewToken++; // cancel any pending async text update
const el = document.getElementById("canvasrefined-todo-preview");
if (el) el.style.display = "none";
}
async function showTodoPreview(anchor, item) {
const token = ++todoPreviewToken;
const el = getTodoPreviewEl();
const title = el.querySelector(".canvasrefined-preview-title");
const text = el.querySelector(".canvasrefined-preview-text");
title.textContent = item.plannable && item.plannable.title ? item.plannable.title : "";
text.textContent = "Loading…";
el.style.display = "block";
positionTodoPreview(el, anchor);
const content = await getTodoPreviewText(item);
if (token !== todoPreviewToken) return; // a newer hover (or hide) superseded this one
if (el.style.display !== "block") return; // user already moved away
text.textContent = content;
positionTodoPreview(el, anchor); // reposition now that the height is known
}
function attachTodoHoverPreview(anchor, item) {
if (options.hover_preview !== true) return;
anchor.addEventListener("mouseenter", () => {
clearTimeout(todoPreviewDelay);
todoPreviewDelay = setTimeout(() => {
if (anchor.matches(":hover")) showTodoPreview(anchor, item);
}, 250);
});
anchor.addEventListener("mouseleave", () => {
clearTimeout(todoPreviewDelay);
hideTodoPreview();
});
}
function populateAssignments(iscompleted = false) {
const today = new Date();
today.setHours(0,0,0,0);
@ -2801,9 +2946,9 @@ function populateAssignments(iscompleted = false) {
const iconLeftOffset = isCustomTask ? 2 : 5;
const taskIcon = isCustomTask
? `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:100%;display:block;">
<path d="M19.8201 14H15.6001C15.04 14 14.76 14 14.5461 14.109C14.3579 14.2049 14.2049 14.3578 14.1091 14.546C14.0001 14.7599 14.0001 15.0399 14.0001 15.6V19.82M20 12.7269V7.2C20 6.0799 20 5.51984 19.782 5.09202C19.5903 4.71569 19.2843 4.40973 18.908 4.21799C18.4802 4 17.9201 4 16.8 4H7.2C6.0799 4 5.51984 4 5.09202 4.21799C4.71569 4.40973 4.40973 4.71569 4.21799 5.09202C4 5.51984 4 6.0799 4 7.2V16.8C4 17.9201 4 18.4802 4.21799 18.908C4.40973 19.2843 4.71569 19.5903 5.09202 19.782C5.51984 20 6.0799 20 7.2 20H12.9496C13.4578 20 13.7118 20 13.9498 19.9407C14.1608 19.8882 14.3618 19.8016 14.5449 19.6844C14.7515 19.5522 14.926 19.3675 15.2751 18.9983L19.1254 14.9252C19.4486 14.5833 19.6101 14.4124 19.7255 14.2156C19.8278 14.041 19.903 13.8519 19.9486 13.6548C20 13.4325 20 13.1973 20 12.7269Z" stroke="var(--bctext-0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M19.8201 14H15.6001C15.04 14 14.76 14 14.5461 14.109C14.3579 14.2049 14.2049 14.3578 14.1091 14.546C14.0001 14.7599 14.0001 15.0399 14.0001 15.6V19.82M20 12.7269V7.2C20 6.0799 20 5.51984 19.782 5.09202C19.5903 4.71569 19.2843 4.40973 18.908 4.21799C18.4802 4 17.9201 4 16.8 4H7.2C6.0799 4 5.51984 4 5.09202 4.21799C4.71569 4.40973 4.40973 4.71569 4.21799 5.09202C4 5.51984 4 6.0799 4 7.2V16.8C4 17.9201 4 18.4802 4.21799 18.908C4.40973 19.2843 4.71569 19.5903 5.09202 19.782C5.51984 20 6.0799 20 7.2 20H12.9496C13.4578 20 13.7118 20 13.9498 19.9407C14.1608 19.8882 14.3618 19.8016 14.5449 19.6844C14.7515 19.5522 14.926 19.3675 15.2751 18.9983L19.1254 14.9252C19.4486 14.5833 19.6101 14.4124 19.7255 14.2156C19.8278 14.041 19.903 13.8519 19.9486 13.6548C20 13.4325 20 13.1973 20 12.7269Z" stroke="var(--cr-todo-icon)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>`
: `<svg fill="var(--bctext-0)" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:100%;display:block;">
: `<svg fill="var(--cr-todo-icon)" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:100%;display:block;">
<g id="SVGRepo_bgCarrier" stroke-width="1"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path d="M1468.214 0v551.145L840.27 1179.089c-31.623 31.623-49.693 74.54-49.693 119.715v395.289h395.288c45.176 0 88.093-18.07 119.716-49.694l162.633-162.633v438.206H0V0h1468.214Zm129.428 581.3c22.137-22.136 57.825-22.136 79.962 0l225.879 225.879c22.023 22.023 22.023 57.712 0 79.848l-677.638 677.637c-10.616 10.503-24.96 16.49-39.98 16.49H903.516v-282.35c0-15.02 5.986-29.364 16.49-39.867Zm-920.005 548.095H338.82v112.94h338.818v-112.94Zm225.88-225.879H338.818v112.94h564.697v-112.94Zm734.106-202.5-89.561 89.56 146.03 146.031 89.562-89.56-146.031-146.031Zm-508.228-362.197H338.82v338.818h790.576V338.82Z" fill-rule="evenodd"></path>
@ -2847,6 +2992,7 @@ function populateAssignments(iscompleted = false) {
openTaskForEdit(item);
});
}
attachTodoHoverPreview(assignment, item);
});
if (document.getElementById("better-todo-see-more")) {
@ -2909,7 +3055,7 @@ function populateAnnouncements() {
<div style="display:flex;align-items:center;gap:5px;width:100%;height:60px;background:var(--bcbackground-2);border-radius:5px;${filter}">
<div style="width:40px;display:flex;align-items:center;justify-content:center;background-color:${courseColor};height:100%;border-radius:5px 0 0 5px;">
<div style="width:23px;height:23px;display:flex;margin-left:0px;">
<svg fill="var(--bctext-0)" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg" style="transition:all .3s ease;">
<svg fill="var(--cr-todo-icon)" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg" style="transition:all .3s ease;">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path d="M1587.162 31.278c11.52-23.491 37.27-35.689 63.473-29.816 25.525 6.099 43.483 28.8 43.483 55.002V570.46C1822.87 596.662 1920 710.733 1920 847.053c0 136.32-97.13 250.503-225.882 276.705v513.883c0 26.202-17.958 49.016-43.483 55.002a57.279 57.279 0 0 1-12.988 1.468c-21.12 0-40.772-11.745-50.485-31.171C1379.238 1247.203 964.18 1242.347 960 1242.347H564.706v564.706h87.755c-11.859-90.127-17.506-247.003 63.473-350.683 52.405-67.087 129.657-101.082 229.948-101.082v112.941c-64.49 0-110.57 18.861-140.837 57.487-68.781 87.868-45.064 263.83-30.269 324.254 4.18 16.828.34 34.673-10.277 48.34-10.73 13.665-27.219 21.684-44.499 21.684H508.235c-31.171 0-56.47-25.186-56.47-56.47v-621.177h-56.47c-155.747 0-282.354-126.607-282.354-282.353v-56.47h-56.47C25.299 903.523 0 878.336 0 847.052c0-31.172 25.299-56.471 56.47-56.471h56.471v-56.47c0-155.634 126.607-282.354 282.353-282.354h564.593c16.941-.112 420.48-7.002 627.275-420.48Zm-5.986 218.429c-194.71 242.371-452.216 298.164-564.705 311.04v572.724c112.489 12.876 369.995 68.556 564.705 311.04ZM903.53 564.7H395.294c-93.402 0-169.412 76.01-169.412 169.411v225.883c0 93.402 76.01 169.412 169.412 169.412H903.53V564.7Zm790.589 123.444v317.93c65.618-23.379 112.94-85.497 112.94-159.021 0-73.525-47.322-135.53-112.94-158.909Z" fill-rule="evenodd"></path>
@ -2926,6 +3072,7 @@ function populateAnnouncements() {
</div>
</div>
`;
attachTodoHoverPreview(announcement, item);
});
}
@ -3611,9 +3758,10 @@ async function loadBetterTodo() {
delay = setTimeout(async () => {
if (listItem.classList.contains("canvasrefined-todo-hover")) {
previewTitle.textContent = item.plannable.title;
// custom assignment
// custom assignment (planner note): preview its description/details
if (customItem) {
previewText.textContent = "Custom assignment";
const details = item.plannable && item.plannable.details ? item.plannable.details : "";
previewText.textContent = details === "" ? "No details given" : details.replace(/<\/?[^>]+(>|$)/g, " ");
} else {
console.log(item);
let found = false;

View File

@ -19,6 +19,7 @@ const syncedSubOptions = [
"assignment_date_format",
"todo_hr24",
"todo_separate_scrollbar",
"todo_alternate_colors",
"grade_hover",
// "hide_completed",
"num_todo_items",
@ -48,7 +49,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"];
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 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,
@ -103,6 +104,7 @@ const defaultOptions = {
"sidebar_blur": 0,
"todo_hr24": false,
"todo_separate_scrollbar": false,
"todo_alternate_colors": false,
"condensed_cards": false,
"center_cards": false,
"custom_cards": {},
@ -506,6 +508,13 @@ function toggleBetterTodoSubOptions(betterTodoOn) {
}
}
// "Alternate colors" (Better Todo List sub-option) only makes sense in light
// mode, so hide its checkbox whenever dark mode is on.
function toggleAlternateColorsVisibility(darkModeOn) {
const wrap = document.getElementById("todo_alternate_colors_wrap");
if (wrap) wrap.style.display = darkModeOn ? "none" : "";
}
// Hide a toggle's sub-options when it's off; auto_dark only hides its time clocks.
function toggleSubOptionsVisibility(option, isOn) {
const togglesWithSubOptions = ["gpa_calc", "assignments_due", "better_todo", "auto_dark"];
@ -833,6 +842,7 @@ function setup() {
"assignment_date_format",
"todo_hr24",
"todo_separate_scrollbar",
"todo_alternate_colors",
"grade_hover",
// "hide_completed",
"hover_preview",
@ -977,6 +987,9 @@ function setup() {
if (option === "better_todo") {
toggleBetterTodoSubOptions(status);
}
if (option === "dark_mode") {
toggleAlternateColorsVisibility(status);
}
toggleSubOptionsVisibility(option, status);
});
});
@ -985,6 +998,7 @@ function setup() {
["gpa_calc", "assignments_due", "better_todo", "auto_dark"].forEach(opt => {
toggleSubOptionsVisibility(opt, sync[opt] === true);
});
toggleAlternateColorsVisibility(sync["dark_mode"] === true);
});
chrome.storage.sync.get(menu.checkboxes, sync => {