feat: simplify startup popups and convert engage announcement to toast

Remove auto-showing privacy statement and BS Cloud announcement from
startup queue. Convert SEQTA Engage announcement from a blocking modal
to a subtle bottom-right dismissable toast.
This commit is contained in:
SethBurkart123
2026-04-20 14:59:24 +10:00
parent f9406fb469
commit 87ba75ff41
3 changed files with 87 additions and 72 deletions
+38
View File
@@ -4371,3 +4371,41 @@ h2.home-subtitle {
font-size: 20px; font-size: 20px;
font-weight: 400; font-weight: 400;
} }
.bsplus-toast {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 10000;
display: flex;
align-items: flex-start;
gap: 12px;
max-width: 380px;
padding: 16px 18px;
border-radius: 12px;
background: var(--background-secondary, #fff);
color: var(--text-primary, #1a1a1a);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.18);
font-size: 0.9rem;
line-height: 1.5;
}
.bsplus-toast-content p {
margin: 6px 0 0;
opacity: 0.8;
font-size: 0.85rem;
}
.bsplus-toast-close {
flex-shrink: 0;
background: none;
border: none;
color: var(--text-primary, #1a1a1a);
font-size: 1.3rem;
cursor: pointer;
padding: 0 2px;
line-height: 1;
opacity: 0.5;
transition: opacity 0.15s;
}
.bsplus-toast-close:hover {
opacity: 1;
}
@@ -1,61 +1,54 @@
import stringToHTML from "../stringToHTML";
import { settingsState } from "../listeners/SettingsState"; import { settingsState } from "../listeners/SettingsState";
import { openPopup } from "./PopupManager"; import { animate as motionAnimate } from "motion";
import { attachPopupMediaFullscreenIfPresent } from "./attachPopupMediaFullscreen";
/** Same hosting pattern as the privacy statement branding images (avoids page-relative extension URLs on Engage). */
const ENGAGE_PROMO_IMG_URL =
"https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/bq%2Bengage.png";
export function shouldShowEngageParentsAnnouncement(): boolean { export function shouldShowEngageParentsAnnouncement(): boolean {
return !settingsState.engageParentsAnnouncementShown; return !settingsState.engageParentsAnnouncementShown;
} }
/** /**
* One-time announcement that BetterSEQTA Plus works on SEQTA Engage (parents). * Non-blocking bottom-right toast announcing SEQTA Engage support. Shown once.
*/ */
export function showEngageParentsAnnouncement(onDismissed?: () => void) { export function showEngageParentsToast() {
if (document.getElementById("whatsnewbk")) { if (!shouldShowEngageParentsAnnouncement()) return;
onDismissed?.();
return;
}
if (!shouldShowEngageParentsAnnouncement()) {
onDismissed?.();
return;
}
const header = stringToHTML(
/* html */
`<div class="whatsnewHeader engageParentsAnnouncementHeader">
<h1>BetterSEQTA Plus now supports <span class="seqtaEngageAccent">SEQTA Engage</span></h1>
<p class="engageParentsSubheading">Buy your mom a BetterSEQTA Plus</p>
</div>`,
).firstChild as HTMLElement;
const text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer privacyStatement" style="overflow-y: auto; font-size: 1.2rem; line-height: 1.6;">
<div class="engageParentsPromoWrap">
<img class="engageParentsPromoImg" src="${ENGAGE_PROMO_IMG_URL}" width="1920" height="1080" alt="BetterSEQTA Plus now supports SEQTA Engage" />
</div>
<p>
BetterSEQTA Plus now supports <strong class="seqtaEngageAccent">SEQTA Engage</strong>, so parents get the same kinds of improvements you are used to on SEQTA Learn—themes, a clearer home experience, and other Plus polish while browsing Engage.
</p>
<p>
The title is a bit of fun; if the extension saves you time, you can always support development via Open Collective or Ko-fi from the What is New changelog or related links in settings.
</p>
<p>
Close this dialog when you are done. We will not show this announcement again.
</p>
</div>
`).firstChild as HTMLElement;
attachPopupMediaFullscreenIfPresent(text, ".engageParentsPromoImg");
settingsState.engageParentsAnnouncementShown = true; settingsState.engageParentsAnnouncementShown = true;
openPopup({ const toast = document.createElement("div");
header, toast.className = "bsplus-toast";
content: [text], toast.innerHTML = /* html */ `
afterClose: onDismissed, <div class="bsplus-toast-content">
}); <strong>BetterSEQTA+ now supports <span class="seqtaEngageAccent">SEQTA Engage</span></strong>
<p>Buy your mum a BetterSEQTA Plus! Parents now get themes, a cleaner home page, and all the Plus polish on SEQTA Engage.</p>
</div>
<button class="bsplus-toast-close" aria-label="Dismiss">&times;</button>
`;
toast.style.opacity = "0";
document.getElementById("container")?.append(toast);
if (settingsState.animations) {
(motionAnimate as any)(
toast,
{ opacity: [0, 1], y: [40, 0] },
{ duration: 0.35, easing: [0.22, 0.03, 0.26, 1] },
);
} else {
toast.style.opacity = "1";
}
const dismiss = () => {
if (settingsState.animations) {
(motionAnimate as any)(
toast,
{ opacity: [1, 0], y: [0, 40] },
{ duration: 0.2, easing: [0.22, 0.03, 0.26, 1] },
).then(() => toast.remove());
} else {
toast.remove();
}
};
toast.querySelector(".bsplus-toast-close")!.addEventListener("click", dismiss);
setTimeout(dismiss, 10000);
} }
+7 -23
View File
@@ -1,24 +1,15 @@
import { settingsState } from "../listeners/SettingsState"; import { settingsState } from "../listeners/SettingsState";
import { OpenWhatsNewPopup } from "./OpenWhatsNewPopup"; import { OpenWhatsNewPopup } from "./OpenWhatsNewPopup";
import {
shouldShowPrivacyNotification,
showPrivacyNotification,
} from "./OpenPrivacyNotification";
import { import {
shouldShowEngageParentsAnnouncement, shouldShowEngageParentsAnnouncement,
showEngageParentsAnnouncement, showEngageParentsToast,
} from "./OpenEngageParentsAnnouncement"; } from "./OpenEngageParentsAnnouncement";
import {
shouldShowBsCloudAutoSyncAnnouncement,
showBsCloudAutoSyncAnnouncement,
} from "./OpenBsCloudAutoSyncAnnouncement";
type QueueStep = (goNext: () => void) => void; type QueueStep = (goNext: () => void) => void;
/** /**
* Runs startup modals in order: What's New (if the extension just updated), * Runs startup modals in order: What's New (if the extension just updated),
* privacy statement (if required), SEQTA Engage announcement (once), then BS Cloud * then shows the SEQTA Engage toast (once, non-blocking).
* auto-sync (once, last).
*/ */
export function runStartupPopupQueue() { export function runStartupPopupQueue() {
const steps: QueueStep[] = []; const steps: QueueStep[] = [];
@@ -27,21 +18,14 @@ export function runStartupPopupQueue() {
steps.push((goNext) => OpenWhatsNewPopup(goNext)); steps.push((goNext) => OpenWhatsNewPopup(goNext));
} }
if (shouldShowPrivacyNotification()) {
steps.push((goNext) => showPrivacyNotification(goNext));
}
if (shouldShowEngageParentsAnnouncement()) {
steps.push((goNext) => showEngageParentsAnnouncement(goNext));
}
if (shouldShowBsCloudAutoSyncAnnouncement()) {
steps.push((goNext) => showBsCloudAutoSyncAnnouncement(goNext));
}
function runNext() { function runNext() {
const step = steps.shift(); const step = steps.shift();
if (step) step(runNext); if (step) step(runNext);
else {
if (shouldShowEngageParentsAnnouncement()) {
showEngageParentsToast();
}
}
} }
runNext(); runNext();