diff --git a/html/popup.html b/html/popup.html index 5840264..942208c 100644 --- a/html/popup.html +++ b/html/popup.html @@ -254,7 +254,16 @@ Better Sidebar
-
+ +
Sidebar scale: %
@@ -303,14 +312,6 @@
Full Width Fix
-
@@ -941,16 +942,30 @@

Custom Background

Pick a preset or use your own image url.

-
-
-
- Image scale - 100% +
+
+
+
+ Image scale + 100% +
+
- + + +
+
+ + +
+
+ + +
+
+ +
- -
diff --git a/js/background.js b/js/background.js index e9a9c23..85aec37 100644 --- a/js/background.js +++ b/js/background.js @@ -104,6 +104,10 @@ chrome.runtime.onInstalled.addListener(function () { "customCardStyles": false, "customBackgroundLink": "", "customBackgroundScale": 100, + "customBackgroundDaily": false, + "customBackgroundNasaDaily": false, + "nasaInfoOverlay": false, + "fitImageToScreen": false, } }; @@ -122,6 +126,11 @@ chrome.runtime.onInstalled.addListener(function () { newLocalOptions[option] = default_options["local"][option]; }) + // migrate old setting name + if (sync["nasaFitToScreen"] !== undefined && sync["fitImageToScreen"] === undefined) { + newSyncOptions["fitImageToScreen"] = sync["nasaFitToScreen"]; + } + if (Object.keys(newLocalOptions).length > 0) { chrome.storage.local.set(newLocalOptions); } @@ -139,4 +148,90 @@ chrome.runtime.onInstalled.addListener(function () { }); }); +// The NASA APOD API with the demo key is limited to 30 requests/hour and 50/day. +// All calls are serialized through this worker and gated against those limits. +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message?.type === "getNasaBackground") { + getNasaBackground().then(sendResponse); + return true; + } +}); + +let nasaRequestQueue = Promise.resolve(); +function queuedNasaTask(task) { + const run = nasaRequestQueue.then(task, task); + nasaRequestQueue = run.catch(() => {}); + return run; +} + +async function getNasaBackground() { + return queuedNasaTask(async () => { + const date = new Date(); + for (let i = 0; i < 7; i++) { + const dateStr = date.toISOString().slice(0, 10); + const cacheKey = `nasa_apod_${dateStr}`; + const metadataKey = `nasa_apod_meta_${dateStr}`; + const cached = await chrome.storage.local.get([cacheKey, metadataKey]); + if (cached[cacheKey]) return cached[cacheKey]; + + // Don't re-probe dates the API already told us don't exist + const missingKey = `nasa_apod_missing_${dateStr}`; + const missing = await chrome.storage.local.get(missingKey); + if (missing[missingKey]) { + date.setDate(date.getDate() - 1); + continue; + } + + const data = await callNasaApi(dateStr); + if (data === "ratelimited" || data === null) return null; + if (data === "missing") { + await chrome.storage.local.set({ [missingKey]: true }); + date.setDate(date.getDate() - 1); + continue; + } + + const url = data.thumbnail_url || data.hdurl || data.url; + if (!url) return null; + const result = { url, scale: 100, date: dateStr }; + await chrome.storage.local.set({ [cacheKey]: result }); + await chrome.storage.local.set({ [metadataKey]: { title: data.title || "", date: data.date || dateStr, copyright: data.copyright || "", explanation: data.explanation || "" } }); + return result; + } + return null; + }); +} + +async function callNasaApi(dateStr) { + const now = Date.now(); + const { nasa_api_calls = [] } = await chrome.storage.local.get("nasa_api_calls"); + const lastHour = nasa_api_calls.filter(t => now - t < 3600 * 1000); + const lastDay = nasa_api_calls.filter(t => now - t < 24 * 3600 * 1000); + if (lastHour.length >= 30 || lastDay.length >= 50) { + console.warn("[CanvasRefined] NASA API rate limit reached, skipping request"); + return "ratelimited"; + } + + let response; + try { + response = await fetch(`https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&thumbs=true&date=${dateStr}`); + } catch (error) { + console.error("[CanvasRefined] Failed to fetch NASA APOD:", error); + return null; + } + + // The request was made, so it counts against the quota + await chrome.storage.local.set({ nasa_api_calls: [...lastDay, now] }); + + if (response.status === 429) return "ratelimited"; + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + if (errorData.code === 404 && (errorData.msg || "").toLowerCase().includes("no data available")) { + return "missing"; + } + return null; + } + + return await response.json().catch(() => null); +} + // chrome.runtime.setUninstallURL("https://diditupe.dev/canvasrefined/goodbye"); diff --git a/js/content.js b/js/content.js index bd64c5e..6af0c8a 100644 --- a/js/content.js +++ b/js/content.js @@ -30,6 +30,10 @@ function isConversationsPage() { return /^\/conversations(?:\/|$)/.test(current_page); } +function isAccountsPage() { + return /^\/accounts(?:\/|$)/.test(current_page); +} + function isProfilePage() { return /^\/profile(?:\/|$)/.test(current_page); } @@ -58,72 +62,6 @@ function addSubmissionPageButton() { }, true); } -let sequenceFooterObserver = null; - -function isAssignmentPage() { - return /^\/courses\/\d+\/assignments(?:\/\d+)?(?:\/|$)/.test(current_page); -} - -function removeSequenceFooter() { - if (!isAssignmentPage()) return false; - const sequenceFooter = document.getElementById("sequence_footer"); - if (!sequenceFooter) return false; - sequenceFooter.remove(); - return true; -} - -function watchSequenceFooter() { - if (!isAssignmentPage()) return; - if (removeSequenceFooter()) return; - if (sequenceFooterObserver) return; - - sequenceFooterObserver = new MutationObserver(() => { - if (removeSequenceFooter() && sequenceFooterObserver) { - sequenceFooterObserver.disconnect(); - sequenceFooterObserver = null; - } - }); - - sequenceFooterObserver.observe(document.documentElement, { childList: true, subtree: true }); - setTimeout(() => { - if (sequenceFooterObserver) { - sequenceFooterObserver.disconnect(); - sequenceFooterObserver = null; - } - }, 10000); -} - -function ensureSubmissionPageButton() { - const assignmentLink = getSubmissionAssignmentLink(); - if (!assignmentLink) return false; - const content = document.getElementById("content"); - if (!content) return false; - if (content.querySelector("#canvasrefined-assignment-return")) return true; - addSubmissionPageButton(); - return Boolean(content.querySelector("#canvasrefined-assignment-return")); -} - -function watchSubmissionPageButton() { - if (!getSubmissionAssignmentLink()) return; - if (ensureSubmissionPageButton()) return; - if (submissionPageButtonObserver) return; - - submissionPageButtonObserver = new MutationObserver(() => { - if (ensureSubmissionPageButton() && submissionPageButtonObserver) { - submissionPageButtonObserver.disconnect(); - submissionPageButtonObserver = null; - } - }); - - submissionPageButtonObserver.observe(document.documentElement, { childList: true, subtree: true }); - setTimeout(() => { - if (submissionPageButtonObserver) { - submissionPageButtonObserver.disconnect(); - submissionPageButtonObserver = null; - } - }, 10000); -} - function addProfileLogoutPageButton() { if (!isProfilePage()) return; const content = document.getElementById("content"); @@ -168,6 +106,194 @@ function watchProfileLogoutPageButton() { }, 10000); } +function ensureSubmissionPageButton() { + const assignmentLink = getSubmissionAssignmentLink(); + if (!assignmentLink) return false; + const content = document.getElementById("content"); + if (!content) return false; + if (content.querySelector("#canvasrefined-assignment-return")) return true; + addSubmissionPageButton(); + return Boolean(content.querySelector("#canvasrefined-assignment-return")); +} + +function watchSequenceFooter() { + if (!isAssignmentPage()) return; + if (removeSequenceFooter()) return; + if (sequenceFooterObserver) return; + + sequenceFooterObserver = new MutationObserver(() => { + if (removeSequenceFooter() && sequenceFooterObserver) { + sequenceFooterObserver.disconnect(); + sequenceFooterObserver = null; + } + }); + + sequenceFooterObserver.observe(document.documentElement, { childList: true, subtree: true }); + setTimeout(() => { + if (sequenceFooterObserver) { + sequenceFooterObserver.disconnect(); + sequenceFooterObserver = null; + } + }, 10000); +} + +function watchSubmissionPageButton() { + if (!getSubmissionAssignmentLink()) return; + if (ensureSubmissionPageButton()) return; + if (submissionPageButtonObserver) return; + + submissionPageButtonObserver = new MutationObserver(() => { + if (ensureSubmissionPageButton() && submissionPageButtonObserver) { + submissionPageButtonObserver.disconnect(); + submissionPageButtonObserver = null; + } + }); + + submissionPageButtonObserver.observe(document.documentElement, { childList: true, subtree: true }); + setTimeout(() => { + if (submissionPageButtonObserver) { + submissionPageButtonObserver.disconnect(); + submissionPageButtonObserver = null; + } + }, 10000); +} + +async function getActiveCustomBackground() { + const syncOpts = await chrome.storage.sync.get([ + "customBackgroundDaily", + "customBackgroundNasaDaily", + "customBackgroundLink", + "customBackgroundScale", + ]); + + console.log("[CanvasRefined] getActiveCustomBackground:", syncOpts); + + if (syncOpts.customBackgroundNasaDaily === true) { + console.log("[CanvasRefined] Using NASA APOD"); + return await getNasaDailyBackground(); + } + + if (syncOpts.customBackgroundDaily === true) { + console.log("[CanvasRefined] Using Wikimedia Featured"); + const dailyPreset = await getDailyBackgroundPreset(); + if (dailyPreset) { + console.log("[CanvasRefined] Wikimedia URL:", dailyPreset.url); + return { + url: dailyPreset.url, + scale: dailyPreset.scale, + }; + } + console.log("[CanvasRefined] Wikimedia returned null"); + } + + if (syncOpts.customBackgroundLink && syncOpts.customBackgroundLink !== "") { + console.log("[CanvasRefined] Using custom link"); + return { + url: syncOpts.customBackgroundLink, + scale: syncOpts.customBackgroundScale || 100, + }; + } + + console.log("[CanvasRefined] No custom background"); + return null; +} + +async function getDailyBackgroundPreset() { + const today = new Date(); + const dateStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`; + const cacheKey = `picsum_daily_${dateStr}`; + const cached = await chrome.storage.local.get(cacheKey); + if (cached[cacheKey]) return cached[cacheKey]; + + const url = `https://picsum.photos/seed/${dateStr}/1920/1080`; + const result = { url, scale: 100 }; + await chrome.storage.local.set({ [cacheKey]: result }); + return result; +} + +async function getNasaDailyBackground() { + try { + return await chrome.runtime.sendMessage({ type: "getNasaBackground" }); + } catch (error) { + console.error("[CanvasRefined] Failed to fetch NASA APOD:", error); + return null; + } +} + +let nasaInfoOverlayEl = null; + +function isDashboardPage() { + return !!document.querySelector("#DashboardCard_Container"); +} + +function createNasaInfoOverlay() { + if (options.customBackgroundNasaDaily !== true) return; + if (nasaInfoOverlayEl || !isDashboardPage()) return; + + const contentMain = document.querySelector("#content.ic-Layout-contentMain, .ic-Layout-contentMain"); + if (!contentMain) return; + if (getComputedStyle(contentMain).position === "static") { + contentMain.style.position = "relative"; + } + + nasaInfoOverlayEl = document.createElement("div"); + nasaInfoOverlayEl.id = "canvasrefined-nasa-info-overlay"; + nasaInfoOverlayEl.style.cssText = "position:absolute;right:24px;bottom:24px;z-index:9999;"; + nasaInfoOverlayEl.innerHTML = ` +
+ + + + + +
+ + `; + + const icon = nasaInfoOverlayEl.querySelector("#nasa-info-icon"); + const panel = nasaInfoOverlayEl.querySelector("#nasa-info-panel"); + + const showPanel = async () => { + const dateStr = new Date().toISOString().slice(0, 10); + const cacheKey = `nasa_apod_${dateStr}`; + const cached = await chrome.storage.local.get(cacheKey); + const metaDate = cached[cacheKey]?.date || dateStr; + const metadataKey = `nasa_apod_meta_${metaDate}`; + const metadata = await chrome.storage.local.get(metadataKey); + const meta = metadata[metadataKey]; + if (meta) { + document.getElementById("nasa-info-title").textContent = meta.title || ""; + document.getElementById("nasa-info-date").textContent = `Date: ${meta.date}`; + document.getElementById("nasa-info-credit").textContent = meta.copyright ? `Credit: ${meta.copyright}` : ""; + document.getElementById("nasa-info-explanation").textContent = meta.explanation || "No description available."; + panel.style.display = "block"; + } + }; + + const hidePanel = () => { + panel.style.display = "none"; + }; + + icon.addEventListener("mouseenter", showPanel); + icon.addEventListener("mouseleave", hidePanel); + panel.addEventListener("mouseenter", showPanel); + panel.addEventListener("mouseleave", hidePanel); + + contentMain.appendChild(nasaInfoOverlayEl); +} + +function removeNasaInfoOverlay() { + if (nasaInfoOverlayEl) { + nasaInfoOverlayEl.remove(); + nasaInfoOverlayEl = null; + } +} + function getSidebarStateMode(mode = getSidebarLayoutMode()) { return mode === "course" ? "course" : "dashboard"; } @@ -348,6 +474,7 @@ async function reminderWatch() { } function updateReminders() { + if (!assignments || typeof assignments.then !== "function") return; const fiveDays = 1000 * 60 * 60 * 24 * 5; const now = (new Date()).getTime(); const list = []; @@ -438,6 +565,17 @@ function isDomainCanvasPage() { } function startExtension() { + // Remove footer robustly - run first so a crash below can't block it + const removeFooter = () => { + const footer = document.querySelector('footer#footer.ic-app-footer, footer#footer'); + if (footer) footer.remove(); + }; + removeFooter(); + const footerObserver = new MutationObserver(() => { + removeFooter(); + }); + footerObserver.observe(document.documentElement, { childList: true, subtree: true }); + toggleDarkMode(); chrome.storage.sync.get(["better_sidebar", "sidebar_scale"], result => { @@ -463,7 +601,6 @@ function startExtension() { //getClassAverages(); - setTimeout(() => document.getElementById("footer")?.remove(), 800); setTimeout(() => runDarkModeFixer(false), 800); setTimeout(() => runDarkModeFixer(false), 4500); }); @@ -567,6 +704,21 @@ function applyOptionsChanges(changes) { applyAestheticChanges(); break; case "customBackgroundScale": + applyCustomBackground(); + break; + case "customBackgroundDaily": + applyCustomBackground(); + removeNasaInfoOverlay(); + break; + case "customBackgroundNasaDaily": + applyCustomBackground(); + if (options.customBackgroundNasaDaily === true) { + createNasaInfoOverlay(); + } else { + removeNasaInfoOverlay(); + } + break; + case "fitImageToScreen": applyCustomBackground(); break; // case "show_updates": @@ -674,22 +826,31 @@ function ensureBetterSidebar() { setupBetterSidebar(getSidebarLayoutMode()); } -function applyCustomBackground() { +async function applyCustomBackground() { // let style = document.querySelector("#DashboardCard_Container") let style = document.querySelector("#canvasrefined-background") || document.createElement('style'); style.id = "canvasrefined-background"; - - if (options.customBackgroundLink && options.customBackgroundLink !== "") { - const backgroundScale = Number(options.customBackgroundScale) || 100; - style.textContent = ` + + const activeBackground = await getActiveCustomBackground(); + console.log("[CanvasRefined] activeBackground:", activeBackground); + if (!activeBackground) { + if (style.isConnected) style.remove(); + return; + } + + const backgroundScale = Number(activeBackground.scale) || 100; + const backgroundUrl = JSON.stringify(activeBackground.url); + const fitToScreen = options.fitImageToScreen === true; + console.log("[CanvasRefined] Applying background:", activeBackground.url, "fitToScreen:", fitToScreen); + style.textContent = ` #wrapper { - background-image: url('${options.customBackgroundLink}') !important; + background-image: url(${backgroundUrl}) !important; background-repeat: no-repeat !important; background-position: center center !important; background-attachment: fixed !important; } @media (orientation: landscape) { - #wrapper { background-size: ${backgroundScale}% auto !important; } + #wrapper { background-size: ${fitToScreen ? 'cover' : backgroundScale + '% auto'} !important; } } @media (orientation: portrait) { #wrapper { background-size: cover !important; } @@ -698,6 +859,20 @@ function applyCustomBackground() { background: none !important; /* backdrop-filter: blur(10px) !important; */ border-radius: 5px; + padding-left: 20px !important; + } + #dashboard_header_container { + margin-left: -35px !important; + margin-right: -35px !important; + box-sizing: border-box !important; + background-color: color-mix(in srgb, var(--bcbackground-0), transparent 20%) !important; + border: 1px solid color-mix(in srgb, var(--bcborders) 60%, transparent) !important; + border-radius: 10px !important; + position: sticky !important; + top: 0 !important; + z-index: 1000 !important; + backdrop-filter: blur(8px) saturate(120%) !important; + -webkit-backdrop-filter: blur(8px) saturate(120%) !important; } #right-side-wrapper { // backdrop-filter: blur(10px) !important; @@ -837,8 +1012,7 @@ function applyCustomBackground() { tr.student_assignment.assignment_graded.editable > * { border:none!important }`; - // TODO: liquid glass? - } + // TODO: liquid glass? document.documentElement.appendChild(style); } @@ -903,6 +1077,7 @@ function checkDashboardReady() { loadDashboardNotes(); setupGPACalc(); showUpdateMsg(); + createNasaInfoOverlay(); } const rightSide = document.querySelector("#right-side"); @@ -942,7 +1117,7 @@ function recieveMessage(request, sender, sendResponse) { case ("getcolors"): sendResponse(getCardColors()); break; case ("inspect"): sendResponse(inspectDarkMode(true)); break; case ("fixdm"): sendResponse(runDarkModeFixer(true)); break; - case ("updateBackground"): clearCustomBackground(); sendResponse(true); break; + case ("updateBackground"): applyCustomBackground(); sendResponse(true); break; default: sendResponse(true); } } @@ -2442,8 +2617,13 @@ async function setupBetterSidebar(mode = getSidebarLayoutMode()) { const contentMain = document.querySelector(".ic-Layout-contentMain"); contentMain?.style.setProperty("flex", "1 1 auto"); contentMain?.style.setProperty("min-width", "0"); + const notRightSide = document.getElementById("not_right_side"); + if (notRightSide && isAccountsPage()) { + notRightSide.style.setProperty("width", "100%"); + notRightSide.style.setProperty("max-width", "100%"); + notRightSide.style.setProperty("min-width", "0"); + } if (layoutMode === "course" && leftSide) { - const notRightSide = document.getElementById("not_right_side"); const rightSideWrapper = document.getElementById("right-side-wrapper"); const sectionTabs = document.getElementById("section-tabs"); leftSide.style.setProperty("padding-top", "0", "important"); @@ -3790,7 +3970,7 @@ function setupGPACalc() { grades?.then(result => { const sortableContainer = document.querySelector(".ic-DashboardCard__box__container"); - const dashboardContainer = document.querySelector("#DashboardCard_Container"); + const dashboardContainer = sortableContainer || document.querySelector("#DashboardCard_Container"); if (!dashboardContainer) return; let container2 = document.querySelector(".canvasrefined-gpa-card"); @@ -3850,17 +4030,15 @@ function setupGPACalc() { if (cumulative) cumulative.style.display = options.gpa_calc_cumulative ? "block" : "none"; const shouldPrepend = options.gpa_calc_prepend === true; - const firstCard = shouldPrepend ? container : container2; - const secondCard = shouldPrepend ? container2 : container; - - if (firstCard.parentElement !== dashboardContainer) { - dashboardContainer.prepend(firstCard); - } - if (secondCard.parentElement !== dashboardContainer) { - if (shouldPrepend) { - dashboardContainer.prepend(secondCard); - } else { - dashboardContainer.appendChild(secondCard); + if (shouldPrepend) { + if (dashboardContainer.children[0] !== container || dashboardContainer.children[1] !== container2) { + dashboardContainer.insertBefore(container, dashboardContainer.firstChild); + dashboardContainer.insertBefore(container2, container.nextSibling); + } + } else { + if (dashboardContainer.lastElementChild !== container || container2.nextElementSibling !== container) { + dashboardContainer.appendChild(container2); + dashboardContainer.appendChild(container); } } } @@ -4013,23 +4191,39 @@ function changeFullWidth() { function changeGradientCards() { if (options.gradient_cards === true) { let cardheads = document.querySelectorAll('.ic-DashboardCard__header_hero'); - let cardcss = document.querySelector("#gradientcss") || document.createElement('style'); - cardcss.id = "gradientcss"; - cardcss.textContent = ""; - document.documentElement.appendChild(cardcss); + // Only create + append the style once; never re-append an already- + // attached element, since appending to triggers the + // MutationObserver in checkDashboardReady() and re-runs this function. + let cardcss = document.querySelector("#gradientcss"); + if (!cardcss) { + cardcss = document.createElement('style'); + cardcss.id = "gradientcss"; + document.documentElement.appendChild(cardcss); + } + + // Build the full CSS into a string first, then only touch the DOM + // if the content actually changed. This keeps #gradientcss from being + // cleared/rewritten on every observer tick. + let css = ""; for (let i = 0; i < cardheads.length; i++) { let colorone = cardheads[i].style.backgroundColor.split(','); let [r, g, b] = [parseInt(colorone[0].split('(')[1]), parseInt(colorone[1]), parseInt(colorone[2])]; let [h, s, l] = [rgbToHsl(r, g, b)[0], rgbToHsl(r, g, b)[1], rgbToHsl(r, g, b)[2]]; let degree = ((h % 60) / 60) >= .66 ? 30 : ((h % 60) / 60) <= .33 ? -30 : 15; let newh = h > 300 ? (360 - (h + 65)) + (65 + degree) : h + 65 + degree; - cardcss.textContent += ".ic-DashboardCard:nth-of-type(" + (i + 1) + ") .ic-DashboardCard__header_hero{background: linear-gradient(115deg, hsl(" + h + "deg," + s + "%," + l + "%) 5%, hsl(" + newh + "deg," + s + "%," + l + "%) 100%)!important}"; + css += ".ic-DashboardCard:nth-of-type(" + (i + 1) + ") .ic-DashboardCard__header_hero{background: linear-gradient(115deg, hsl(" + h + "deg," + s + "%," + l + "%) 5%, hsl(" + newh + "deg," + s + "%," + l + "%) 100%)!important}"; + } + + if (cardcss.textContent !== css) { + cardcss.textContent = css; } } else { let cardcss = document.querySelector("#gradientcss"); - if (cardcss) cardcss.textContent = ""; + if (cardcss && cardcss.textContent !== "") { + cardcss.textContent = ""; + } } } diff --git a/js/popup.js b/js/popup.js index 6d665ca..bed498c 100644 --- a/js/popup.js +++ b/js/popup.js @@ -29,6 +29,9 @@ const syncedSubOptions = [ "cardHeight", "customBackgroundLink", "customBackgroundScale", + "customBackgroundDaily", + "customBackgroundNasaDaily", + "fitImageToScreen", "sidebar_scale", ]; const localSwitches = []; @@ -133,6 +136,9 @@ const defaultOptions = { "customCardStyles": false, "customBackgroundLink": "", "customBackgroundScale": 100, + "customBackgroundDaily": false, + "customBackgroundNasaDaily": false, + "fitImageToScreen": false, } }; @@ -315,9 +321,41 @@ function setupCustomBackgroundScale(initial) { }); } +function getDailyBackgroundPreset() { + if (typeof backgroundPresets === "undefined" || !Array.isArray(backgroundPresets) || backgroundPresets.length === 0) { + return null; + } + + const today = new Date(); + const dayNumber = Math.floor(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate()) / 86400000); + return backgroundPresets[Math.abs(dayNumber) % backgroundPresets.length]; +} + +function syncCustomBackgroundDailyState(isDaily) { + const manualControls = document.getElementById("customBackgroundManualControls"); + if (manualControls) { + manualControls.style.opacity = isDaily ? "0.45" : "1"; + manualControls.style.pointerEvents = isDaily ? "none" : "auto"; + manualControls.style.filter = isDaily ? "grayscale(1)" : "none"; + } + + ["customBackgroundLink", "customBackgroundScale", "clearCustomBackground"].forEach(id => { + const el = document.getElementById(id); + if (el) el.disabled = isDaily; + }); + + document.querySelectorAll(".background-preset-card").forEach(button => { + button.disabled = isDaily; + }); + + renderBackgroundPresetSelection(); +} + function renderBackgroundPresetSelection() { - const currentLink = document.querySelector("#customBackgroundLink")?.value || ""; - const currentScale = String(document.querySelector("#customBackgroundScale")?.value || "100"); + const isDaily = document.querySelector("#customBackgroundDaily")?.checked === true || document.querySelector("#customBackgroundNasaDaily")?.checked === true; + const dailyPreset = isDaily ? getDailyBackgroundPreset() : null; + const currentLink = isDaily ? (dailyPreset?.url || "") : (document.querySelector("#customBackgroundLink")?.value || ""); + const currentScale = isDaily ? String(dailyPreset?.scale || "100") : String(document.querySelector("#customBackgroundScale")?.value || "100"); document.querySelectorAll(".background-preset-card").forEach(button => { const matchesLink = button.dataset.backgroundUrl === currentLink; const matchesScale = button.dataset.backgroundScale === currentScale; @@ -349,6 +387,29 @@ function displayBackgroundPresets() { }); }); renderBackgroundPresetSelection(); + syncCustomBackgroundDailyState(document.querySelector("#customBackgroundDaily")?.checked === true || document.querySelector("#customBackgroundNasaDaily")?.checked === true); +} + +function toggleBetterSidebarSubOptions(betterSidebarOn) { + const remlogoEl = document.getElementById("remlogo"); + if (remlogoEl) { + remlogoEl.style.display = betterSidebarOn ? "none" : "flex"; + } + const sidebarScaleEl = document.getElementById("sidebarScaleSub"); + if (sidebarScaleEl) { + sidebarScaleEl.style.display = betterSidebarOn ? "block" : "none"; + } +} + +// When the Better Todo List is on, its own "Hide Recent Feedback" sub-option +// (todo_hide_feedback) replaces the standalone "Hide recent feedback" toggle, +// so hide the big #hide_feedback toggle to avoid showing two controls for the +// same thing. Mirrors toggleBetterSidebarSubOptions. +function toggleBetterTodoSubOptions(betterTodoOn) { + const hideFeedbackEl = document.getElementById("hide_feedback"); + if (hideFeedbackEl) { + hideFeedbackEl.style.display = betterTodoOn ? "none" : "flex"; + } } function setup() { @@ -376,6 +437,9 @@ function setup() { "grade_hover", // "hide_completed", "hover_preview", + "customBackgroundDaily", + "customBackgroundNasaDaily", + "fitImageToScreen", // "scheduledReminder", "customCardStyles", ], @@ -493,8 +557,16 @@ function setup() { if (option === "auto_dark") { toggleDarkModeDisable(status); } + if (option === "better_sidebar") { + toggleBetterSidebarSubOptions(status); + } + if (option === "better_todo") { + toggleBetterTodoSubOptions(status); + } }); }); + toggleBetterSidebarSubOptions(sync["better_sidebar"] === true); + toggleBetterTodoSubOptions(sync["better_todo"] === true); }); chrome.storage.sync.get(menu.checkboxes, sync => { @@ -503,11 +575,21 @@ function setup() { if (!checkbox) {console.log(option); return;} checkbox.addEventListener("change", function (e) { let status = this.checked; - chrome.storage.sync.set(JSON.parse(`{"${option}": ${status}}`)); + if (option === "customBackgroundDaily" && status) { + document.querySelector("#customBackgroundNasaDaily").checked = false; + chrome.storage.sync.set({ "customBackgroundDaily": true, "customBackgroundNasaDaily": false }); + } else if (option === "customBackgroundNasaDaily" && status) { + document.querySelector("#customBackgroundDaily").checked = false; + chrome.storage.sync.set({ "customBackgroundNasaDaily": true, "customBackgroundDaily": false }); + } else { + chrome.storage.sync.set(JSON.parse(`{"${option}": ${status}}`)); + } + syncCustomBackgroundDailyState(document.querySelector("#customBackgroundDaily")?.checked === true || document.querySelector("#customBackgroundNasaDaily")?.checked === true); }); const value = sync[option] !== undefined ? sync[option] : defaultOptions.sync[option]; document.querySelector("#" + option).checked = value; }); + syncCustomBackgroundDailyState(sync.customBackgroundDaily === true || sync.customBackgroundNasaDaily === true); /* document.querySelector('#autodark_start').value = result.auto_dark_start["hour"] + ":" + result.auto_dark_start["minute"]; document.querySelector('#autodark_end').value = result.auto_dark_end["hour"] + ":" + result.auto_dark_end["minute"]; @@ -662,7 +744,7 @@ function setup() { final = { ...final, ...(await getExport(storage, ["custom_styles"])) }; break; case "export-background": - final = { ...final, ...(await getExport(storage, ["customBackgroundLink", "customBackgroundScale"])) }; + final = { ...final, ...(await getExport(storage, ["customBackgroundLink", "customBackgroundScale", "customBackgroundDaily", "fitImageToScreen"])) }; break; } } @@ -1270,6 +1352,7 @@ function saveCurrentTheme() { "cardHeight": current["cardHeight"], "customBackgroundLink": current["customBackgroundLink"], "customBackgroundScale": current["customBackgroundScale"], + "customBackgroundDaily": current["customBackgroundDaily"], } const now = new Date(); local["saved_themes"][now.getTime()] = trimmed; diff --git a/manifest.json b/manifest.json index 890cb8d..4eb77c1 100644 --- a/manifest.json +++ b/manifest.json @@ -25,7 +25,7 @@ "content_scripts": [ { "matches": ["https://*/*"], - "js": ["css/darkmodecss.js", "js/content.js"], + "js": ["css/darkmodecss.js", "js/backgrounds.js", "js/content.js"], "css": ["css/content.css"], "run_at": "document_start" }