feat: new settings popup

This commit is contained in:
2026-07-24 10:08:03 +09:30
parent b5347e2732
commit 928f05ec8e
12 changed files with 662 additions and 354 deletions
@@ -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();
+18 -8
View File
@@ -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);