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(); });