mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-08-28 17:21:05 +00:00
refactor(sidebar): analytics start below courses
This commit is contained in:
+7
-33
@@ -2794,39 +2794,9 @@ body {
|
||||
.defaultWelcomeWrapper {
|
||||
background: unset !important;
|
||||
}
|
||||
.clr-swatches button::after,
|
||||
.clr-dark .clr-preview::after,
|
||||
.clr-field button::after {
|
||||
opacity: unset;
|
||||
padding-top: unset;
|
||||
-webkit-transform: unset;
|
||||
transform: unset;
|
||||
-webkit-transform-origin: unset;
|
||||
transform-origin: unset;
|
||||
visibility: unset;
|
||||
-webkit-animation-name: unset !important;
|
||||
animation-name: unset !important;
|
||||
background-color: currentColor !important;
|
||||
}
|
||||
.clr-swatches button {
|
||||
align-items: unset;
|
||||
display: block;
|
||||
padding: unset;
|
||||
transition: none;
|
||||
}
|
||||
.clr-clear {
|
||||
display: none !important;
|
||||
}
|
||||
.clr-preview::before,
|
||||
.clr-preview::after {
|
||||
visibility: unset;
|
||||
-webkit-transform-origin: unset;
|
||||
transform-origin: unset;
|
||||
-webkit-transform: unset;
|
||||
transform: unset;
|
||||
padding-top: unset;
|
||||
opacity: unset;
|
||||
}
|
||||
|
||||
/* Coloris (timetable subject colours): cosmetic only — do not unset
|
||||
transforms/animations on ::after (breaks picker reopen). */
|
||||
#clr-color-preview {
|
||||
margin: 15px 0 20px 20px;
|
||||
border: 0;
|
||||
@@ -2835,6 +2805,10 @@ body {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clr-swatches button {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dark
|
||||
[class*="MessageList__MessageList___"]
|
||||
> ol
|
||||
|
||||
@@ -2,8 +2,14 @@ import type { Plugin } from "@/plugins/core/types";
|
||||
import MenuitemSVGKey from "@/seqta/content/MenuItemSVGKey.json";
|
||||
import { waitForElm } from "@/seqta/utils/waitForElm";
|
||||
import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
|
||||
import { processMenuItemNode } from "@/seqta/utils/sidebarMenuIcons";
|
||||
import {
|
||||
ChangeMenuItemPositions,
|
||||
ensureAnalyticsMenuOrder,
|
||||
insertMenuItemAfterKey,
|
||||
processMenuItemNode,
|
||||
} from "@/seqta/utils/sidebarMenuIcons";
|
||||
import { MenuOptionsOpen } from "@/seqta/utils/Openers/OpenMenuOptions";
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||
import {
|
||||
applyMenuItemVisibility,
|
||||
isMenuItemHidden,
|
||||
@@ -45,11 +51,14 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
|
||||
analyticsItem.dataset.betterseqta = "true";
|
||||
analyticsItem.innerHTML = `<label>${ANALYTICS_MENU_ICON}<span>Analytics</span></label>`;
|
||||
|
||||
const homeButton = document.getElementById("homebutton");
|
||||
if (homeButton?.parentElement === menuList) {
|
||||
homeButton.insertAdjacentElement("afterend", analyticsItem);
|
||||
} else {
|
||||
menuList.insertBefore(analyticsItem, menuList.firstChild);
|
||||
const placeAnalyticsItem = () => {
|
||||
insertMenuItemAfterKey(menuList, analyticsItem, "courses");
|
||||
};
|
||||
|
||||
placeAnalyticsItem();
|
||||
ensureAnalyticsMenuOrder();
|
||||
if (settingsState.menuorder.length > 0) {
|
||||
ChangeMenuItemPositions(settingsState.menuorder);
|
||||
}
|
||||
|
||||
processMenuItemNode(analyticsItem);
|
||||
@@ -59,10 +68,10 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
|
||||
if (MenuOptionsOpen) return;
|
||||
if (isMenuItemHidden("analytics")) return;
|
||||
if (!menuList.contains(analyticsItem)) {
|
||||
if (homeButton?.parentElement === menuList) {
|
||||
homeButton.insertAdjacentElement("afterend", analyticsItem);
|
||||
} else {
|
||||
menuList.insertBefore(analyticsItem, menuList.firstChild);
|
||||
placeAnalyticsItem();
|
||||
ensureAnalyticsMenuOrder();
|
||||
if (settingsState.menuorder.length > 0) {
|
||||
ChangeMenuItemPositions(settingsState.menuorder);
|
||||
}
|
||||
processMenuItemNode(analyticsItem);
|
||||
applyMenuItemVisibility();
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||
import type { Plugin } from "../../core/types";
|
||||
import { convertTo12HourFormat } from "@/seqta/utils/convertTo12HourFormat";
|
||||
import {
|
||||
attachTimetableColorisRecovery,
|
||||
resetStuckColorisPicker,
|
||||
} from "@/seqta/utils/timetableColoris";
|
||||
import { waitForElm } from "@/seqta/utils/waitForElm";
|
||||
|
||||
const timetablePlugin: Plugin<{}, {}> = {
|
||||
@@ -63,6 +66,9 @@ function resetTimetableStyles(): void {
|
||||
}
|
||||
|
||||
async function handleTimetable(): Promise<void> {
|
||||
attachTimetableColorisRecovery();
|
||||
resetStuckColorisPicker();
|
||||
|
||||
// SEQTA uses `.times` blocks on entries, not necessarily `.time`; avoid infinite polling on a missing selector.
|
||||
try {
|
||||
await waitForElm(".timetablepage .times, .timetablepage .entry.class", true, 50, 200);
|
||||
|
||||
@@ -30,6 +30,7 @@ import { loadAnalyticsPage } from "@/plugins/built-in/gradeAnalytics/loadAnalyti
|
||||
import { runStartupPopupQueue } from "@/seqta/utils/Openers/StartupPopupQueue";
|
||||
|
||||
import { updateTimetableTimes } from "@/seqta/utils/updateTimetableTimes";
|
||||
import { attachTimetableColorisRecovery } from "@/seqta/utils/timetableColoris";
|
||||
|
||||
// JSON content
|
||||
import { observeMenuItemPosition } from "@/seqta/utils/sidebarMenuIcons";
|
||||
@@ -247,6 +248,7 @@ async function LoadPageElements(): Promise<void> {
|
||||
className: "timetablepage",
|
||||
},
|
||||
async () => {
|
||||
attachTimetableColorisRecovery();
|
||||
await updateTimetableTimes();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { SettingsState } from "@/types/storage";
|
||||
import { settingsState } from "../listeners/SettingsState";
|
||||
import { applyMenuItemVisibility } from "../menuItemVisibility";
|
||||
import { insertKeyAfterInOrder } from "@/seqta/utils/sidebarMenuIcons";
|
||||
import stringToHTML from "../stringToHTML";
|
||||
import Sortable from "sortablejs";
|
||||
|
||||
@@ -57,9 +58,18 @@ export function OpenMenuOptions() {
|
||||
key &&
|
||||
settingsState.defaultmenuorder.indexOf(key) === -1
|
||||
) {
|
||||
let newdefaultmenuorder = settingsState.defaultmenuorder;
|
||||
newdefaultmenuorder.push(key);
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder;
|
||||
if (key === "analytics") {
|
||||
settingsState.defaultmenuorder = insertKeyAfterInOrder(
|
||||
settingsState.defaultmenuorder,
|
||||
key,
|
||||
"courses",
|
||||
);
|
||||
} else {
|
||||
settingsState.defaultmenuorder = [
|
||||
...settingsState.defaultmenuorder,
|
||||
key,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,58 @@ import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
|
||||
|
||||
const BETTERSEQTA_ICON_ATTR = "data-betterseqta-icon";
|
||||
|
||||
export function insertMenuItemAfterKey(
|
||||
menuList: HTMLElement,
|
||||
item: HTMLElement,
|
||||
afterKey: string,
|
||||
): void {
|
||||
const after = menuList.querySelector(
|
||||
`:scope > li[data-key="${afterKey}"], :scope > section[data-key="${afterKey}"]`,
|
||||
);
|
||||
if (after instanceof HTMLElement) {
|
||||
after.insertAdjacentElement("afterend", item);
|
||||
} else {
|
||||
menuList.appendChild(item);
|
||||
}
|
||||
}
|
||||
|
||||
export function insertKeyAfterInOrder(
|
||||
order: string[],
|
||||
key: string,
|
||||
afterKey: string,
|
||||
): string[] {
|
||||
if (order.includes(key)) return order;
|
||||
const copy = [...order];
|
||||
const afterIdx = copy.indexOf(afterKey);
|
||||
if (afterIdx >= 0) {
|
||||
copy.splice(afterIdx + 1, 0, key);
|
||||
} else {
|
||||
copy.push(key);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Default Analytics immediately below Courses in saved menu order. */
|
||||
export function ensureAnalyticsMenuOrder(): void {
|
||||
if (!settingsState.defaultmenuorder.includes("analytics")) {
|
||||
settingsState.defaultmenuorder = insertKeyAfterInOrder(
|
||||
settingsState.defaultmenuorder,
|
||||
"analytics",
|
||||
"courses",
|
||||
);
|
||||
}
|
||||
if (
|
||||
settingsState.menuorder.length > 0 &&
|
||||
!settingsState.menuorder.includes("analytics")
|
||||
) {
|
||||
settingsState.menuorder = insertKeyAfterInOrder(
|
||||
settingsState.menuorder,
|
||||
"analytics",
|
||||
"courses",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getMenuLabel(element: HTMLElement): HTMLElement | null {
|
||||
const label = element.querySelector(":scope > label");
|
||||
return label instanceof HTMLElement ? label : null;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* SEQTA timetable uses Coloris for subject colours. Extension CSS previously
|
||||
* unset Coloris ::after animations, which left the picker unable to reopen.
|
||||
* This module clears stuck `clr-open` / hidden picker state after each use.
|
||||
*/
|
||||
|
||||
let attached = false;
|
||||
|
||||
export function resetStuckColorisPicker(): void {
|
||||
document.body.classList.remove("clr-open");
|
||||
document.documentElement.classList.remove("clr-open");
|
||||
|
||||
for (const picker of document.querySelectorAll(".clr-picker")) {
|
||||
picker.classList.remove("clr-open");
|
||||
if (picker instanceof HTMLElement) {
|
||||
picker.style.removeProperty("display");
|
||||
picker.style.removeProperty("pointer-events");
|
||||
picker.style.removeProperty("visibility");
|
||||
}
|
||||
}
|
||||
|
||||
for (const field of document.querySelectorAll(".clr-field")) {
|
||||
field.classList.remove("clr-open");
|
||||
}
|
||||
}
|
||||
|
||||
export function attachTimetableColorisRecovery(): void {
|
||||
if (attached) return;
|
||||
attached = true;
|
||||
|
||||
const afterColorisEvent = () => {
|
||||
requestAnimationFrame(() => resetStuckColorisPicker());
|
||||
};
|
||||
|
||||
document.addEventListener("coloris:pick", afterColorisEvent);
|
||||
document.addEventListener("coloris:close", afterColorisEvent);
|
||||
|
||||
document.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
if (!target.closest(".timetablepage [title='Choose a colour']")) return;
|
||||
resetStuckColorisPicker();
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user