started dashboard v2

This commit is contained in:
Guy Sandler 2026-07-20 07:43:05 -07:00
parent fb5651eda9
commit 16c3666e0b
5 changed files with 690 additions and 31 deletions

View File

@ -175,4 +175,101 @@
50% { 50% {
opacity: .5; opacity: .5;
} }
}
/* Dashboard V2 */
#canvasrefined-v2-container + .canvasrefined-gpa-card {
margin-top: 18px;
}
#canvasrefined-v2-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
padding: 0 12px 20px;
box-sizing: border-box;
max-width: 1200px;
margin: 25px auto 0;
}
#DashboardCard_Container .ic-Dashboard-header {
margin-bottom: 0;
}
.canvasrefined-v2-active .ic-DashboardCard__box__container {
display: none !important;
}
.canvasrefined-v2-card {
display: block;
width: 262px;
box-sizing: border-box;
cursor: grab;
margin: 0 !important;
}
#canvasrefined-v2-container.drag-active > * > * {
pointer-events: none;
}
.canvasrefined-v2-card[draggable="true"]:active {
cursor: grabbing;
opacity: 0.7;
}
.canvasrefined-v2-card.dragging {
opacity: 0.4;
transform: scale(0.98);
}
.canvasrefined-v2-card.drag-over {
outline: 2px solid var(--bclinks, #56Caf0);
outline-offset: -2px;
}
.canvasrefined-v2-card .ic-DashboardCard__action-layout svg {
fill: var(--bctext-1, #333);
}
.canvasrefined-v2-card .ic-DashboardCard__action {
color: var(--bctext-1, #333);
}
#canvasrefined-v2-container .canvasrefined-gpa-card {
margin: 0;
width: 262px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
background: var(--bcbackground-1, #2d2d2d);
align-self: flex-start;
}
#canvasrefined-v2-container .canvasrefined-gpa-edit-btn {
background: var(--bcbackground-2, #3a3a3a);
border: 1px solid var(--bcbackground-2, #555);
color: var(--bctext-0, #f5f5f5);
}
#canvasrefined-v2-container .canvasrefined-gpa-header {
color: var(--bctext-0, #f5f5f5);
}
#canvasrefined-v2-container .canvasrefined-gpa p {
color: var(--bctext-1, #ccc);
}
#canvasrefined-v2-container .canvasrefined-gpa {
background: var(--bcbackground-1, #2d2d2d);
border-radius: 0 0 4px 4px;
box-shadow: none;
margin: 0;
}
#canvasrefined-v2-container .canvasrefined-gpa-course {
border-color: var(--bcbackground-2, #444);
}
body.canvasrefined-limit-assignments .canvasrefined-card-assignment {
max-height: 160px;
overflow-y: auto;
}
body.canvasrefined-truncate-names .canvasrefined-card-assignment {
overflow-x: hidden;
}
body.canvasrefined-truncate-names .canvasrefined-assignment-link {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 240px;
display: block;
}
#canvasrefined-v2-container .canvasrefined-gpa-courses-container {
max-height: 220px;
overflow-y: auto;
} }

View File

@ -58,6 +58,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 9v4"></path><path d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z"></path><path d="M12 16h.01"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 9v4"></path><path d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z"></path><path d="M12 16h.01"></path></svg>
<span data-i18n="report_issue">Report issue</span> <span data-i18n="report_issue">Report issue</span>
</button> </button>
<button id="experimental-btn" class="big-button tab-btn">
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" width="15" height="15"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <rect width="48" height="48" fill="white" fill-opacity="0.01"></rect> <path fill-rule="evenodd" clip-rule="evenodd" d="M18.019 4V15.0386L6.27437 39.3014C5.48686 40.9283 6.16731 42.8855 7.79421 43.673C8.23876 43.8882 8.72624 44 9.22013 44H38.7874C40.5949 44 42.0602 42.5347 42.0602 40.7273C42.0602 40.2348 41.949 39.7488 41.7351 39.3052L30.0282 15.0386V4H18.019Z" stroke="currentColor" stroke-width="4" stroke-linejoin="round"></path> <path d="M10.9604 29.9998C13.1241 31.3401 15.2893 32.0103 17.4559 32.0103C19.6226 32.0103 21.7908 31.3401 23.9605 29.9998C26.1088 28.6735 28.2664 28.0103 30.433 28.0103C32.5997 28.0103 34.7755 28.6735 36.9604 29.9998" stroke="currentColor" stroke-width="4" stroke-linecap="round"></path> </g></svg>
<span>Experimental</span>
</button>
<!-- <button id="updates-btn" class="big-button tab-btn"> <!-- <button id="updates-btn" class="big-button tab-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4" /><path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" /></svg> <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4" /><path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" /></svg>
<span data-i18n="updates">Updates</span> <span data-i18n="updates">Updates</span>
@ -124,6 +128,14 @@
<input type="checkbox" id="relative_dues" name="relative_dues"> <input type="checkbox" id="relative_dues" name="relative_dues">
<label for="relative_dues" class="sub-text" data-i18n="relative_due_dates">Relative due dates</label> <label for="relative_dues" class="sub-text" data-i18n="relative_due_dates">Relative due dates</label>
</div> </div>
<div class="sub-option">
<input type="checkbox" id="v2_limit_assignments" name="v2_limit_assignments">
<label for="v2_limit_assignments" class="sub-text">Limited height</label>
</div>
<div class="sub-option">
<input type="checkbox" id="v2_truncate_names" name="v2_truncate_names">
<label for="v2_truncate_names" class="sub-text">Truncate names</label>
</div>
<div style="margin-top: 5px"> <div style="margin-top: 5px">
<span class="sub-text" data-i18n="max_items">Max items to show: </span><span <span class="sub-text" data-i18n="max_items">Max items to show: </span><span
id="numAssignments"></span> id="numAssignments"></span>
@ -981,6 +993,28 @@
</div> </div>
</div> </div>
<div class="experimental tab" style="display:none">
<div class="tab-header">
<div>
<h2 style="margin-top: 0">Experimental</h2>
</div>
<button class="big-button back-btn" data-i18n="back">Back</button>
</div>
<div class="options">
<div class="option-container">
<div class="option" id="dashboard_v2">
<input type="radio" id="off" name="dashboard_v2">
<input type="radio" id="on" name="dashboard_v2">
<div class="slider">
<div class="sliderknob"></div>
<div class="sliderbg"></div>
</div>
<span class="option-name">Dashboard V2</span>
</div>
</div>
</div>
</div>
<div class="report-issue-container tab"> <div class="report-issue-container tab">
<div class="tab-header"> <div class="tab-header">
<div> <div>

View File

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

View File

@ -196,6 +196,7 @@ let timeCheck = null;
let reminderCheck = null; let reminderCheck = null;
let betterSidebarLoading = false; let betterSidebarLoading = false;
let dashboardReadyTimer = null; let dashboardReadyTimer = null;
let v2DragSetup = false;
//let assignmentData = null; //let assignmentData = null;
/* /*
@ -460,6 +461,8 @@ function startExtension() {
watchSequenceFooter(); watchSequenceFooter();
watchSubmissionPageButton(); watchSubmissionPageButton();
watchProfileLogoutPageButton(); watchProfileLogoutPageButton();
document.body?.classList.toggle("canvasrefined-limit-assignments", options.v2_limit_assignments);
document.body?.classList.toggle("canvasrefined-truncate-names", options.v2_truncate_names);
//getClassAverages(); //getClassAverages();
@ -499,7 +502,7 @@ function applyOptionsChanges(changes) {
toggleAutoDarkMode(); toggleAutoDarkMode();
break; break;
case "gradient_cards": case "gradient_cards":
changeGradientCards(); if (!isDashboardV2Active()) changeGradientCards();
break; break;
case "widget_clock": case "widget_clock":
loadWidgets(); loadWidgets();
@ -510,7 +513,11 @@ function applyOptionsChanges(changes) {
case "dashboard_grades": case "dashboard_grades":
case "grade_hover": case "grade_hover":
if (!grades) getGrades(); if (!grades) getGrades();
insertGrades(); if (isDashboardV2Active()) {
renderDashboardV2();
} else {
insertGrades();
}
break; break;
case "assignments_due": case "assignments_due":
case "num_assignments": case "num_assignments":
@ -520,19 +527,31 @@ function applyOptionsChanges(changes) {
.length === 0 .length === 0
) )
setupCardAssignments(); setupCardAssignments();
loadCardAssignments(); if (isDashboardV2Active()) {
loadV2Assignments();
} else {
loadCardAssignments();
}
break; break;
case "custom_assignments": case "custom_assignments":
case "assignment_date_format": case "assignment_date_format":
case "card_overdues": case "card_overdues":
case "relative_dues": case "relative_dues":
cardAssignments = preloadAssignmentEls(); cardAssignments = preloadAssignmentEls();
loadCardAssignments(); if (isDashboardV2Active()) {
renderDashboardV2();
} else {
loadCardAssignments();
}
break; break;
case "custom_cards": case "custom_cards":
case "custom_cards_2": case "custom_cards_2":
case "custom_cards_3": case "custom_cards_3":
customizeCards(); if (isDashboardV2Active()) {
renderDashboardV2();
} else {
customizeCards();
}
break; break;
case "todo_hr24": case "todo_hr24":
case "todo_separate_scrollbar": case "todo_separate_scrollbar":
@ -637,6 +656,29 @@ function applyOptionsChanges(changes) {
} }
break; break;
} }
case "dashboard_v2":
if (options.dashboard_v2) {
renderDashboardV2();
document.body.classList.toggle("canvasrefined-limit-assignments", options.v2_limit_assignments);
document.body.classList.toggle("canvasrefined-truncate-names", options.v2_truncate_names);
moveGPACardToV2();
} else {
removeDashboardV2();
document.body.classList.remove("canvasrefined-limit-assignments", "canvasrefined-truncate-names");
moveGPACardOutOfV2();
let cards = document.querySelectorAll(".ic-DashboardCard");
changeGradientCards();
loadCardAssignments();
customizeCards(cards);
insertGrades();
}
break;
case "v2_limit_assignments":
document.body.classList.toggle("canvasrefined-limit-assignments", options.v2_limit_assignments);
break;
case "v2_truncate_names":
document.body.classList.toggle("canvasrefined-truncate-names", options.v2_truncate_names);
break;
} }
}); });
} }
@ -898,13 +940,22 @@ function checkDashboardReady() {
const c = document.querySelector("#DashboardCard_Container"); const c = document.querySelector("#DashboardCard_Container");
if (c) { if (c) {
let cards = document.querySelectorAll(".ic-DashboardCard"); if (isDashboardV2Active()) {
loadWidgets(); const v2 = document.querySelector("#canvasrefined-v2-container");
changeGradientCards(); if (!v2 || v2.dataset.rendered !== "true") {
setupCardAssignments(); loadWidgets();
loadCardAssignments(); setupCardAssignments();
customizeCards(cards); renderDashboardV2();
insertGrades(); }
} else {
let cards = document.querySelectorAll(".ic-DashboardCard");
loadWidgets();
changeGradientCards();
setupCardAssignments();
loadCardAssignments();
customizeCards(cards);
insertGrades();
}
loadDashboardNotes(); loadDashboardNotes();
setupGPACalc(); setupGPACalc();
showUpdateMsg(); showUpdateMsg();
@ -3824,7 +3875,10 @@ function setupGPACalc() {
container.innerHTML = '<h3 class="canvasrefined-gpa-header">GPA Calculator</h3><div class="canvasrefined-gpa-courses-container"><div class="canvasrefined-gpa-courses"></div></div>'; 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) { const v2Container = document.querySelector("#canvasrefined-v2-container");
if (isDashboardV2Active() && v2Container) {
// Don't append here — moveGPACardToV2() in renderDashboardV2 handles placement
} else if (options.gpa_calc_prepend === true) {
dashboardContainer.prepend(container2); dashboardContainer.prepend(container2);
dashboardContainer.prepend(container); dashboardContainer.prepend(container);
} else { } else {
@ -3859,18 +3913,24 @@ function setupGPACalc() {
if (weighted) weighted.style.display = options.gpa_calc_weighted ? "block" : "none"; if (weighted) weighted.style.display = options.gpa_calc_weighted ? "block" : "none";
if (cumulative) cumulative.style.display = options.gpa_calc_cumulative ? "block" : "none"; if (cumulative) cumulative.style.display = options.gpa_calc_cumulative ? "block" : "none";
const shouldPrepend = options.gpa_calc_prepend === true; const v2Container = document.querySelector("#canvasrefined-v2-container");
const firstCard = shouldPrepend ? container : container2; if (isDashboardV2Active() && v2Container) {
const secondCard = shouldPrepend ? container2 : container; if (container2.parentElement !== v2Container) v2Container.appendChild(container2);
if (container.parentElement !== v2Container) v2Container.appendChild(container);
} else {
const shouldPrepend = options.gpa_calc_prepend === true;
const firstCard = shouldPrepend ? container : container2;
const secondCard = shouldPrepend ? container2 : container;
if (firstCard.parentElement !== dashboardContainer) { if (firstCard.parentElement !== dashboardContainer) {
dashboardContainer.prepend(firstCard); dashboardContainer.prepend(firstCard);
} }
if (secondCard.parentElement !== dashboardContainer) { if (secondCard.parentElement !== dashboardContainer) {
if (shouldPrepend) { if (shouldPrepend) {
dashboardContainer.prepend(secondCard); dashboardContainer.prepend(secondCard);
} else { } else {
dashboardContainer.appendChild(secondCard); dashboardContainer.appendChild(secondCard);
}
} }
} }
} }
@ -4228,7 +4288,7 @@ function getGrades() {
} }
function getColors() { function getColors() {
if (options.tab_icons || options.better_todo || options.better_sidebar) { if (options.tab_icons || options.better_todo || options.better_sidebar || options.dashboard_v2) {
return getData(`${domain}/api/v1/users/self/colors`).then(data => { return getData(`${domain}/api/v1/users/self/colors`).then(data => {
let cards = options.custom_cards_3; let cards = options.custom_cards_3;
Object.keys(cards).forEach(key => { Object.keys(cards).forEach(key => {
@ -4259,7 +4319,7 @@ function getAssignments() {
} }
function getApiData() { function getApiData() {
if (current_page === "/" || current_page === "" || options.better_todo || options.better_sidebar) { if (current_page === "/" || current_page === "" || options.better_todo || options.better_sidebar || options.dashboard_v2) {
getAssignments(); getAssignments();
getGrades(); getGrades();
getColors(); getColors();
@ -4381,6 +4441,463 @@ function formatCardDue(date) {
return options.assignment_date_format ? (due.getDate()) + "/" + (due.getMonth() + 1) : (due.getMonth() + 1) + "/" + (due.getDate()); return options.assignment_date_format ? (due.getDate()) + "/" + (due.getMonth() + 1) : (due.getMonth() + 1) + "/" + (due.getDate());
} }
function setupV2DragAndDrop() {
if (v2DragSetup) return;
v2DragSetup = true;
let dragState = null;
function onMouseDown(e) {
if (e.button !== 0) return;
if (e.target.closest("a, button")) return;
const card = e.target.closest(".canvasrefined-v2-card, .canvasrefined-gpa-card");
if (!card) return;
const header = e.target.closest(".ic-DashboardCard__header");
if (!header) return;
const v2Container = document.querySelector("#canvasrefined-v2-container");
if (!v2Container || v2Container.dataset.rendered !== "true") return;
dragState = {
card: card,
courseId: card.dataset.courseId,
startX: e.clientX,
startY: e.clientY,
ghost: null,
dragging: false,
v2Container: v2Container
};
}
function onMouseMove(e) {
if (!dragState) return;
const dx = e.clientX - dragState.startX;
const dy = e.clientY - dragState.startY;
if (!dragState.dragging) {
if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
dragState.dragging = true;
dragState.card.classList.add("dragging");
dragState.v2Container.classList.add("drag-active");
const ghost = dragState.card.cloneNode(true);
ghost.classList.add("canvasrefined-v2-ghost");
ghost.style.position = "fixed";
ghost.style.opacity = "0.8";
ghost.style.pointerEvents = "none";
ghost.style.zIndex = "9999";
ghost.style.width = dragState.card.offsetWidth + "px";
ghost.style.left = (e.clientX - dragState.card.offsetWidth / 2) + "px";
ghost.style.top = (e.clientY - 20) + "px";
document.body.appendChild(ghost);
dragState.ghost = ghost;
}
return;
}
if (dragState.ghost) {
dragState.ghost.style.left = (e.clientX - dragState.card.offsetWidth / 2) + "px";
dragState.ghost.style.top = (e.clientY - 20) + "px";
}
const v2Container = dragState.v2Container;
v2Container.querySelectorAll(".drag-over").forEach(c => c.classList.remove("drag-over"));
const cards = Array.from(v2Container.querySelectorAll(".canvasrefined-v2-card, .canvasrefined-gpa-card"));
for (const targetCard of cards) {
if (targetCard === dragState.card) continue;
const rect = targetCard.getBoundingClientRect();
const midX = rect.left + rect.width / 2;
if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) {
targetCard.classList.add("drag-over");
if (e.clientX < midX) {
v2Container.insertBefore(dragState.card, targetCard);
} else {
v2Container.insertBefore(dragState.card, targetCard.nextSibling);
}
break;
}
}
}
function onMouseUp(e) {
if (!dragState) return;
if (dragState.dragging) {
if (dragState.ghost) {
dragState.ghost.remove();
}
dragState.card.classList.remove("dragging");
dragState.v2Container.classList.remove("drag-active");
dragState.v2Container.querySelectorAll(".drag-over").forEach(c => c.classList.remove("drag-over"));
if (dragState.courseId === "gpa") {
const gpaEdit = document.querySelector(".canvasrefined-gpa");
if (gpaEdit) dragState.v2Container.appendChild(gpaEdit);
}
saveV2CardOrder();
}
dragState = null;
}
document.addEventListener("mousedown", onMouseDown, true);
document.addEventListener("mousemove", onMouseMove, true);
document.addEventListener("mouseup", onMouseUp, true);
}
function renderDashboardV2() {
const dashboardContainer = document.querySelector("#DashboardCard_Container");
if (!dashboardContainer) return;
dashboardContainer.classList.add("canvasrefined-v2-active");
const originalCards = document.querySelector(".ic-DashboardCard__box__container");
if (originalCards) originalCards.style.display = "none";
let v2Container = document.querySelector("#canvasrefined-v2-container");
if (!v2Container) {
v2Container = document.createElement("div");
v2Container.id = "canvasrefined-v2-container";
dashboardContainer.prepend(v2Container);
v2Container.addEventListener("dragover", (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = "move";
});
}
if (v2Container.dataset.rendered === "true") return;
setupV2DragAndDrop();
v2Container.dataset.rendered = "true";
v2Container.innerHTML = "";
const cards = options.custom_cards || {};
const cardLinks = options.custom_cards_2 || {};
const cardColors = options.custom_cards_3 || {};
const courseIds = Object.keys(cards);
if (courseIds.length === 0) {
v2Container.innerHTML = '<div class="canvasrefined-v2-empty">No courses found. Try refreshing the page.</div>';
return;
}
courseIds.forEach(courseId => {
const cardOpts = cards[courseId] || {};
const linkOpts = cardLinks[courseId] || {};
const colorData = cardColors[courseId] || {};
const courseColor = colorData.color || "#394b58";
if (cardOpts.hidden === true) return;
const card = document.createElement("div");
card.className = "ic-DashboardCard canvasrefined-v2-card";
card.dataset.courseId = courseId;
card.setAttribute("aria-label", cardOpts.name || cardOpts.default || "Course");
const header = document.createElement("div");
header.className = "ic-DashboardCard__header";
if (cardOpts.img && cardOpts.img !== "" && cardOpts.img !== "none") {
const headerImage = document.createElement("div");
headerImage.className = "ic-DashboardCard__header_image";
headerImage.style.backgroundImage = "url(\"" + cardOpts.img + "\")";
const hero = document.createElement("div");
hero.className = "ic-DashboardCard__header_hero";
hero.setAttribute("aria-hidden", "true");
hero.style.backgroundColor = courseColor;
hero.style.opacity = "0.6";
headerImage.appendChild(hero);
header.appendChild(headerImage);
} else {
const hero = document.createElement("div");
hero.className = "ic-DashboardCard__header_hero";
hero.setAttribute("aria-hidden", "true");
hero.style.backgroundColor = courseColor;
hero.style.opacity = "0.8";
header.appendChild(hero);
}
const headerLink = document.createElement("a");
headerLink.className = "ic-DashboardCard__link";
headerLink.href = domain + "/courses/" + courseId;
headerLink.setAttribute("draggable", "false");
const headerContent = document.createElement("div");
headerContent.className = "ic-DashboardCard__header_content";
const title = document.createElement("h2");
title.className = "ic-DashboardCard__header-title ellipsis";
const titleSpan = document.createElement("span");
titleSpan.style.color = courseColor;
titleSpan.textContent = cardOpts.name || cardOpts.default || ("Course " + courseId);
title.appendChild(titleSpan);
headerContent.appendChild(title);
const subtitle = document.createElement("div");
subtitle.className = "ic-DashboardCard__header-subtitle ellipsis";
subtitle.title = cardOpts.default || "";
subtitle.textContent = cardOpts.default || "";
headerContent.appendChild(subtitle);
const term = document.createElement("div");
term.className = "ic-DashboardCard__header-term ellipsis";
headerContent.appendChild(term);
headerLink.appendChild(headerContent);
header.appendChild(headerLink);
if (options.dashboard_grades === true) {
const gradeLink = document.createElement("a");
gradeLink.className = "canvasrefined-card-grade";
gradeLink.href = domain + "/courses/" + courseId + "/grades";
gradeLink.textContent = "--%";
header.appendChild(gradeLink);
}
card.appendChild(header);
const actions = document.createElement("nav");
actions.className = "ic-DashboardCard__action-container";
actions.setAttribute("aria-label", "Actions for course " + courseId);
const defaultLinks = [
{ path: "/announcements", label: "Announcements", icon: '<svg viewBox="0 0 1920 1920" width="19" height="19"><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></svg>' },
{ path: "/assignments", label: "Assignments", icon: '<svg viewBox="0 0 1920 1920" width="19" height="19"><path d="M1468.214 0v564.698h-112.94V112.94H112.94v1694.092h1242.334v-225.879h112.94v338.819H0V0h1468.214Zm129.428 581.311c22.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.504-24.96 16.49-39.98 16.49h-225.88c-31.17 0-56.469-25.299-56.469-56.47v-225.88c0-15.02 5.986-29.364 16.49-39.867Zm-155.291 314.988-425.895 425.895v146.031h146.03l425.895-425.895-146.03-146.03Zm-764.714 346.047v112.94H338.82v-112.94h338.818Zm225.88-225.88v112.94H338.818v-112.94h564.697Zm734.106-315.44-115.424 115.425 146.03 146.03 115.425-115.423-146.031-146.031ZM1129.395 338.83v451.758H338.82V338.83h790.576Zm-112.94 112.94H451.759v225.878h564.698V451.77Z" fill-rule="evenodd"></path></svg>' },
{ path: "/discussion_topics", label: "Discussions", icon: '<svg viewBox="0 0 1920 1920" width="19" height="19"><path d="M677.647 16v338.936h112.941V129.054h1016.47V919.53h-225.994v259.765L1321.412 919.53h-79.172V467.878H0v1016.47h338.71v418.9l417.996-418.9h485.534v-451.877h32.753l419.125 419.124v-419.124H1920V16H677.647ZM338.79 919.563h564.706v-112.94H338.79v112.94Zm0 225.883h338.936v-113.054H338.79v113.054Zm-225.85-564.74h1016.47v790.701H710.4L451.652 1631.06v-259.652h-338.71V580.706Z" fill-rule="evenodd"></path></svg>' },
{ path: "/files", label: "Files", icon: '<svg viewBox="0 0 1920 1920" width="19" height="19"><path d="M1807.059 1637.706c0 31.172-25.412 56.47-56.47 56.47H169.411c-31.06 0-56.47-25.298-56.47-56.47V225.94h590.907L854.4 451.824H225.882v112.94H1807.06v1072.942ZM990.269 451.824 764.385 113H0v1524.706c0 93.402 76.01 169.412 169.412 169.412h1581.176c93.403 0 169.412-76.01 169.412-169.412V451.824H990.268Z" fill-rule="evenodd"></path></svg>' }
];
for (let i = 0; i < 4; i++) {
const action = document.createElement("a");
action.className = "ic-DashboardCard__action";
action.setAttribute("draggable", "false");
action.style.display = "inherit";
const customLink = linkOpts.links && linkOpts.links[i];
const img = document.createElement("img");
img.className = "canvasrefined-link-image";
img.style.display = "none";
action.appendChild(img);
if (customLink && customLink.path === "none") {
action.style.display = "none";
} else if (customLink && !customLink.is_default && customLink.path) {
action.href = customLink.path;
action.target = "_blank";
img.src = getCustomLinkImage(customLink.path);
img.style.display = "block";
img.onerror = () => { img.src = "https://www.instructure.com/favicon.ico"; };
} else {
action.href = domain + "/courses/" + courseId + defaultLinks[i].path;
const layout = document.createElement("span");
layout.className = "ic-DashboardCard__action-layout";
layout.innerHTML = defaultLinks[i].icon;
action.appendChild(layout);
}
actions.appendChild(action);
}
card.appendChild(actions);
if (options.assignments_due === true) {
const assignmentsDiv = document.createElement("div");
assignmentsDiv.className = "canvasrefined-card-assignment";
assignmentsDiv.style.display = "block";
const headerContainer = document.createElement("div");
headerContainer.className = "canvasrefined-card-header-container";
const header3 = document.createElement("h3");
header3.className = "canvasrefined-card-header";
header3.textContent = "Due";
headerContainer.appendChild(header3);
assignmentsDiv.appendChild(headerContainer);
const assignmentsContainer = document.createElement("div");
assignmentsContainer.className = "canvasrefined-card-container";
assignmentsContainer.dataset.courseId = courseId;
const assignmentInner = document.createElement("div");
assignmentInner.className = "canvasrefined-assignment-container";
const noneLink = document.createElement("a");
noneLink.className = "canvasrefined-assignment-link";
noneLink.textContent = "None";
assignmentInner.appendChild(noneLink);
assignmentsContainer.appendChild(assignmentInner);
assignmentsDiv.appendChild(assignmentsContainer);
card.appendChild(assignmentsDiv);
}
v2Container.appendChild(card);
});
loadV2Assignments();
loadV2Grades();
moveGPACardToV2();
chrome.storage.sync.get("v2_card_order", (result) => {
if (result.v2_card_order && result.v2_card_order.length > 0) {
const order = result.v2_card_order;
const cardMap = {};
v2Container.querySelectorAll(".canvasrefined-v2-card, .canvasrefined-gpa-card").forEach(card => {
cardMap[card.dataset.courseId] = card;
});
order.forEach(id => {
if (cardMap[id]) {
v2Container.appendChild(cardMap[id]);
if (id === "gpa") {
const gpaEdit = document.querySelector(".canvasrefined-gpa");
if (gpaEdit) v2Container.appendChild(gpaEdit);
}
}
});
}
});
}
function loadV2Grades() {
if (!options.dashboard_grades || !grades) return;
grades.then(data => {
document.querySelectorAll(".canvasrefined-v2-card").forEach(card => {
const courseId = card.dataset.courseId;
const gradeLink = card.querySelector(".canvasrefined-card-grade");
if (!gradeLink) return;
data.forEach(course => {
if (parseInt(courseId) === course.id) {
const score = course.enrollments[0].has_grading_periods
? course.enrollments[0].current_period_computed_current_score
: course.enrollments[0].computed_current_score;
gradeLink.textContent = (score || "--") + "%";
}
});
});
});
}
function loadV2Assignments() {
if (!options.assignments_due || !cardAssignments) return;
const now = new Date();
cardAssignments.then(els => {
document.querySelectorAll(".canvasrefined-v2-card").forEach(card => {
const courseId = card.dataset.courseId;
const container = card.querySelector(".canvasrefined-card-container");
if (!container) return;
container.innerHTML = "";
if (els[courseId]) {
let count = 0;
els[courseId].forEach(assignment => {
if (count >= options.num_assignments) return;
if (options.card_overdues !== true && now >= assignment.due) return;
if (assignment.submitted === true) return;
if (assignment.type !== "assignment" && assignment.type !== "quiz" && assignment.type !== "discussion_topic") return;
if (assignment.override === true) return;
const row = document.createElement("div");
row.className = "canvasrefined-assignment-container";
const linkEl = document.createElement("a");
linkEl.className = "canvasrefined-assignment-link";
linkEl.href = assignment.el.querySelector(".canvasrefined-assignment-link").href;
linkEl.textContent = assignment.el.querySelector(".canvasrefined-assignment-link").textContent;
linkEl.target = "_blank";
row.appendChild(linkEl);
const dueSpan = document.createElement("span");
dueSpan.className = "canvasrefined-assignment-dueat";
dueSpan.textContent = assignment.el.querySelector(".canvasrefined-assignment-dueat").textContent;
row.appendChild(dueSpan);
container.appendChild(row);
count++;
});
}
if (container.children.length === 0) {
const row = document.createElement("div");
row.className = "canvasrefined-assignment-container";
const link = document.createElement("a");
link.className = "canvasrefined-assignment-link";
link.textContent = "None";
row.appendChild(link);
container.appendChild(row);
}
});
});
}
function moveGPACardToV2() {
const v2Container = document.querySelector("#canvasrefined-v2-container");
const gpaCard = document.querySelector(".canvasrefined-gpa-card");
const gpaEdit = document.querySelector(".canvasrefined-gpa");
if (!v2Container || !gpaCard) return;
if (gpaCard.parentElement === v2Container) return;
gpaCard.dataset.courseId = "gpa";
gpaCard.dataset.widgetType = "gpa";
if (gpaEdit) {
gpaEdit.dataset.courseId = "gpa";
gpaEdit.dataset.widgetType = "gpa";
v2Container.appendChild(gpaCard);
v2Container.appendChild(gpaEdit);
} else {
v2Container.appendChild(gpaCard);
}
}
function moveGPACardOutOfV2() {
const dashboardContainer = document.querySelector("#DashboardCard_Container");
const gpaCard = document.querySelector(".canvasrefined-gpa-card");
const gpaEdit = document.querySelector(".canvasrefined-gpa");
if (!dashboardContainer || !gpaCard) return;
gpaCard.removeAttribute("draggable");
gpaCard.removeAttribute("data-testid");
gpaCard.removeAttribute("aria-label");
delete gpaCard.dataset.courseId;
delete gpaCard.dataset.widgetType;
if (options.gpa_calc_prepend === true) {
dashboardContainer.prepend(gpaCard);
if (gpaEdit) dashboardContainer.prepend(gpaEdit);
} else {
dashboardContainer.appendChild(gpaCard);
if (gpaEdit) dashboardContainer.appendChild(gpaEdit);
}
}
function saveV2CardOrder() {
const v2Container = document.querySelector("#canvasrefined-v2-container");
if (!v2Container) return;
const order = [];
v2Container.querySelectorAll(".canvasrefined-v2-card, .canvasrefined-gpa-card").forEach(c => {
order.push(c.dataset.courseId);
});
chrome.storage.sync.set({ "v2_card_order": order });
}
function removeDashboardV2() {
const dashboardContainer = document.querySelector("#DashboardCard_Container");
if (dashboardContainer) dashboardContainer.classList.remove("canvasrefined-v2-active");
const v2Container = document.querySelector("#canvasrefined-v2-container");
if (v2Container) v2Container.remove();
const originalCards = document.querySelector(".ic-DashboardCard__box__container");
if (originalCards) originalCards.style.display = "";
}
function isDashboardV2Active() {
return options.dashboard_v2 === true;
}
function logError(e) { function logError(e) {
chrome.storage.local.get("errors", storage => { chrome.storage.local.get("errors", storage => {
if (storage.errors.length > 20) { if (storage.errors.length > 20) {

View File

@ -1,4 +1,4 @@
const syncedSwitches = ['remind', 'tab_icons', 'hide_feedback', 'dark_mode', 'remlogo', 'full_width', 'auto_dark', 'assignments_due', 'gpa_calc', 'gradient_cards', 'disable_color_overlay', 'dashboard_grades', 'dashboard_notes', 'better_todo', 'better_sidebar', 'condensed_cards', 'widget_clock']; const syncedSwitches = ['remind', 'tab_icons', 'hide_feedback', 'dark_mode', 'remlogo', 'full_width', 'auto_dark', 'assignments_due', 'gpa_calc', 'gradient_cards', 'disable_color_overlay', 'dashboard_grades', 'dashboard_notes', 'better_todo', 'better_sidebar', 'condensed_cards', 'widget_clock', 'dashboard_v2'];
const syncedSubOptions = [ const syncedSubOptions = [
"todo_hide_feedback", "todo_hide_feedback",
"todo_full_height", "todo_full_height",
@ -6,6 +6,8 @@ const syncedSubOptions = [
"device_dark", "device_dark",
"relative_dues", "relative_dues",
"card_overdues", "card_overdues",
"v2_limit_assignments",
"v2_truncate_names",
// "todo_overdues", // "todo_overdues",
"gpa_calc_prepend", "gpa_calc_prepend",
"auto_dark", "auto_dark",
@ -130,10 +132,12 @@ const defaultOptions = {
"cardSpacing": 0, "cardSpacing": 0,
"cardWidth": 262, "cardWidth": 262,
"cardHeight": 250, "cardHeight": 250,
"customCardStyles": false, "customCardStyles": false,
"customBackgroundLink": "", "customBackgroundLink": "",
"customBackgroundScale": 100, "customBackgroundScale": 100,
"widget_clock": false, "widget_clock": false,
"v2_limit_assignments": true,
"v2_truncate_names": false,
} }
}; };
@ -379,6 +383,8 @@ function setup() {
"hover_preview", "hover_preview",
// "scheduledReminder", // "scheduledReminder",
"customCardStyles", "customCardStyles",
"v2_limit_assignments",
"v2_truncate_names",
], ],
tabs: { tabs: {
"advanced-settings": { "advanced-settings": {
@ -410,6 +416,10 @@ function setup() {
setup: displayErrors, setup: displayErrors,
tab: ".report-issue-container", tab: ".report-issue-container",
}, },
"experimental-btn": {
setup: null,
tab: ".experimental",
},
"updates-btn": { setup: null, tab: ".updates-container" }, "updates-btn": { setup: null, tab: ".updates-container" },
}, },
special: [ special: [