mirror of
https://github.com/GuySandler/CanvasRefined.git
synced 2026-09-19 12:04:54 +02:00
more list mode compatibility
This commit is contained in:
parent
6aa50259e4
commit
b859108ac8
@ -389,3 +389,19 @@
|
||||
#grades_summary td.details { white-space: normal; }
|
||||
#assignments { overflow-x: auto; }
|
||||
|
||||
|
||||
/* Big strikethrough on checked-off tasks (dashboard list view). Canvas keeps
|
||||
completed planner items looking identical to unfinished ones — the only cue
|
||||
is the checkbox itself — so when a task's checkbox is checked, strike its
|
||||
title through with a thick line and dim the row. :has() matches the
|
||||
checkbox state reactively, so this also applies live at the moment a task
|
||||
is checked, before Canvas collapses it into the completed-items section. */
|
||||
.planner-item:has(input[data-testid="planner-item-completed-checkbox"]:checked) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.planner-item:has(input[data-testid="planner-item-completed-checkbox"]:checked) .PlannerItem-styles__details a,
|
||||
.planner-item:has(input[data-testid="planner-item-completed-checkbox"]:checked) .PlannerItem-styles__title a,
|
||||
.planner-item:has(input[data-testid="planner-item-completed-checkbox"]:checked) .PlannerItem-styles__title button {
|
||||
text-decoration: line-through !important;
|
||||
text-decoration-thickness: 2.5px !important;
|
||||
}
|
||||
|
||||
@ -1207,4 +1207,33 @@ hr {
|
||||
color-scheme: dark !important;
|
||||
color: var(--bctext-0) !important;
|
||||
}
|
||||
/* Dashboard list view header (Today / Add To Do / Show My Grades /
|
||||
opportunities): Canvas paints the icon glyphs a dark ink color that
|
||||
disappears on the dark glass header bar. Recolor the header text and
|
||||
its icon SVGs to the theme text color. */
|
||||
.PlannerHeader-styles__root {
|
||||
color: var(--bctext-0) !important;
|
||||
}
|
||||
.PlannerHeader-styles__root svg {
|
||||
fill: var(--bctext-0) !important;
|
||||
}
|
||||
/* Flash alert toasts (.flashalert-message, e.g. "Nothing planned today.
|
||||
Selecting next item."): Canvas renders them as white cards with dark
|
||||
text, unthemed in dark mode. Paint them with the theme background and
|
||||
text color; the inner div[open] is the alert card itself. The close X
|
||||
glyph inherits currentColor from the button. */
|
||||
.flashalert-message > div {
|
||||
background: var(--bcbackground-0) !important;
|
||||
color: var(--bctext-0) !important;
|
||||
border-color: var(--bcborders) !important;
|
||||
}
|
||||
.flashalert-message > div p {
|
||||
color: var(--bctext-0) !important;
|
||||
}
|
||||
.flashalert-message > div button {
|
||||
color: var(--bctext-0) !important;
|
||||
}
|
||||
.flashalert-message > div button svg {
|
||||
fill: var(--bctext-0) !important;
|
||||
}
|
||||
`;
|
||||
126
js/content.js
126
js/content.js
@ -1505,7 +1505,7 @@ function recieveMessage(request, sender, sendResponse) {
|
||||
}
|
||||
return true; // keep the message channel open for async sendResponse
|
||||
case ("setcolors"): changeColorPreset(request.options); sendResponse(true); break;
|
||||
case ("getcolors"): sendResponse(getCardColors()); break;
|
||||
case ("getcolors"): getCardColors().then(colors => sendResponse(colors)); return true; // keep the message channel open for async sendResponse
|
||||
case ("inspect"): sendResponse(inspectDarkMode(true)); break;
|
||||
case ("fixdm"): sendResponse(runDarkModeFixer(true)); break;
|
||||
case ("updateBackground"): applyCustomBackground(); sendResponse(true); break;
|
||||
@ -1577,16 +1577,15 @@ function inspectDarkMode(withOutput = false) {
|
||||
return { "selectors": output === "" ? "no gaps determined" : output, "time": performance.now() - time };
|
||||
}
|
||||
|
||||
function getCardColors() {
|
||||
let cards = document.querySelectorAll(".ic-DashboardCard__header");
|
||||
let colors = [];
|
||||
cards.forEach(card => {
|
||||
let rgbColor = card.querySelector(".ic-DashboardCard__header_hero").style.backgroundColor;
|
||||
colors.push({ "href": card.querySelector(".ic-DashboardCard__link").href, "color": rgbToHex(rgbColor) });
|
||||
});
|
||||
colors.sort((a, b) => a.href > b.href ? 1 : -1);
|
||||
colors = colors.map(x => x.color);
|
||||
return colors;
|
||||
async function getCardColors() {
|
||||
// Same display order changeColorPreset uses to APPLY palettes, so an
|
||||
// exported theme's color list maps back onto the same courses when
|
||||
// applied. Works in list mode too (API fallback inside getPaletteCards).
|
||||
const { cards, apiColors } = await getPaletteCards();
|
||||
if (cards.length === 0) return [];
|
||||
return cards.map(card => card.el
|
||||
? rgbToHex(card.el.querySelector(".ic-DashboardCard__header_hero").style.backgroundColor)
|
||||
: (apiColors["course_" + card.href.split("courses/")[1]] || "#ffffff"));
|
||||
}
|
||||
|
||||
function getCardsFromDashboard() {
|
||||
@ -4339,6 +4338,48 @@ Card color palettes
|
||||
|
||||
let changeColorInterval = null;
|
||||
let colorChanges = [];
|
||||
|
||||
// Course list for palette operations, in DISPLAY order (first shown to
|
||||
// last) so palette colors land on courses in the order the user sees them.
|
||||
// Card view: dashboard cards are already in the DOM in display order.
|
||||
// List mode: there are no .ic-DashboardCard elements (which used to make the
|
||||
// palette silently do nothing), so fall back to the dashboard_cards API —
|
||||
// ordered by where each course's planner grouping first appears top-to-
|
||||
// bottom, with any courses not currently displayed (no items in the loaded
|
||||
// date range) at the end in API order. Also returns the user's current
|
||||
// course colors from the users/self/colors API (used for "revert colors"
|
||||
// when no DOM cards exist to read inline styles from).
|
||||
async function getPaletteCards() {
|
||||
let cards = [];
|
||||
let apiColors = {};
|
||||
document.querySelectorAll(".ic-DashboardCard__header").forEach(card => {
|
||||
cards.push({ "href": card.querySelector(".ic-DashboardCard__link").href, "el": card });
|
||||
});
|
||||
if (cards.length > 0) return { cards, apiColors };
|
||||
try {
|
||||
const [cardsRes, colorsRes] = await Promise.all([
|
||||
fetch(domain + "/api/v1/dashboard/dashboard_cards", { headers: { "accept": "application/json" } }),
|
||||
fetch(domain + "/api/v1/users/self/colors", { headers: { "accept": "application/json" } })
|
||||
]);
|
||||
const apiCards = await cardsRes.json();
|
||||
apiColors = (await colorsRes.json())?.custom_colors || {};
|
||||
const seen = new Set();
|
||||
const orderedIds = [];
|
||||
document.querySelectorAll("a.Grouping-styles__hero").forEach(hero => {
|
||||
const m = (hero.getAttribute("href") || "").match(/\/courses\/(\d+)/);
|
||||
if (m && !seen.has(m[1])) { seen.add(m[1]); orderedIds.push(m[1]); }
|
||||
});
|
||||
apiCards.forEach(card => {
|
||||
const id = String(card.id);
|
||||
if (!seen.has(id)) { seen.add(id); orderedIds.push(id); }
|
||||
});
|
||||
orderedIds.forEach(id => cards.push({ "href": domain + "/courses/" + id, "el": null }));
|
||||
} catch (e) {
|
||||
logError(e);
|
||||
}
|
||||
return { cards, apiColors };
|
||||
}
|
||||
|
||||
async function changeColorPreset(colors) {
|
||||
|
||||
if (colors.length === 0) return;
|
||||
@ -4352,26 +4393,45 @@ async function changeColorPreset(colors) {
|
||||
colorChanges = [];
|
||||
|
||||
// sort cards
|
||||
let cards = document.querySelectorAll(".ic-DashboardCard__header");
|
||||
let sortedCards = [];
|
||||
cards.forEach(card => {
|
||||
sortedCards.push({ "href": card.querySelector(".ic-DashboardCard__link").href, "el": card });
|
||||
});
|
||||
sortedCards.sort((a, b) => a.href > b.href ? 1 : -1);
|
||||
// (display order — see getPaletteCards; no re-sorting here so palette
|
||||
// colors apply from the first course on screen to the last)
|
||||
const { cards: sortedCards, apiColors } = await getPaletteCards();
|
||||
|
||||
// push each color change into a queue
|
||||
try {
|
||||
sortedCards.forEach((card, i) => {
|
||||
let previousColor = rgbToHex(card.el.querySelector(".ic-DashboardCard__header_hero").style.backgroundColor);
|
||||
let course_id = card.href.split("courses/")[1];
|
||||
let previousColor = card.el
|
||||
? rgbToHex(card.el.querySelector(".ic-DashboardCard__header_hero").style.backgroundColor)
|
||||
: (apiColors["course_" + course_id] || "#ffffff");
|
||||
previous.push(previousColor);
|
||||
|
||||
// Object.keys(res.custom_colors).forEach(item => {
|
||||
//let item_id = item.split("_")[1];
|
||||
let course_id = card.href.split("courses/")[1];
|
||||
|
||||
//if (card.href.includes(item_id)) {
|
||||
let cnum = i % colors.length;
|
||||
|
||||
// Apply the new color to whatever surface is rendered: dashboard
|
||||
// card elements (card view) or planner item avatars (list view),
|
||||
// so the change is visible immediately instead of only after a
|
||||
// reload.
|
||||
let applyColor = () => {
|
||||
if (card.el) {
|
||||
card.el.querySelector(".ic-DashboardCard__header_hero").style.backgroundColor = colors[cnum];
|
||||
card.el.querySelector(".ic-DashboardCard__header-title span").style.color = colors[cnum];
|
||||
card.el.querySelector(".ic-DashboardCard__header-button-bg").style.backgroundColor = colors[cnum];
|
||||
} else {
|
||||
const coursePrefix = "/courses/" + course_id;
|
||||
document.querySelectorAll(".planner-item").forEach(item => {
|
||||
const titleLink = item.querySelector(".PlannerItem-styles__title a");
|
||||
const heroLink = item.closest(".Grouping-styles__root")?.querySelector("a.Grouping-styles__hero");
|
||||
const inCourse = (titleLink && (titleLink.getAttribute("href") || "").startsWith(coursePrefix)) ||
|
||||
(heroLink && (heroLink.getAttribute("href") || "").startsWith(coursePrefix));
|
||||
if (inCourse) {
|
||||
const avatar = item.querySelector(".PlannerItem-styles__avatar, .PlannerItem-styles__icon");
|
||||
if (avatar) avatar.style.color = colors[cnum];
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let changeCardColor = () => {
|
||||
fetch(domain + "/api/v1/users/self/colors/courses_" + course_id,
|
||||
{
|
||||
@ -4382,20 +4442,12 @@ async function changeColorPreset(colors) {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body: JSON.stringify({ "hexcode": colors[cnum] })
|
||||
}).then(() => {
|
||||
card.el.querySelector(".ic-DashboardCard__header_hero").style.backgroundColor = colors[cnum];
|
||||
card.el.querySelector(".ic-DashboardCard__header-title span").style.color = colors[cnum];
|
||||
card.el.querySelector(".ic-DashboardCard__header-button-bg").style.backgroundColor = colors[cnum];
|
||||
});
|
||||
}).then(() => applyColor());
|
||||
}
|
||||
|
||||
colorChanges.push(changeCardColor);
|
||||
|
||||
card.el.querySelector(".ic-DashboardCard__header_hero").style.backgroundColor = colors[cnum];
|
||||
card.el.querySelector(".ic-DashboardCard__header-title span").style.color = colors[cnum];
|
||||
card.el.querySelector(".ic-DashboardCard__header-button-bg").style.backgroundColor = colors[cnum];
|
||||
//}
|
||||
// });
|
||||
applyColor();
|
||||
});
|
||||
} catch (e) {
|
||||
logError(e);
|
||||
@ -4417,7 +4469,13 @@ async function changeColorPreset(colors) {
|
||||
// set colors to revert back to
|
||||
chrome.storage.local.get("previous_colors", local => {
|
||||
const now = Date.now();
|
||||
if (local["previous_colors"] === null || now >= local["previous_colors"].expire) {
|
||||
const prev = local["previous_colors"];
|
||||
// Overwrite when missing or expired — and when an old list-mode run
|
||||
// (which found no dashboard cards) stored an empty list, which made
|
||||
// revert a silent no-op. Never store an empty capture (nothing to
|
||||
// revert to). chrome.storage.local.get yields undefined (not null)
|
||||
// for an unset key, so the old `=== null` check never matched it.
|
||||
if (previous.length > 0 && (!prev || now >= prev.expire || !Array.isArray(prev.colors) || prev.colors.length === 0)) {
|
||||
chrome.storage.local.set({ "previous_colors": { "colors": previous, "expire": now + 86400000 } });
|
||||
}
|
||||
});
|
||||
|
||||
@ -1388,8 +1388,11 @@ function setup() {
|
||||
// activate revert to original card colors button
|
||||
document.querySelector("#revert-colors").addEventListener("click", () => {
|
||||
chrome.storage.local.get("previous_colors", local => {
|
||||
if (local["previous_colors"] !== null) {
|
||||
sendFromPopup("setcolors", local["previous_colors"].colors);
|
||||
const prev = local["previous_colors"];
|
||||
// Guard against unset/expired-shape entries and the empty lists
|
||||
// old list-mode runs stored — sending [] would be a silent no-op.
|
||||
if (prev && Array.isArray(prev.colors) && prev.colors.length > 0) {
|
||||
sendFromPopup("setcolors", prev.colors);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user