fix up TOTM

This commit is contained in:
2026-05-25 13:26:33 +09:30
parent 65cd0a1c4f
commit eb49e8d7f1
4 changed files with 166 additions and 12 deletions
+36
View File
@@ -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<void> {
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.runtime.onInstalled.addListener(function (event) {
browser.storage.local.remove(["justupdated"]); browser.storage.local.remove(["justupdated"]);
browser.storage.local.remove(["data"]); browser.storage.local.remove(["data"]);
@@ -561,6 +596,7 @@ browser.runtime.onInstalled.addListener(function (event) {
if (event.reason === "update" && event.previousVersion) { if (event.reason === "update" && event.previousVersion) {
void migrateGlobalSearchDefaultsFor365Upgrade(event.previousVersion); void migrateGlobalSearchDefaultsFor365Upgrade(event.previousVersion);
void resetThemeOfTheMonthDisabledFor366Upgrade(event.previousVersion);
} }
}); });
+86 -8
View File
@@ -3753,20 +3753,98 @@ div.day-empty {
pointer-events: none; pointer-events: none;
animation: themeOfTheMonthCardOut 0.18s ease-in forwards; animation: themeOfTheMonthCardOut 0.18s ease-in forwards;
} }
.themeOfTheMonthCardClose { .themeOfTheMonthCardDisable {
position: absolute !important; position: absolute !important;
top: 4px !important; top: 6px !important;
right: 4px !important; right: 6px !important;
z-index: 2; z-index: 3;
width: 32px; display: flex;
height: 32px; align-items: center;
justify-content: center;
width: 18px;
height: 18px;
padding: 0 !important;
border: 1px solid rgba(255, 255, 255, 0.22); border: 1px solid rgba(255, 255, 255, 0.22);
border-radius: 16px !important; border-radius: 9px !important;
background: rgba(0, 0, 0, 0.42); background: rgba(0, 0, 0, 0.42);
color: white; color: white;
cursor: pointer; cursor: pointer;
font-size: 1.35rem; font-size: 0.78rem;
line-height: 1; 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 { .themeOfTheMonthCardImage {
display: block; display: block;
@@ -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} {#if $settingsState.devMode}
<div class="flex-col p-1 my-1 bg-gradient-to-br from-white rounded-xl border shadow-sm to-zinc-100 border-zinc-200/50 dark:border-zinc-700/40 dark:to-zinc-900/50 dark:from-zinc-900/40"> <div class="flex-col p-1 my-1 bg-gradient-to-br from-white rounded-xl border shadow-sm to-zinc-100 border-zinc-200/50 dark:border-zinc-700/40 dark:to-zinc-900/50 dark:from-zinc-900/40">
<div class="flex justify-between items-center px-4 py-3"> <div class="flex justify-between items-center px-4 py-3">
@@ -143,7 +143,7 @@ export async function OpenThemeOfTheMonthPopup(
const card = stringToHTML(/* html */ ` const card = stringToHTML(/* html */ `
<aside id="theme-of-the-month-card" class="themeOfTheMonthCard" role="dialog" aria-label="Theme of the Month"> <aside id="theme-of-the-month-card" class="themeOfTheMonthCard" role="dialog" aria-label="Theme of the Month">
<button type="button" class="themeOfTheMonthCardClose" aria-label="Close Theme of the Month">×</button> <button type="button" class="themeOfTheMonthCardDisable" aria-label="Don't show Theme of the Month again" title="Don't show again">×</button>
${ ${
heroUrl heroUrl
? `<img class="themeOfTheMonthCardImage" src="${escapeHTML(heroUrl)}" alt="${escapeHTML(entry.title)}" />` ? `<img class="themeOfTheMonthCardImage" src="${escapeHTML(heroUrl)}" alt="${escapeHTML(entry.title)}" />`
@@ -159,7 +159,17 @@ export async function OpenThemeOfTheMonthPopup(
? `<button type="button" class="themeOfTheMonthCardPrimary">Open Store</button>` ? `<button type="button" class="themeOfTheMonthCardPrimary">Open Store</button>`
: "" : ""
} }
<button type="button" class="themeOfTheMonthCardSecondary">Don't show again</button> <button type="button" class="themeOfTheMonthCardSecondary">Close</button>
</div>
</div>
<div class="themeOfTheMonthCardConfirm" hidden>
<div class="themeOfTheMonthCardConfirmInner">
<h3>Don't show again?</h3>
<p>You can re-enable Theme of the Month from BetterSEQTA+ settings.</p>
<div class="themeOfTheMonthCardConfirmActions">
<button type="button" class="themeOfTheMonthCardConfirmCancel">Cancel</button>
<button type="button" class="themeOfTheMonthCardConfirmAccept">Don't show again</button>
</div>
</div> </div>
</div> </div>
</aside> </aside>
@@ -177,7 +187,9 @@ export async function OpenThemeOfTheMonthPopup(
card.addEventListener("mouseenter", () => window.clearTimeout(autoCloseTimeout), { once: true }); card.addEventListener("mouseenter", () => window.clearTimeout(autoCloseTimeout), { once: true });
card.querySelector(".themeOfTheMonthCardClose")?.addEventListener("click", () => { const confirmEl = card.querySelector<HTMLElement>(".themeOfTheMonthCardConfirm");
card.querySelector(".themeOfTheMonthCardSecondary")?.addEventListener("click", () => {
dismiss(); dismiss();
}); });
@@ -186,7 +198,24 @@ export async function OpenThemeOfTheMonthPopup(
openThemeStoreWithHighlight(linkedThemeId!); 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; settingsState.themeOfTheMonthDisabled = true;
dismiss(); dismiss();
}); });