diff --git a/src/css/injected.scss b/src/css/injected.scss index 2e5f33cc..261552c2 100644 --- a/src/css/injected.scss +++ b/src/css/injected.scss @@ -4371,3 +4371,41 @@ h2.home-subtitle { font-size: 20px; 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; +} diff --git a/src/seqta/utils/Openers/OpenEngageParentsAnnouncement.ts b/src/seqta/utils/Openers/OpenEngageParentsAnnouncement.ts index a9f19b50..1cd72939 100644 --- a/src/seqta/utils/Openers/OpenEngageParentsAnnouncement.ts +++ b/src/seqta/utils/Openers/OpenEngageParentsAnnouncement.ts @@ -1,61 +1,54 @@ -import stringToHTML from "../stringToHTML"; import { settingsState } from "../listeners/SettingsState"; -import { openPopup } from "./PopupManager"; -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"; +import { animate as motionAnimate } from "motion"; export function shouldShowEngageParentsAnnouncement(): boolean { 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) { - if (document.getElementById("whatsnewbk")) { - onDismissed?.(); - return; - } - if (!shouldShowEngageParentsAnnouncement()) { - onDismissed?.(); - return; - } - - const header = stringToHTML( - /* html */ - `
-

BetterSEQTA Plus now supports SEQTA Engage

-

Buy your mom a BetterSEQTA Plus

-
`, - ).firstChild as HTMLElement; - - const text = stringToHTML(/* html */ ` -
-
- BetterSEQTA Plus now supports SEQTA Engage -
-

- BetterSEQTA Plus now supports SEQTA Engage, 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. -

-

- 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. -

-

- Close this dialog when you are done. We will not show this announcement again. -

-
- `).firstChild as HTMLElement; - - attachPopupMediaFullscreenIfPresent(text, ".engageParentsPromoImg"); +export function showEngageParentsToast() { + if (!shouldShowEngageParentsAnnouncement()) return; settingsState.engageParentsAnnouncementShown = true; - openPopup({ - header, - content: [text], - afterClose: onDismissed, - }); + const toast = document.createElement("div"); + toast.className = "bsplus-toast"; + toast.innerHTML = /* html */ ` +
+ BetterSEQTA+ now supports SEQTA Engage +

Buy your mum a BetterSEQTA Plus! Parents now get themes, a cleaner home page, and all the Plus polish on SEQTA Engage.

+
+ + `; + + 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); } diff --git a/src/seqta/utils/Openers/StartupPopupQueue.ts b/src/seqta/utils/Openers/StartupPopupQueue.ts index 3b05e88b..7bfa4e8a 100644 --- a/src/seqta/utils/Openers/StartupPopupQueue.ts +++ b/src/seqta/utils/Openers/StartupPopupQueue.ts @@ -1,24 +1,15 @@ import { settingsState } from "../listeners/SettingsState"; import { OpenWhatsNewPopup } from "./OpenWhatsNewPopup"; -import { - shouldShowPrivacyNotification, - showPrivacyNotification, -} from "./OpenPrivacyNotification"; import { shouldShowEngageParentsAnnouncement, - showEngageParentsAnnouncement, + showEngageParentsToast, } from "./OpenEngageParentsAnnouncement"; -import { - shouldShowBsCloudAutoSyncAnnouncement, - showBsCloudAutoSyncAnnouncement, -} from "./OpenBsCloudAutoSyncAnnouncement"; type QueueStep = (goNext: () => void) => void; /** * Runs startup modals in order: What's New (if the extension just updated), - * privacy statement (if required), SEQTA Engage announcement (once), then BS Cloud - * auto-sync (once, last). + * then shows the SEQTA Engage toast (once, non-blocking). */ export function runStartupPopupQueue() { const steps: QueueStep[] = []; @@ -27,21 +18,14 @@ export function runStartupPopupQueue() { 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() { const step = steps.shift(); if (step) step(runNext); + else { + if (shouldShowEngageParentsAnnouncement()) { + showEngageParentsToast(); + } + } } runNext();