feat: final fixes and chores

This commit is contained in:
2026-08-19 17:44:53 +09:30
parent 835620fd67
commit c2ddd67021
8 changed files with 119 additions and 15 deletions
+29
View File
@@ -1469,6 +1469,35 @@ html.transparencyEffects
color: var(--text-primary) !important; color: var(--text-primary) !important;
box-shadow: none; box-shadow: none;
} }
// Engage lesson/course Lexical editor ships inline light-mode colours on canvas + text nodes.
[class*="Canvas__canvas___"] {
background-color: transparent !important;
background-image: none !important;
color: var(--text-primary) !important;
}
[class*="LexicalEditor__editor-container___"],
[class*="LexicalEditor__editor-inner___"],
[class*="LexicalEditor__editor-input___"],
[class*="LexicalEditor__editor-paragraph___"],
[class*="LexicalEditor__editor-text-bold___"],
[class*="LexicalEditor__editor-text-italic___"],
[class*="LexicalEditor__editor-text-underline___"],
[class*="TextModuleBody__lexicalEditor___"] {
color: var(--text-primary) !important;
}
[class*="Module__module___"],
[class*="Module__content___"] {
background: transparent !important;
color: inherit !important;
}
.dark [class*="LexicalEditor__editor-input___"] img[data-lexical-decorator] {
filter: invert(1) hue-rotate(180deg);
}
.course .composer { .course .composer {
background: transparent !important; background: transparent !important;
overflow: hidden; overflow: hidden;
Binary file not shown.
+2 -2
View File
@@ -128,8 +128,8 @@ function onCustomSidebarCaptureClick(event: MouseEvent) {
} }
const key = li.dataset.key; const key = li.dataset.key;
if (!key) return; const path = li.dataset.path;
const item = sidebarState.findByKey(key); const item = sidebarState.resolveItem(key, path);
if (item) sidebarState.activateItem(item, menuEl); if (item) sidebarState.activateItem(item, menuEl);
} }
+47 -1
View File
@@ -1,7 +1,11 @@
/** /**
* @jest-environment jsdom * @jest-environment jsdom
*/ */
import { getPagePathFromHash, parseNativeMenu } from "./parseNativeMenu"; import {
findNativeMenuEntry,
getPagePathFromHash,
parseNativeMenu,
} from "./parseNativeMenu";
describe("parseNativeMenu", () => { describe("parseNativeMenu", () => {
it("parses top-level items and nested folders", () => { it("parses top-level items and nested folders", () => {
@@ -67,4 +71,46 @@ describe("parseNativeMenu", () => {
expect(items.map((i) => i.key)).toEqual(["home"]); expect(items.map((i) => i.key)).toEqual(["home"]);
}); });
it("findNativeMenuEntry prefers path over duplicate data-key", () => {
document.body.innerHTML = `
<div id="menu">
<ul>
<li class="item hasChildren" data-key="courses" data-path="/courses">
<label>Courses</label>
<div class="sub"><ul>
<li class="item hasChildren" data-key="4804:11066">
<label>English</label>
<div class="sub"><ul>
<li class="item" data-key="4804:11066" data-path="/courses/4804:11066">
<label>Course</label>
</li>
<li class="item" data-key="4804:11066" data-path="/assessments/4804:11066">
<label>Assessments</label>
</li>
</ul></div>
</li>
</ul></div>
</li>
</ul>
</div>
`;
const menu = document.getElementById("menu")!;
const course = findNativeMenuEntry(menu, {
key: "4804:11066",
id: null,
path: "/courses/4804:11066",
label: "Course",
});
const assessments = findNativeMenuEntry(menu, {
key: "4804:11066",
id: null,
path: "/assessments/4804:11066",
label: "Assessments",
});
expect(course?.dataset.path).toBe("/courses/4804:11066");
expect(assessments?.dataset.path).toBe("/assessments/4804:11066");
});
}); });
+7 -7
View File
@@ -97,13 +97,6 @@ export function findNativeMenuEntry(
if (byId instanceof HTMLElement) return byId; if (byId instanceof HTMLElement) return byId;
} }
if (item.key) {
const byKey = list.querySelector(
`li[data-key="${CSS.escape(item.key)}"], section[data-key="${CSS.escape(item.key)}"]`,
);
if (byKey instanceof HTMLElement) return byKey;
}
if (item.path) { if (item.path) {
const byPath = list.querySelector( const byPath = list.querySelector(
`li[data-path="${CSS.escape(item.path)}"], section[data-path="${CSS.escape(item.path)}"]`, `li[data-path="${CSS.escape(item.path)}"], section[data-path="${CSS.escape(item.path)}"]`,
@@ -111,6 +104,13 @@ export function findNativeMenuEntry(
if (byPath instanceof HTMLElement) return byPath; if (byPath instanceof HTMLElement) return byPath;
} }
if (item.key) {
const byKey = list.querySelector(
`li[data-key="${CSS.escape(item.key)}"], section[data-key="${CSS.escape(item.key)}"]`,
);
if (byKey instanceof HTMLElement) return byKey;
}
if (item.label) { if (item.label) {
const candidates = list.querySelectorAll<HTMLElement>( const candidates = list.querySelectorAll<HTMLElement>(
"li.item, section.item", "li.item, section.item",
+21 -4
View File
@@ -105,7 +105,7 @@ export function clearNativeDrillActive(menu: HTMLElement) {
.forEach((node) => node.classList.remove("active")); .forEach((node) => node.classList.remove("active"));
} }
function findItemByPath( export function findItemByPath(
items: SidebarItem[], items: SidebarItem[],
path: string, path: string,
): SidebarItem | null { ): SidebarItem | null {
@@ -119,14 +119,14 @@ function findItemByPath(
return null; return null;
} }
function findItemByKey( function findItemByKeyInList(
items: SidebarItem[], items: SidebarItem[],
key: string, key: string,
): SidebarItem | null { ): SidebarItem | null {
for (const item of items) { for (const item of items) {
if (item.key === key) return item; if (item.key === key) return item;
if (item.children.length) { if (item.children.length) {
const nested = findItemByKey(item.children, key); const nested = findItemByKeyInList(item.children, key);
if (nested) return nested; if (nested) return nested;
} }
} }
@@ -383,7 +383,24 @@ class SidebarState {
} }
findByKey(key: string) { findByKey(key: string) {
return findItemByKey(this.items, key); for (let i = this.drillStack.length - 1; i >= 0; i--) {
const hit = this.drillStack[i].items.find((item) => item.key === key);
if (hit) return hit;
}
return findItemByKeyInList(this.items, key);
}
findByPath(path: string) {
return findItemByPath(this.items, path);
}
resolveItem(key: string | undefined, path: string | undefined) {
if (path) {
const byPath = this.findByPath(path);
if (byPath) return byPath;
}
if (key) return this.findByKey(key);
return null;
} }
} }
+2 -1
View File
@@ -5,8 +5,9 @@ export type WhatsNewRelease = {
export const WHATS_NEW_CHANGELOG: WhatsNewRelease[] = [ export const WHATS_NEW_CHANGELOG: WhatsNewRelease[] = [
{ {
"title": "3.7.3 Timetable sync into Calendars, Sidebar Customisation & Bugfix Bundle", "title": "3.7.3 Timetable sync into Calendars, Sidebar Customisation, new loading animations & Bugfix Bundle",
"items": [ "items": [
"Added a few new loading screens you will see when opening SEQTA with BetterSEQTA",
"Added an option in the Timetable to sync to Google Calendar and Outlook Calendar", "Added an option in the Timetable to sync to Google Calendar and Outlook Calendar",
"Added a new sidebar customisation page in the settings menu to change the sidebar layout, icons, and more.", "Added a new sidebar customisation page in the settings menu to change the sidebar layout, icons, and more.",
"Added extension feedback in settings.", "Added extension feedback in settings.",
+11
View File
@@ -1,5 +1,16 @@
import { __resetBrowserStorageMock } from "./mocks/webextension-polyfill"; import { __resetBrowserStorageMock } from "./mocks/webextension-polyfill";
if (typeof globalThis.CSS === "undefined") {
Object.defineProperty(globalThis, "CSS", {
value: {
escape(value: string) {
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
},
},
writable: true,
});
}
afterEach(() => { afterEach(() => {
__resetBrowserStorageMock(); __resetBrowserStorageMock();
}); });