diff --git a/src/css/injected.scss b/src/css/injected.scss index 11bc6e5c..bbace617 100644 --- a/src/css/injected.scss +++ b/src/css/injected.scss @@ -1469,6 +1469,35 @@ html.transparencyEffects color: var(--text-primary) !important; 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 { background: transparent !important; overflow: hidden; diff --git a/src/resources/update-video.webm b/src/resources/update-video.webm index e4f8dc9c..1bde0bc5 100644 Binary files a/src/resources/update-video.webm and b/src/resources/update-video.webm differ diff --git a/src/seqta/ui/sidebar/mountCustomSidebar.ts b/src/seqta/ui/sidebar/mountCustomSidebar.ts index 156e6e46..442fcd26 100644 --- a/src/seqta/ui/sidebar/mountCustomSidebar.ts +++ b/src/seqta/ui/sidebar/mountCustomSidebar.ts @@ -128,8 +128,8 @@ function onCustomSidebarCaptureClick(event: MouseEvent) { } const key = li.dataset.key; - if (!key) return; - const item = sidebarState.findByKey(key); + const path = li.dataset.path; + const item = sidebarState.resolveItem(key, path); if (item) sidebarState.activateItem(item, menuEl); } diff --git a/src/seqta/ui/sidebar/parseNativeMenu.test.ts b/src/seqta/ui/sidebar/parseNativeMenu.test.ts index 45f1ba3c..62462a20 100644 --- a/src/seqta/ui/sidebar/parseNativeMenu.test.ts +++ b/src/seqta/ui/sidebar/parseNativeMenu.test.ts @@ -1,7 +1,11 @@ /** * @jest-environment jsdom */ -import { getPagePathFromHash, parseNativeMenu } from "./parseNativeMenu"; +import { + findNativeMenuEntry, + getPagePathFromHash, + parseNativeMenu, +} from "./parseNativeMenu"; describe("parseNativeMenu", () => { it("parses top-level items and nested folders", () => { @@ -67,4 +71,46 @@ describe("parseNativeMenu", () => { expect(items.map((i) => i.key)).toEqual(["home"]); }); + + it("findNativeMenuEntry prefers path over duplicate data-key", () => { + document.body.innerHTML = ` + + `; + + 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"); + }); }); diff --git a/src/seqta/ui/sidebar/parseNativeMenu.ts b/src/seqta/ui/sidebar/parseNativeMenu.ts index c05be243..2ce6369c 100644 --- a/src/seqta/ui/sidebar/parseNativeMenu.ts +++ b/src/seqta/ui/sidebar/parseNativeMenu.ts @@ -97,13 +97,6 @@ export function findNativeMenuEntry( 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) { const byPath = list.querySelector( `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 (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) { const candidates = list.querySelectorAll( "li.item, section.item", diff --git a/src/seqta/ui/sidebar/sidebarState.svelte.ts b/src/seqta/ui/sidebar/sidebarState.svelte.ts index 2ef81965..565170fb 100644 --- a/src/seqta/ui/sidebar/sidebarState.svelte.ts +++ b/src/seqta/ui/sidebar/sidebarState.svelte.ts @@ -105,7 +105,7 @@ export function clearNativeDrillActive(menu: HTMLElement) { .forEach((node) => node.classList.remove("active")); } -function findItemByPath( +export function findItemByPath( items: SidebarItem[], path: string, ): SidebarItem | null { @@ -119,14 +119,14 @@ function findItemByPath( return null; } -function findItemByKey( +function findItemByKeyInList( items: SidebarItem[], key: string, ): SidebarItem | null { for (const item of items) { if (item.key === key) return item; if (item.children.length) { - const nested = findItemByKey(item.children, key); + const nested = findItemByKeyInList(item.children, key); if (nested) return nested; } } @@ -383,7 +383,24 @@ class SidebarState { } 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; } } diff --git a/src/seqta/utils/Openers/whatsNewChangelog.ts b/src/seqta/utils/Openers/whatsNewChangelog.ts index 20b61f7a..ac67bb63 100644 --- a/src/seqta/utils/Openers/whatsNewChangelog.ts +++ b/src/seqta/utils/Openers/whatsNewChangelog.ts @@ -5,8 +5,9 @@ export type 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": [ + "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 a new sidebar customisation page in the settings menu to change the sidebar layout, icons, and more.", "Added extension feedback in settings.", diff --git a/src/test/jest.setup.ts b/src/test/jest.setup.ts index ab105650..57630f1b 100644 --- a/src/test/jest.setup.ts +++ b/src/test/jest.setup.ts @@ -1,5 +1,16 @@ 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(() => { __resetBrowserStorageMock(); });