feat: refine settings, stores, and message folders

This commit is contained in:
SethBurkart123
2026-08-04 11:05:51 +10:00
parent defaf76144
commit ddbccecda2
33 changed files with 922 additions and 705 deletions
+7 -37
View File
@@ -1,39 +1,9 @@
import { unmount } from "svelte";
let remove: () => void;
export async function OpenStorePage(): Promise<void> {
remove = await renderStore();
}
export async function renderStore() {
const [{ default: renderSvelte }, { default: Store }] = await Promise.all([
import("@/interface/main"),
import("@/interface/pages/store.svelte"),
]);
const container =
document.querySelector("#container") ??
document.getElementById("content") ??
document.body;
document.getElementById("store")?.remove();
const child = document.createElement("div");
child.id = "store";
container.appendChild(child);
const shadow = child.attachShadow({ mode: "open" });
const app = renderSvelte(Store, shadow);
return () => unmount(app);
}
export function closeStore() {
document.getElementById("store")!.classList.add("hide");
setTimeout(() => {
remove();
document.getElementById("store")!.remove();
}, 500);
const [{ requestSettingsDestination }, { openSettingsPopup }] =
await Promise.all([
import("@/seqta/utils/settingsNavigation"),
import("@/seqta/utils/setupSettingsButton"),
]);
requestSettingsDestination({ page: "themes", view: "store" });
await openSettingsPopup();
}
@@ -52,7 +52,12 @@ async function loadSettingsUi(extensionPopup: HTMLElement): Promise<void> {
const mount = () => renderSvelte(Settings, shadow);
if ("requestIdleCallback" in window) {
requestIdleCallback(mount);
await new Promise<void>((resolve) => {
requestIdleCallback(() => {
mount();
resolve();
});
});
} else {
mount();
}
+12 -3
View File
@@ -11,14 +11,23 @@ export const closeExtensionPopup = (extensionPopup?: HTMLElement) => {
extensionPopup.classList.add("hide");
if (settingsState.animations) {
const panel = extensionPopup.shadowRoot?.querySelector<HTMLElement>(
"[data-settings-panel]",
);
animate(1, 0, {
onUpdate: (progress) => {
extensionPopup.style.opacity = Math.max(0, progress).toString();
},
type: "spring",
stiffness: 520,
damping: 20,
duration: 0.18,
ease: "easeIn",
});
if (panel) {
animate(
panel,
{ scale: [1, 0], opacity: [1, 0] },
{ duration: 0.18, ease: "easeIn" },
);
}
} else {
extensionPopup.style.opacity = "0";
}
@@ -311,10 +311,10 @@ export async function loadEngageHomePage(): Promise<void> {
const engageHomeBody = stringToHTML(/* html */ `
<div class="home-root" id="engage-home-root">
<div class="home-container" id="engage-home-container">
<div class="bsplus-rounded shortcut-container">
<div class="bsplus-rounded shortcuts" id="shortcuts"></div>
<div class="border shortcut-container">
<div class="border shortcuts" id="shortcuts"></div>
</div>
<div class="bsplus-rounded timetable-container">
<div class="border timetable-container">
<div class="home-subtitle">
<div class="engage-timetable-title-cluster">
<h2 id="engage-home-lesson-subtitle">Today's Lessons</h2>
@@ -331,7 +331,7 @@ export async function loadEngageHomePage(): Promise<void> {
</div>
<div class="day-container loading" id="engage-day-container"></div>
</div>
<div class="bsplus-rounded notices-container">
<div class="border notices-container">
<div style="display: flex; justify-content: space-between">
<h2 class="home-subtitle">Notices</h2>
<input type="date" id="engage-notices-date" />
+5 -5
View File
@@ -62,10 +62,10 @@ export async function loadHomePage() {
const skeletonStructure = stringToHTML(/* html */ `
<div class="home-container" id="home-container">
<div class="bsplus-rounded shortcut-container">
<div class="bsplus-rounded shortcuts" id="shortcuts"></div>
<div class="border shortcut-container">
<div class="border shortcuts" id="shortcuts"></div>
</div>
<div class="bsplus-rounded timetable-container">
<div class="border timetable-container">
<div class="home-subtitle">
<h2 id="home-lesson-subtitle">Today's Lessons</h2>
<div class="timetable-arrows">
@@ -80,7 +80,7 @@ export async function loadHomePage() {
<div class="day-container loading" id="day-container">
</div>
</div>
<div class="bsplus-rounded upcoming-container">
<div class="border upcoming-container">
<div class="upcoming-title">
<h2 class="home-subtitle">Upcoming Assessments</h2>
<div class="upcoming-filters" id="upcoming-filters"></div>
@@ -88,7 +88,7 @@ export async function loadHomePage() {
<div class="upcoming-items loading" id="upcoming-items">
</div>
</div>
<div class="bsplus-rounded notices-container">
<div class="border notices-container">
<div style="display: flex; justify-content: space-between">
<h2 class="home-subtitle">Notices</h2>
<input type="date" />
@@ -11,15 +11,9 @@ export function consumePendingHighlightThemeId(): string | null {
export async function openThemeStoreWithHighlight(themeId: string): Promise<void> {
pendingHighlightThemeId = themeId;
const existing = document.getElementById("store");
if (existing) {
window.dispatchEvent(
new CustomEvent("bsplus:highlight-theme", { detail: { themeId } }),
);
return;
}
const { OpenStorePage } = await import("@/seqta/ui/renderStore");
await OpenStorePage();
window.dispatchEvent(
new CustomEvent("bsplus:highlight-theme", { detail: { themeId } }),
);
}
+20
View File
@@ -0,0 +1,20 @@
export type SettingsDestination =
| { page: "settings"; section?: string }
| { page: "themes" | "backgrounds"; view?: "settings" | "store" };
export const SETTINGS_NAVIGATION_EVENT = "bsplus:navigate-settings";
let pendingDestination: SettingsDestination | null = null;
export function requestSettingsDestination(destination: SettingsDestination): void {
pendingDestination = destination;
window.dispatchEvent(
new CustomEvent(SETTINGS_NAVIGATION_EVENT, { detail: destination }),
);
}
export function consumeSettingsDestination(): SettingsDestination | null {
const destination = pendingDestination;
pendingDestination = null;
return destination;
}
+49 -30
View File
@@ -17,38 +17,57 @@ export function setupSettingsButton() {
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);
closeExtensionPopup();
} else {
await renderSettingsIfNeeded();
await delay(30);
extensionPopup.style.transform = "none";
if (settingsState.animations) {
animate(0, 1, {
onUpdate: (progress) => {
extensionPopup.style.opacity = progress.toString();
},
type: "spring",
stiffness: 280,
damping: 20,
});
} else {
extensionPopup.style.opacity = "1";
extensionPopup.style.transition = "opacity 0s linear";
}
extensionPopup.classList.remove("hide");
changeSettingsClicked(true);
await openSettingsPopup();
}
});
}
export async function openSettingsPopup(): Promise<void> {
if (SettingsClicked && document.getElementById("ExtensionPopup")) return;
// Re-query each time — 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;
await renderSettingsIfNeeded();
await delay(30);
extensionPopup.style.transform = "none";
const panel = extensionPopup.shadowRoot?.querySelector<HTMLElement>(
"[data-settings-panel]",
);
if (settingsState.animations) {
animate(0, 1, {
onUpdate: (progress) => {
extensionPopup.style.opacity = progress.toString();
},
type: "spring",
stiffness: 280,
damping: 20,
});
if (panel) {
animate(
panel,
{ scale: [0, 1], opacity: [0, 1] },
{ type: "spring", stiffness: 330, damping: 30 },
);
}
} else {
extensionPopup.style.opacity = "1";
extensionPopup.style.transition = "opacity 0s linear";
if (panel) {
panel.style.scale = "1";
panel.style.opacity = "1";
}
}
extensionPopup.classList.remove("hide");
changeSettingsClicked(true);
}