Release v0.1.2: site-backup persistence + PNG toolbar icons
- Mirror dismissals to window.localStorage on autotrader.co.uk ("atm:..."
key). If browser.storage.local comes up empty after a quirky reinstall,
the content script rehydrates from the site backup on the next page load.
- Replace the SVG toolbar icon with PNG renders (16/32/48/96/128) — some
Firefox installs don't render extension SVG icons reliably in the
toolbar / extensions flyout.
- Sharp added as a devDependency to rebuild icons from icon.svg.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+49
-3
@@ -20,22 +20,67 @@ const state = {
|
||||
};
|
||||
|
||||
// --- storage ---
|
||||
//
|
||||
// Primary: browser.storage.local (per-extension, syncs across tabs via
|
||||
// storage.onChanged). Secondary: window.localStorage scoped to
|
||||
// autotrader.co.uk — survives extension reinstall, because it's the site's
|
||||
// storage, not the extension's. On load, if extension storage is empty but
|
||||
// the site backup has entries, we re-hydrate. On every write we mirror to the
|
||||
// site backup so the two stay in lockstep.
|
||||
|
||||
const BACKUP_KEY = "atm:dismissedListings:v1";
|
||||
|
||||
function readSiteBackup() {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(BACKUP_KEY);
|
||||
return raw ? JSON.parse(raw) : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function writeSiteBackup(dismissed) {
|
||||
try {
|
||||
window.localStorage.setItem(BACKUP_KEY, JSON.stringify(dismissed));
|
||||
} catch {
|
||||
// localStorage full/disabled — nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
async function loadState() {
|
||||
const res = await api.storage.local.get([STORAGE_KEY, SETTINGS_KEY]);
|
||||
state.dismissed = res[STORAGE_KEY] || {};
|
||||
let dismissed = res[STORAGE_KEY] || {};
|
||||
|
||||
// Re-hydrate from site backup if extension storage lost its entries
|
||||
// (e.g. after an unlisted reinstall that didn't upgrade in place).
|
||||
const backup = readSiteBackup();
|
||||
if (backup && Object.keys(dismissed).length === 0 && Object.keys(backup).length > 0) {
|
||||
dismissed = backup;
|
||||
await api.storage.local.set({ [STORAGE_KEY]: dismissed });
|
||||
console.log("[ATM] restored", Object.keys(dismissed).length, "dismissals from site backup");
|
||||
} else if (Object.keys(dismissed).length > 0) {
|
||||
// Keep site backup fresh even if we didn't need it this load
|
||||
writeSiteBackup(dismissed);
|
||||
}
|
||||
|
||||
state.dismissed = dismissed;
|
||||
state.hideDismissed = !!(res[SETTINGS_KEY] && res[SETTINGS_KEY].hideDismissed);
|
||||
applyHideMode();
|
||||
}
|
||||
|
||||
async function persistDismissed() {
|
||||
await api.storage.local.set({ [STORAGE_KEY]: state.dismissed });
|
||||
writeSiteBackup(state.dismissed);
|
||||
}
|
||||
|
||||
async function setDismissed(id, title) {
|
||||
state.dismissed[id] = { ts: Date.now(), title: title || "" };
|
||||
await api.storage.local.set({ [STORAGE_KEY]: state.dismissed });
|
||||
await persistDismissed();
|
||||
}
|
||||
|
||||
async function clearDismissed(id) {
|
||||
delete state.dismissed[id];
|
||||
await api.storage.local.set({ [STORAGE_KEY]: state.dismissed });
|
||||
await persistDismissed();
|
||||
}
|
||||
|
||||
function applyHideMode() {
|
||||
@@ -263,6 +308,7 @@ api.storage.onChanged.addListener((changes, area) => {
|
||||
if (area !== "local") return;
|
||||
if (changes[STORAGE_KEY]) {
|
||||
state.dismissed = changes[STORAGE_KEY].newValue || {};
|
||||
writeSiteBackup(state.dismissed); // keep site backup in sync with popup-driven changes
|
||||
document.querySelectorAll(".atm-card[data-atm-id]").forEach((card) => {
|
||||
refreshCardState(card, card.dataset.atmId);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user