From eb49e8d7f12ccea2b8ea9a88ce3edf7ebbbd21c8 Mon Sep 17 00:00:00 2001 From: StroepWafel Date: Mon, 25 May 2026 13:26:33 +0930 Subject: [PATCH 1/8] fix up TOTM --- src/background.ts | 36 +++++++ src/css/injected.scss | 94 +++++++++++++++++-- src/interface/pages/settings/general.svelte | 11 +++ .../utils/Openers/OpenThemeOfTheMonthPopup.ts | 37 +++++++- 4 files changed, 166 insertions(+), 12 deletions(-) diff --git a/src/background.ts b/src/background.ts index b98b5514..c25caa9b 100644 --- a/src/background.ts +++ b/src/background.ts @@ -551,6 +551,41 @@ async function migrateGlobalSearchDefaultsFor365Upgrade( } } +/** One-time reset for 3.6.6: re-enable Theme of the Month for existing users. */ +const THEME_OF_THE_MONTH_RESET_VERSION = "3.6.6"; + +async function resetThemeOfTheMonthDisabledFor366Upgrade( + previousVersion: string, +): Promise { + try { + const currRaw = browser.runtime.getManifest().version; + const prev = semver.coerce(previousVersion); + const curr = semver.coerce(currRaw); + if ( + prev == null || + curr == null || + semver.lt(curr, THEME_OF_THE_MONTH_RESET_VERSION) || + !semver.lt(prev, THEME_OF_THE_MONTH_RESET_VERSION) + ) { + return; + } + + await browser.storage.local.set({ + themeOfTheMonthDisabled: false, + themeOfTheMonthLastSeenId: undefined, + }); + + console.info( + `[BetterSEQTA+] Migration ${THEME_OF_THE_MONTH_RESET_VERSION}: Theme of the Month re-enabled (from ${previousVersion}).`, + ); + } catch (e) { + console.warn( + "[BetterSEQTA+] Theme of the Month 3.6.6 reset migration failed:", + e, + ); + } +} + browser.runtime.onInstalled.addListener(function (event) { browser.storage.local.remove(["justupdated"]); browser.storage.local.remove(["data"]); @@ -561,6 +596,7 @@ browser.runtime.onInstalled.addListener(function (event) { if (event.reason === "update" && event.previousVersion) { void migrateGlobalSearchDefaultsFor365Upgrade(event.previousVersion); + void resetThemeOfTheMonthDisabledFor366Upgrade(event.previousVersion); } }); diff --git a/src/css/injected.scss b/src/css/injected.scss index 57f7fc64..22d0f211 100644 --- a/src/css/injected.scss +++ b/src/css/injected.scss @@ -3753,20 +3753,98 @@ div.day-empty { pointer-events: none; animation: themeOfTheMonthCardOut 0.18s ease-in forwards; } -.themeOfTheMonthCardClose { +.themeOfTheMonthCardDisable { position: absolute !important; - top: 4px !important; - right: 4px !important; - z-index: 2; - width: 32px; - height: 32px; + top: 6px !important; + right: 6px !important; + z-index: 3; + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + padding: 0 !important; border: 1px solid rgba(255, 255, 255, 0.22); - border-radius: 16px !important; + border-radius: 9px !important; background: rgba(0, 0, 0, 0.42); color: white; cursor: pointer; - font-size: 1.35rem; + font-size: 0.78rem; line-height: 1; + opacity: 0.75; + transition: opacity 0.15s ease, transform 0.15s ease, background 0.15s ease; +} +.themeOfTheMonthCardDisable:hover { + opacity: 1; + transform: scale(1.08); + background: rgba(0, 0, 0, 0.6); +} +.themeOfTheMonthCardConfirm { + position: absolute; + inset: 0; + z-index: 4; + display: flex; + align-items: center; + justify-content: center; + padding: 16px; + border-radius: inherit; + background: color-mix(in srgb, var(--background-primary) 88%, transparent); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + opacity: 0; + transition: opacity 0.16s ease; +} +.themeOfTheMonthCardConfirmVisible { + opacity: 1; +} +.themeOfTheMonthCardConfirmInner { + width: 100%; + text-align: center; +} +.themeOfTheMonthCardConfirmInner h3 { + margin: 0 0 6px; + font-size: 1rem; + line-height: 1.2; +} +.themeOfTheMonthCardConfirmInner p { + margin: 0 0 14px; + font-size: 0.86rem; + line-height: 1.4; + color: color-mix(in srgb, var(--text-primary) 78%, transparent); +} +.themeOfTheMonthCardConfirmActions { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px; +} +.themeOfTheMonthCardConfirmCancel, +.themeOfTheMonthCardConfirmAccept { + appearance: none; + border: none; + cursor: pointer; + border-radius: 9999px; + padding: 0.5rem 0.85rem; + font-size: 0.84rem; + font-weight: 700; + transition: transform 0.15s ease, filter 0.15s ease, background 0.15s ease; +} +.themeOfTheMonthCardConfirmCancel { + background: color-mix(in srgb, var(--text-primary) 10%, transparent); + color: var(--text-primary); +} +.themeOfTheMonthCardConfirmAccept { + background: var(--better-pri, #6366f1); + color: white; +} +.themeOfTheMonthCardConfirmCancel:hover, +.themeOfTheMonthCardConfirmAccept:hover { + filter: brightness(1.08); + transform: translateY(-1px); +} +.themeOfTheMonthCardConfirmCancel:active, +.themeOfTheMonthCardConfirmAccept:active { + transform: translateY(0); } .themeOfTheMonthCardImage { display: block; diff --git a/src/interface/pages/settings/general.svelte b/src/interface/pages/settings/general.svelte index 7bc7ecc9..1bb59313 100644 --- a/src/interface/pages/settings/general.svelte +++ b/src/interface/pages/settings/general.svelte @@ -458,6 +458,17 @@ } })} + {@render Setting({ + title: "Theme of the Month", + description: "Show the monthly featured theme popup when a new entry is available", + id: 15, + Component: Switch, + props: { + state: !($settingsState.themeOfTheMonthDisabled ?? false), + onChange: (isOn: boolean) => settingsState.themeOfTheMonthDisabled = !isOn + } + })} + {#if $settingsState.devMode}
diff --git a/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts b/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts index aaf6348a..c6a609ac 100644 --- a/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts +++ b/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts @@ -143,7 +143,7 @@ export async function OpenThemeOfTheMonthPopup( const card = stringToHTML(/* html */ `
+
+ @@ -177,7 +187,9 @@ export async function OpenThemeOfTheMonthPopup( card.addEventListener("mouseenter", () => window.clearTimeout(autoCloseTimeout), { once: true }); - card.querySelector(".themeOfTheMonthCardClose")?.addEventListener("click", () => { + const confirmEl = card.querySelector(".themeOfTheMonthCardConfirm"); + + card.querySelector(".themeOfTheMonthCardSecondary")?.addEventListener("click", () => { dismiss(); }); @@ -186,7 +198,24 @@ export async function OpenThemeOfTheMonthPopup( openThemeStoreWithHighlight(linkedThemeId!); }); - card.querySelector(".themeOfTheMonthCardSecondary")?.addEventListener("click", () => { + card.querySelector(".themeOfTheMonthCardDisable")?.addEventListener("click", () => { + window.clearTimeout(autoCloseTimeout); + if (confirmEl) { + confirmEl.hidden = false; + // allow CSS transition by toggling on next frame + requestAnimationFrame(() => confirmEl.classList.add("themeOfTheMonthCardConfirmVisible")); + } + }); + + card.querySelector(".themeOfTheMonthCardConfirmCancel")?.addEventListener("click", () => { + if (!confirmEl) return; + confirmEl.classList.remove("themeOfTheMonthCardConfirmVisible"); + window.setTimeout(() => { + confirmEl.hidden = true; + }, 160); + }); + + card.querySelector(".themeOfTheMonthCardConfirmAccept")?.addEventListener("click", () => { settingsState.themeOfTheMonthDisabled = true; dismiss(); }); From 7a3cbb50cc50437cbb0f4c84ddebee8e33c6dc5e Mon Sep 17 00:00:00 2001 From: StroepWafel Date: Mon, 25 May 2026 13:49:46 +0930 Subject: [PATCH 2/8] fix style --- src/css/injected.scss | 40 ++++++++++++++------- src/interface/pages/settings/general.svelte | 23 ++++++------ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/css/injected.scss b/src/css/injected.scss index 22d0f211..00d7f356 100644 --- a/src/css/injected.scss +++ b/src/css/injected.scss @@ -3757,27 +3757,36 @@ div.day-empty { position: absolute !important; top: 6px !important; right: 6px !important; - z-index: 3; - display: flex; - align-items: center; - justify-content: center; - width: 18px; - height: 18px; + z-index: 3 !important; + box-sizing: border-box !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 18px !important; + height: 18px !important; + min-width: 0 !important; + min-height: 0 !important; + max-width: 18px !important; + max-height: 18px !important; + margin: 0 !important; padding: 0 !important; - border: 1px solid rgba(255, 255, 255, 0.22); + border: 1px solid rgba(255, 255, 255, 0.22) !important; border-radius: 9px !important; - background: rgba(0, 0, 0, 0.42); - color: white; - cursor: pointer; - font-size: 0.78rem; - line-height: 1; + background: rgba(0, 0, 0, 0.42) !important; + color: white !important; + cursor: pointer !important; + font-family: inherit !important; + font-size: 12px !important; + font-weight: 600 !important; + line-height: 1 !important; + text-align: center !important; opacity: 0.75; transition: opacity 0.15s ease, transform 0.15s ease, background 0.15s ease; } .themeOfTheMonthCardDisable:hover { opacity: 1; transform: scale(1.08); - background: rgba(0, 0, 0, 0.6); + background: rgba(0, 0, 0, 0.6) !important; } .themeOfTheMonthCardConfirm { position: absolute; @@ -3792,10 +3801,15 @@ div.day-empty { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); opacity: 0; + pointer-events: none; transition: opacity 0.16s ease; } +.themeOfTheMonthCardConfirm[hidden] { + display: none; +} .themeOfTheMonthCardConfirmVisible { opacity: 1; + pointer-events: auto; } .themeOfTheMonthCardConfirmInner { width: 100%; diff --git a/src/interface/pages/settings/general.svelte b/src/interface/pages/settings/general.svelte index 1bb59313..6140c02f 100644 --- a/src/interface/pages/settings/general.svelte +++ b/src/interface/pages/settings/general.svelte @@ -423,6 +423,18 @@ {/each} {/if} + {#if plugin.pluginId === 'global-search'} + {@render Setting({ + title: "Theme of the Month", + description: "Show the monthly featured theme popup when a new entry is available", + id: 15, + Component: Switch, + props: { + state: !($settingsState.themeOfTheMonthDisabled ?? false), + onChange: (isOn: boolean) => settingsState.themeOfTheMonthDisabled = !isOn + } + })} + {/if} {/each} @@ -458,17 +470,6 @@ } })} - {@render Setting({ - title: "Theme of the Month", - description: "Show the monthly featured theme popup when a new entry is available", - id: 15, - Component: Switch, - props: { - state: !($settingsState.themeOfTheMonthDisabled ?? false), - onChange: (isOn: boolean) => settingsState.themeOfTheMonthDisabled = !isOn - } - })} - {#if $settingsState.devMode}
From e8d1dadfa72d97debc9dfa8c98f09721fbb07a3e Mon Sep 17 00:00:00 2001 From: StroepWafel <109832156+StroepWafel@users.noreply.github.com> Date: Thu, 28 May 2026 15:16:43 +0930 Subject: [PATCH 3/8] Update OpenWhatsNewPopup.ts --- src/seqta/utils/Openers/OpenWhatsNewPopup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/seqta/utils/Openers/OpenWhatsNewPopup.ts b/src/seqta/utils/Openers/OpenWhatsNewPopup.ts index 8b068f05..b066d886 100644 --- a/src/seqta/utils/Openers/OpenWhatsNewPopup.ts +++ b/src/seqta/utils/Openers/OpenWhatsNewPopup.ts @@ -34,7 +34,7 @@ export function OpenWhatsNewPopup(onDismissed?: () => void) { const text = stringToHTML(/* html */ `
-

3.6.6 – Global Search improvements!

+

3.7.0 – Global Search improvements!

  • Tuned hybrid search and indexing reliability.
  • Clearer progress UI and green “Done!” when a pass finishes.
  • Merged duplicate course hits that opened the same page.
  • From 9f263c8c029d1bbd89339cb7f0febfb7316a579c Mon Sep 17 00:00:00 2001 From: StroepWafel <109832156+StroepWafel@users.noreply.github.com> Date: Thu, 28 May 2026 15:17:38 +0930 Subject: [PATCH 4/8] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f69f0865..9504b2fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "betterseqtaplus", - "version": "3.6.5", + "version": "3.7.0", "type": "module", "description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development and add heaps more features!", "browserslist": "> 0.5%, last 2 versions, not dead", From a23eda1162df24f7824db3709c8945ece3f5b5e7 Mon Sep 17 00:00:00 2001 From: StroepWafel Date: Fri, 29 May 2026 10:55:55 +0930 Subject: [PATCH 5/8] show TOTM popup until dismissed - forgotten commit i forgot to commit this basically just shows until dismissed even persistent over reloads so the user doesn't lose it the moment they navigate away or if they load the page and close it immediately --- src/background.ts | 36 +++++++++++++++++++ .../utils/Openers/OpenThemeOfTheMonthPopup.ts | 28 +++++---------- src/seqta/utils/Openers/StartupPopupQueue.ts | 2 +- src/types/storage.ts | 7 +++- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/background.ts b/src/background.ts index c25caa9b..074a4138 100644 --- a/src/background.ts +++ b/src/background.ts @@ -586,6 +586,41 @@ async function resetThemeOfTheMonthDisabledFor366Upgrade( } } +/** 3.7.0: Close no longer marks entries seen — clear legacy dismissal keys. */ +const THEME_OF_THE_MONTH_RELOAD_VERSION = "3.7.0"; + +async function resetThemeOfTheMonthDismissalFor370Upgrade( + previousVersion: string, +): Promise { + try { + const currRaw = browser.runtime.getManifest().version; + const prev = semver.coerce(previousVersion); + const curr = semver.coerce(currRaw); + if ( + prev == null || + curr == null || + semver.lt(curr, THEME_OF_THE_MONTH_RELOAD_VERSION) || + !semver.lt(prev, THEME_OF_THE_MONTH_RELOAD_VERSION) + ) { + return; + } + + await browser.storage.local.set({ + themeOfTheMonthLastSeenId: undefined, + themeOfTheMonthDismissedMonth: undefined, + }); + + console.info( + `[BetterSEQTA+] Migration ${THEME_OF_THE_MONTH_RELOAD_VERSION}: Theme of the Month shows again until dismissed for the month (from ${previousVersion}).`, + ); + } catch (e) { + console.warn( + "[BetterSEQTA+] Theme of the Month 3.7.0 dismissal migration failed:", + e, + ); + } +} + browser.runtime.onInstalled.addListener(function (event) { browser.storage.local.remove(["justupdated"]); browser.storage.local.remove(["data"]); @@ -597,6 +632,7 @@ browser.runtime.onInstalled.addListener(function (event) { if (event.reason === "update" && event.previousVersion) { void migrateGlobalSearchDefaultsFor365Upgrade(event.previousVersion); void resetThemeOfTheMonthDisabledFor366Upgrade(event.previousVersion); + void resetThemeOfTheMonthDismissalFor370Upgrade(event.previousVersion); } }); diff --git a/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts b/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts index c6a609ac..03ac2e0b 100644 --- a/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts +++ b/src/seqta/utils/Openers/OpenThemeOfTheMonthPopup.ts @@ -45,10 +45,10 @@ export async function fetchThemeOfTheMonth(): Promise void, - markSeen = true, -) { +function closeThemeOfTheMonthCard(card: HTMLElement, onDismissed?: () => void) { if (card.classList.contains("themeOfTheMonthCardClosing")) return; - if (markSeen) { - const entryId = card.dataset.entryId; - if (entryId) settingsState.themeOfTheMonthLastSeenId = entryId; - } - card.classList.add("themeOfTheMonthCardClosing"); window.setTimeout(() => { card.remove(); @@ -165,7 +156,7 @@ export async function OpenThemeOfTheMonthPopup(