custom image presets + bugfix

This commit is contained in:
Guy Sandler 2026-05-29 19:08:25 -07:00
parent 1c97f89e3a
commit dab27d4687
7 changed files with 192 additions and 40 deletions

View File

@ -99,7 +99,7 @@
"message": "Text"
},
"full_width": {
"message": "Dashboard Full Width"
"message": "Full Width Fix"
},
"report_issue": {
"message": "Report Issue"

View File

@ -20,8 +20,8 @@ h2 {font-size:24px;}
.header {font-size: 16px;display: flex;align-items: center;gap:12px; margin-bottom:14px;}
.header h1 { font-weight: 600; font-size:24px; }
#bclogo {height: 30px;width:30px;filter: none}
#numAssignmentsSlider, #numTodoItemsSlider, #sidebarScaleSlider {display: block;margin-top: 14px;width: 100%;-webkit-appearance: none; appearance: none;background:var(--inputbg);outline: none;height:6px;border-radius:20px;}
#numAssignmentsSlider::-webkit-slider-thumb, #numTodoItemsSlider::-webkit-slider-thumb, #sidebarScaleSlider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none;height: 18px; width: 18px;background: #727272;cursor: pointer;border-radius:30px;}
#numAssignmentsSlider, #numTodoItemsSlider, #sidebarScaleSlider, #customBackgroundScale {display: block;margin-top: 14px;width: 100%;-webkit-appearance: none; appearance: none;background:var(--inputbg);outline: none;height:6px;border-radius:20px;}
#numAssignmentsSlider::-webkit-slider-thumb, #numTodoItemsSlider::-webkit-slider-thumb, #sidebarScaleSlider::-webkit-slider-thumb, #customBackgroundScale::-webkit-slider-thumb {-webkit-appearance: none; appearance: none;height: 18px; width: 18px;background: #727272;cursor: pointer;border-radius:30px;}
.option-container {font-size: 14px; margin-top: 8px;background: var(--containerbg);padding: 18px;border-radius: 14px;box-sizing:border-box}
.options .option-container {padding: 14px;}
a.option-container {display: block;color:#5ca5f6;font-size: 14px;}
@ -96,6 +96,10 @@ h2 {margin-top: 20px;font-weight:600}
.theme-button:hover {background-size: 120%; background-position:center;}
.theme-button-creator {font-size:10px;white-space:nowrap}
.theme-button-title {font-weight: 600;font-size:12px;white-space:nowrap;}
.background-preset-grid {display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; margin-top: 10px;}
.background-preset-card {min-height: 96px; display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; border-radius: 8px;}
.background-preset-card.selected {outline: 2px solid #56Caf0; outline-offset: 2px;}
.background-preset-scale {font-size:10px;white-space:nowrap;opacity:0.9;}
.theme-sort-btn {padding:10px 30px 10px 20px;border-radius:7px;background:none;border:none;color: #9d9d9d;font-size:12px;font-weight:600;text-align: left;cursor: pointer;transition:.18s color}
.theme-sort-btn:hover {color: #fff;}
.theme-header {display:flex;justify-content: space-between;margin-bottom:10px;align-items:center}

View File

@ -1,5 +1,5 @@
<!doctype html>
<html lang="en" style="/*background:linear-gradient(115deg, rgb(255, 53, 88), rgb(255, 131, 73), rgb(255, 103, 187))*/">
<html lang="en">
<head>
<title>Canvas Refined</title>
@ -301,7 +301,7 @@
<div class="sliderknob"></div>
<div class="sliderbg"></div>
</div>
<span class="option-name" data-i18n="full_width">Dashboard full width</span>
<span class="option-name" data-i18n="full_width">Full Width Fix</span>
</div>
<div class="option" id="remlogo">
<input type="radio" id="off" name="remlogo">
@ -372,7 +372,7 @@
<h2 style="margin-top: 0" data-i18n="themes">Themes</h2>
<button class="big-button back-btn" data-i18n="back">Back</button>
</div>
<div class="option-container">
<div class="option-container" style="display:none;">
<div class="theme-header small-option">
<h3 class="header-small" style="margin:0">Submit your theme</h3>
<div class="big-button" id="show-submit-form">Show</div>
@ -940,7 +940,15 @@
</div>
<div class="custom-font option-container">
<h3 class="header-small">Custom Background</h3>
<p>Use an image url or upload an image file</p>
<p>Pick a preset or use your own image url.</p>
<div class="background-preset-grid" id="background-presets"></div>
<div class="background-scale-row">
<div style="display:flex;justify-content:space-between;gap:10px;align-items:center;margin-top:10px;">
<span class="sub-text" style="font-weight:600; color:#e2e2e2;">Image scale</span>
<span class="sub-text" id="customBackgroundScaleValue">100%</span>
</div>
<input type="range" min="50" max="200" step="1" id="customBackgroundScale">
</div>
<input style="width:85%;" class="card-input" id="customBackgroundLink" placeholder="https://...">
<button id="clearCustomBackground" class="big-button" style="margin-top: 8px;">Clear Background</button>
</div>
@ -1019,6 +1027,7 @@
</div>
<script type="text/javascript" src="../js/themes.js"></script>
<script type="text/javascript" src="../js/backgrounds.js"></script>
<script type="text/javascript" src="../js/popup.js"></script>
</body>

View File

@ -103,6 +103,7 @@ chrome.runtime.onInstalled.addListener(function () {
"cardHeight": 250,
"customCardStyles": false,
"customBackgroundLink": "",
"customBackgroundScale": 100,
}
};

32
js/backgrounds.js Normal file
View File

@ -0,0 +1,32 @@
const backgroundPresets = [
{
title: "Nature 1",
credit: "Kalen Emsley",
url: "https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
scale: 120,
},
{
title: "Nature 2",
credit: "John Fowler",
url: "https://images.unsplash.com/photo-1537819191377-d3305ffddce4?q=80&w=2621&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
scale: 115,
},
{
title: "Nature 3",
credit: "HeiKiwi",
url: "https://cdn.pixabay.com/photo/2023/08/23/18/39/dahlia-8209085_1280.jpg",
scale: 110,
},
{
title: "Moon",
credit: "NASA",
url: "https://images-assets.nasa.gov/image/art002e021283/art002e021283~large.jpg?w=1920&h=1280&fit=clip&crop=faces%2Cfocalpoint",
scale: 140,
},
{
title: "Illustration 1",
credit: "ahmetyuksek.",
url: "https://cdn.pixabay.com/photo/2025/09/19/05/48/mountain-range-9842371_1280.jpg",
scale: 100,
},
]

View File

@ -516,6 +516,9 @@ function applyOptionsChanges(changes) {
case "custom_styles":
applyAestheticChanges();
break;
case "customBackgroundScale":
applyCustomBackground();
break;
// case "show_updates":
// showUpdateMsg();
// break;
@ -624,10 +627,13 @@ function applyCustomBackground() {
style.id = "canvasrefined-background";
if (options.customBackgroundLink && options.customBackgroundLink !== "") {
const backgroundScale = Number(options.customBackgroundScale) || 100;
style.textContent = `
#wrapper {
background-image: url('${options.customBackgroundLink}') !important;
background-size: cover !important;
background-size: ${backgroundScale}% auto !important;
background-repeat: no-repeat !important;
background-position: center center !important;
background-attachment: fixed !important;
}
.ic-Dashboard-header__layout {
@ -3706,28 +3712,41 @@ function setupGPACalc() {
try {
grades?.then(result => {
if (!document.querySelector(".ic-DashboardCard__box__container")) return;
const dashboardContainer = document.querySelector(".ic-DashboardCard__box__container");
if (!dashboardContainer) return;
let container2 = document.querySelector(".canvasrefined-gpa-card") || document.createElement("div");
let container2 = document.querySelector(".canvasrefined-gpa-card");
let container = document.querySelector(".canvasrefined-gpa");
const alreadyRendered = container2?.dataset?.canvasrefinedGpaRendered === "true" && container?.dataset?.canvasrefinedGpaRendered === "true";
if (!container2) {
container2 = document.createElement("div");
container2.className = "canvasrefined-gpa-card";
}
if (!container) {
container = document.createElement("div");
container.className = "canvasrefined-gpa";
}
container2.style.display = options.gpa_calc === true ? "inline-block" : "none";
if (!alreadyRendered) {
container2.innerHTML = `<h3 class="canvasrefined-gpa-header">GPA</h3><div><div><p id="canvasrefined-gpa-unweighted"></p><p>Current</p></div><div style="display:${options["gpa_calc_weighted"] ? "block" : "none"}"><p id="canvasrefined-gpa-weighted"></p><p>Weighted</p></div><div style="display:${options["gpa_calc_cumulative"] ? "block" : "none"}"><p id="canvasrefined-gpa-cumulative"></p><p>Cumulative</p></div></div>`;
let editBtn = makeElement("button", container2, { "className": "canvasrefined-gpa-edit-btn", "textContent": "Edit Calculator" });
let container = document.querySelector(".canvasrefined-gpa") || document.createElement("div");
container.className = "canvasrefined-gpa";
container.innerHTML = '<h3 class="canvasrefined-gpa-header">GPA Calculator</h3><div class="canvasrefined-gpa-courses-container"><div class="canvasrefined-gpa-courses"></div></div>';
if (options.gpa_calc_prepend === true) {
document.querySelector(".ic-DashboardCard__box__container").prepend(container2);
document.querySelector(".ic-DashboardCard__box__container").prepend(container);
dashboardContainer.prepend(container2);
dashboardContainer.prepend(container);
} else {
document.querySelector(".ic-DashboardCard__box__container").appendChild(container2);
document.querySelector(".ic-DashboardCard__box__container").appendChild(container);
dashboardContainer.appendChild(container2);
dashboardContainer.appendChild(container);
}
let location = document.querySelector(".canvasrefined-gpa-courses");
if (!location) return;
let cumulative = createGPACalcCourse(location, { "id": "cumulative", "enrollments": [{ "has_grading_periods": true, "current_period_computed_current_score": 0 }] });
cumulative.id = "canvasrefined-cumulative-gpa";
result.forEach(course => createGPACalcCourse(location, course));
@ -3744,6 +3763,30 @@ function setupGPACalc() {
}
});
container2.dataset.canvasrefinedGpaRendered = "true";
container.dataset.canvasrefinedGpaRendered = "true";
} else {
const weighted = container2.querySelector("#canvasrefined-gpa-weighted")?.parentElement;
const cumulative = container2.querySelector("#canvasrefined-gpa-cumulative")?.parentElement;
if (weighted) weighted.style.display = options.gpa_calc_weighted ? "block" : "none";
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);
}
}
}
calculateGPA2();
});
} catch (e) {
@ -3835,7 +3878,7 @@ function applyAestheticChanges() {
if (options.remlogo === true) style.textContent += ".ic-app-header__logomark-container{display:none}";
if (options.disable_color_overlay === true) style.textContent += ".ic-DashboardCard__header_hero{opacity: 0!important} .ic-DashboardCard__header-button-bg{opacity: 1!important}";
if (options.hide_feedback === true) style.textContent += ".recent_feedback {display: none}";
if (options.full_width === true) style.textContent += ".ic-Layout-wrapper{max-width:100%!important}";
if (options.full_width === true) style.textContent += "#wrapper,.ic-Layout-wrapper{max-width:100%!important}";
if (options.customCardStyles === true) {
if (options.imageSize !== undefined && options.imageSize !== 100) style.textContent += `.ic-DashboardCard__header_image {transform: scale(${options.imageSize / 100})!important; }`;

View File

@ -28,6 +28,7 @@ const syncedSubOptions = [
"cardWidth",
"cardHeight",
"customBackgroundLink",
"customBackgroundScale",
"sidebar_scale",
];
const localSwitches = [];
@ -130,6 +131,7 @@ const defaultOptions = {
"cardHeight": 250,
"customCardStyles": false,
"customBackgroundLink": "",
"customBackgroundScale": 100,
}
};
@ -293,9 +295,61 @@ function setupCustomBackgroundLink(initial) {
el.value = initial || "";
el.addEventListener("input", (e) => {
chrome.storage.sync.set({ "customBackgroundLink": e.target.value });
renderBackgroundPresetSelection();
})
}
function setupCustomBackgroundScale(initial) {
const el = document.querySelector("#customBackgroundScale");
const output = document.querySelector("#customBackgroundScaleValue");
if (!el || !output) return;
const value = Number(initial) || 100;
el.value = value;
output.textContent = `${value}%`;
el.addEventListener("input", (e) => {
const nextValue = parseInt(e.target.value);
output.textContent = `${nextValue}%`;
chrome.storage.sync.set({ "customBackgroundScale": nextValue });
renderBackgroundPresetSelection();
});
}
function renderBackgroundPresetSelection() {
const currentLink = document.querySelector("#customBackgroundLink")?.value || "";
const currentScale = 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;
button.classList.toggle("selected", matchesLink && matchesScale);
});
}
function displayBackgroundPresets() {
const container = document.querySelector("#background-presets");
if (!container || container.dataset.rendered === "true" || typeof backgroundPresets === "undefined") return;
container.dataset.rendered = "true";
container.innerHTML = backgroundPresets.map(preset => `
<button type="button" class="theme-button customization-button background-preset-card" data-background-url="${preset.url}" data-background-scale="${preset.scale}" style="background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), url('${preset.url}');">
<p class="theme-button-title">${preset.title}</p>
<p class="theme-button-creator">${preset.credit}</p>
<p class="background-preset-scale">Scale ${preset.scale}%</p>
</button>
`).join("");
container.querySelectorAll(".background-preset-card").forEach(button => {
button.addEventListener("click", () => {
const backgroundUrl = button.dataset.backgroundUrl;
const backgroundScale = parseInt(button.dataset.backgroundScale);
document.querySelector("#customBackgroundLink").value = backgroundUrl;
document.querySelector("#customBackgroundScale").value = backgroundScale;
document.querySelector("#customBackgroundScaleValue").textContent = `${backgroundScale}%`;
chrome.storage.sync.set({ "customBackgroundLink": backgroundUrl, "customBackgroundScale": backgroundScale });
renderBackgroundPresetSelection();
});
});
renderBackgroundPresetSelection();
}
function setup() {
const menu = {
@ -415,6 +469,10 @@ function setup() {
identifier: "customBackgroundLink",
setup: (initial) => setupCustomBackgroundLink(initial),
},
{
identifier: "customBackgroundScale",
setup: (initial) => setupCustomBackgroundScale(initial),
},
],
};
@ -456,6 +514,7 @@ function setup() {
document.querySelector("#todo_hr24").checked = result.todo_hr24 == true;
*/
toggleDarkModeDisable(sync.auto_dark);
displayBackgroundPresets();
});
const specialOptions = menu.special.map(obj => obj.identifier);
@ -602,7 +661,7 @@ function setup() {
final = { ...final, ...(await getExport(storage, ["custom_styles"])) };
break;
case "export-background":
final = { ...final, ...(await getExport(storage, ["customBackgroundLink"])) };
final = { ...final, ...(await getExport(storage, ["customBackgroundLink", "customBackgroundScale"])) };
break;
}
}
@ -857,8 +916,11 @@ function setup() {
});
document.getElementById("clearCustomBackground").addEventListener("click", () => {
chrome.storage.sync.set({ "customBackgroundLink": "" });
chrome.storage.sync.set({ "customBackgroundLink": "", "customBackgroundScale": 100 });
document.querySelector("#customBackgroundLink").value = "";
document.querySelector("#customBackgroundScale").value = 100;
document.querySelector("#customBackgroundScaleValue").textContent = "100%";
renderBackgroundPresetSelection();
sendFromPopup("updateBackground");
});
@ -1206,6 +1268,7 @@ function saveCurrentTheme() {
"cardWidth": current["cardWidth"],
"cardHeight": current["cardHeight"],
"customBackgroundLink": current["customBackgroundLink"],
"customBackgroundScale": current["customBackgroundScale"],
}
const now = new Date();
local["saved_themes"][now.getTime()] = trimmed;