mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-08-28 17:21:05 +00:00
feat: new settings popup
This commit is contained in:
@@ -440,22 +440,56 @@ async function addEngageUserInfo() {
|
||||
});
|
||||
}
|
||||
|
||||
async function setupEngageSettingsButton() {
|
||||
try {
|
||||
const notificationsWrapper = await waitForElm(
|
||||
"#content > div.connectedNotificationsWrapper > div",
|
||||
);
|
||||
const parent = notificationsWrapper.parentElement!;
|
||||
async function mountEngageToolbarControls(parent?: Element) {
|
||||
// React can remount the notifications chrome — recreate missing controls.
|
||||
if (!document.getElementById("LightDarkModeButton")) {
|
||||
await addDarkLightToggle(parent);
|
||||
await createSettingsButton(parent);
|
||||
setupSettingsButton();
|
||||
attachNotificationsPanelAnimation();
|
||||
} catch {
|
||||
await addDarkLightToggle();
|
||||
await createSettingsButton();
|
||||
setupSettingsButton();
|
||||
attachNotificationsPanelAnimation();
|
||||
}
|
||||
if (!document.getElementById("AddedSettings")) {
|
||||
await createSettingsButton(parent);
|
||||
}
|
||||
setupSettingsButton();
|
||||
attachNotificationsPanelAnimation();
|
||||
}
|
||||
|
||||
async function setupEngageSettingsButton() {
|
||||
let mounting = false;
|
||||
|
||||
const tryMount = async () => {
|
||||
if (mounting || document.getElementById("AddedSettings")) return;
|
||||
mounting = true;
|
||||
try {
|
||||
try {
|
||||
const notificationsWrapper = await waitForElm(
|
||||
"#content > div.connectedNotificationsWrapper > div",
|
||||
true,
|
||||
100,
|
||||
40,
|
||||
);
|
||||
const parent = notificationsWrapper.parentElement!;
|
||||
await mountEngageToolbarControls(parent);
|
||||
} catch {
|
||||
await mountEngageToolbarControls();
|
||||
}
|
||||
} finally {
|
||||
mounting = false;
|
||||
}
|
||||
};
|
||||
|
||||
await tryMount();
|
||||
|
||||
// Re-inject if Engage's React shell wipes the toolbar controls.
|
||||
const content = document.getElementById("content");
|
||||
if (!content || (content as HTMLElement).dataset.bsplusEngageSettingsWatch === "1") {
|
||||
return;
|
||||
}
|
||||
(content as HTMLElement).dataset.bsplusEngageSettingsWatch = "1";
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
if (document.getElementById("AddedSettings")) return;
|
||||
void tryMount();
|
||||
});
|
||||
observer.observe(content, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
function GetLightDarkModeString() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import debounce from "@/seqta/utils/debounce";
|
||||
|
||||
/**
|
||||
* Automatically resizes the popup to fit the screen, checks on resize but is debounced to prevent intense utilisation.
|
||||
* Keeps the settings overlay covering the viewport.
|
||||
*/
|
||||
export class SettingsResizer {
|
||||
constructor() {
|
||||
@@ -17,10 +17,10 @@ export class SettingsResizer {
|
||||
const iframePopup = document.getElementById("ExtensionPopup");
|
||||
if (!iframePopup) return;
|
||||
|
||||
const viewportHeight = window.innerHeight;
|
||||
const rawIdeal = viewportHeight - 80 - 15; // room below top chrome
|
||||
const idealHeight = Math.min(Math.max(rawIdeal, 280), 600);
|
||||
|
||||
iframePopup.style.height = `${idealHeight}px`;
|
||||
iframePopup.style.inset = "0";
|
||||
iframePopup.style.top = "0";
|
||||
iframePopup.style.right = "0";
|
||||
iframePopup.style.width = "100%";
|
||||
iframePopup.style.height = "100%";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ export async function renderStore() {
|
||||
import("@/interface/pages/store.svelte"),
|
||||
]);
|
||||
|
||||
const container = document.querySelector("#container");
|
||||
if (!container) {
|
||||
throw new Error("Container not found");
|
||||
}
|
||||
const container =
|
||||
document.querySelector("#container") ??
|
||||
document.getElementById("content") ??
|
||||
document.body;
|
||||
|
||||
document.getElementById("store")?.remove();
|
||||
|
||||
|
||||
@@ -13,12 +13,18 @@ function extensionOutsideClickHandler(extensionPopup: HTMLElement) {
|
||||
if (!SettingsClicked) return;
|
||||
|
||||
if (!(event.target as HTMLElement).closest("#AddedSettings")) {
|
||||
// Clicks inside the shadow tree retarget to the host — keep open.
|
||||
if (event.target == extensionPopup) return;
|
||||
changeSettingsClicked(closeExtensionPopup());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mount the settings host on `document.body` so `position: fixed` covers the
|
||||
* viewport on both SEQTA Learn and SEQTA Engage (Engage often lacks `#container`
|
||||
* or wraps the app in stacking contexts that clip in-app overlays).
|
||||
*/
|
||||
export function addExtensionSettings() {
|
||||
if (document.getElementById("ExtensionPopup")) return;
|
||||
|
||||
@@ -26,15 +32,12 @@ export function addExtensionSettings() {
|
||||
extensionPopup.classList.add("outside-container", "hide");
|
||||
extensionPopup.id = "ExtensionPopup";
|
||||
|
||||
const extensionContainer =
|
||||
document.querySelector("#container") ?? document.getElementById("container");
|
||||
const mountParent = extensionContainer ?? document.body;
|
||||
mountParent.appendChild(extensionPopup);
|
||||
document.body.appendChild(extensionPopup);
|
||||
|
||||
new SettingsResizer();
|
||||
|
||||
const handler = extensionOutsideClickHandler(extensionPopup);
|
||||
(extensionContainer ?? document.body).addEventListener("click", handler, false);
|
||||
document.body.addEventListener("click", handler, false);
|
||||
}
|
||||
|
||||
async function loadSettingsUi(extensionPopup: HTMLElement): Promise<void> {
|
||||
|
||||
@@ -14,7 +14,6 @@ export const closeExtensionPopup = (extensionPopup?: HTMLElement) => {
|
||||
animate(1, 0, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup.style.opacity = Math.max(0, progress).toString();
|
||||
extensionPopup.style.transform = `scale(${Math.max(0, progress)})`;
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 520,
|
||||
@@ -22,7 +21,6 @@ export const closeExtensionPopup = (extensionPopup?: HTMLElement) => {
|
||||
});
|
||||
} else {
|
||||
extensionPopup.style.opacity = "0";
|
||||
extensionPopup.style.transform = "scale(0)";
|
||||
}
|
||||
|
||||
settingsPopup.triggerClose();
|
||||
|
||||
@@ -10,22 +10,34 @@ import { delay } from "./delay";
|
||||
|
||||
export function setupSettingsButton() {
|
||||
const AddedSettings = document.getElementById("AddedSettings");
|
||||
const extensionPopup = document.getElementById("ExtensionPopup");
|
||||
if (!AddedSettings || !extensionPopup) return;
|
||||
if (!AddedSettings) return;
|
||||
|
||||
// Avoid stacking duplicate listeners if Engage remounts the toolbar.
|
||||
if (AddedSettings.dataset.bsplusSettingsBound === "1") return;
|
||||
AddedSettings.dataset.bsplusSettingsBound = "1";
|
||||
|
||||
AddedSettings.addEventListener("click", async () => {
|
||||
// Re-query each click — Engage SPA navigations can recreate the host.
|
||||
let extensionPopup = document.getElementById("ExtensionPopup");
|
||||
if (!extensionPopup) {
|
||||
const { addExtensionSettings } = await import("./Adders/AddExtensionSettings");
|
||||
addExtensionSettings();
|
||||
extensionPopup = document.getElementById("ExtensionPopup");
|
||||
}
|
||||
if (!extensionPopup) return;
|
||||
|
||||
if (SettingsClicked) {
|
||||
closeExtensionPopup(extensionPopup as HTMLElement);
|
||||
closeExtensionPopup(extensionPopup);
|
||||
} else {
|
||||
await renderSettingsIfNeeded();
|
||||
|
||||
await delay(30);
|
||||
|
||||
|
||||
extensionPopup.style.transform = "none";
|
||||
if (settingsState.animations) {
|
||||
animate(0, 1, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup.style.opacity = progress.toString();
|
||||
extensionPopup.style.transform = `scale(${progress})`;
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 280,
|
||||
@@ -33,9 +45,7 @@ export function setupSettingsButton() {
|
||||
});
|
||||
} else {
|
||||
extensionPopup.style.opacity = "1";
|
||||
extensionPopup.style.transform = "scale(1)";
|
||||
extensionPopup.style.transition =
|
||||
"opacity 0s linear, transform 0s linear";
|
||||
extensionPopup.style.transition = "opacity 0s linear";
|
||||
}
|
||||
extensionPopup.classList.remove("hide");
|
||||
changeSettingsClicked(true);
|
||||
|
||||
Reference in New Issue
Block a user