From 7f45e1729c777de8f37e2f98bd58957a13d7027b Mon Sep 17 00:00:00 2001 From: sameerasw Date: Thu, 10 Apr 2025 14:27:39 +0530 Subject: Added whitelist and blacklist toggle for forcing themes --- popup/popup.css | 51 +++++++++++++++----- popup/popup.html | 9 +++- popup/popup.js | 141 ++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 169 insertions(+), 32 deletions(-) (limited to 'popup') diff --git a/popup/popup.css b/popup/popup.css index 0058174..1a47b2a 100644 --- a/popup/popup.css +++ b/popup/popup.css @@ -1,4 +1,4 @@ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); +@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"); :root { --radius-sm: 6px; @@ -7,7 +7,7 @@ --transition: all 0.2s ease; --shadow: 0 2px 10px rgba(0, 0, 0, 0.3); --accent-color: #f98764; /* Subtle Zen-themed orange */ - --hover-color: #fa9475; /* Lighter hover state */ + --hover-color: #fa9475; /* Lighter hover state */ --success-color: #40c057; --warning-color: #fab005; --danger-color: #fa5252; @@ -22,7 +22,7 @@ body { width: 360px; margin: 0; padding: 0; - font-family: 'Inter', Arial, sans-serif; + font-family: "Inter", Arial, sans-serif; color: var(--text-primary); background-color: var(--bg-color); font-size: 14px; @@ -106,8 +106,14 @@ body { } @keyframes fadeIn { - from { opacity: 0; transform: translateY(-5px); } - to { opacity: 1; transform: translateY(0); } + from { + opacity: 0; + transform: translateY(-5px); + } + to { + opacity: 1; + transform: translateY(0); + } } .toggle-switch { @@ -243,7 +249,7 @@ input:checked + .slider:before { border: 1px solid var(--border-color); border-radius: var(--radius-sm); background-color: var(--bg-color); - + /* Firefox scrollbar styling */ scrollbar-width: thin; scrollbar-color: var(--accent-color) transparent; @@ -355,6 +361,14 @@ input:checked + .slider:before { padding-left: 9px !important; /* Compensate for the border */ } +/* Mode Indicator */ +.mode-indicator { + font-size: 0.85em; + color: var(--text-secondary); + margin: 8px 0; + font-style: italic; +} + .current-badge { display: inline-block; background-color: var(--accent-color); @@ -387,8 +401,12 @@ input:checked + .slider:before { } @keyframes fadeIn { - from { opacity: 0.7; } - to { opacity: 1; } + from { + opacity: 0.7; + } + to { + opacity: 1; + } } /* Make sure the text doesn't overflow */ @@ -404,22 +422,29 @@ input:checked + .slider:before { margin-right: 4px; } -#addon-version, #last-fetched-time{ +#addon-version, +#last-fetched-time { font-size: 0.75em; } -.forcing-container{ +.forcing-container { background-color: var(--secondary-bg); border-radius: var(--radius-md); padding: 16px; margin-bottom: 16px; } -.warning{ +.warning { color: var(--warning-color); margin-top: 8px; } -#reload{ +#reload { margin-top: 16px; -} \ No newline at end of file +} + +.mode-hint { + font-size: 0.75em; + color: var(--text-secondary); + margin-left: 8px; +} diff --git a/popup/popup.html b/popup/popup.html index c07e5fa..8ffa03d 100644 --- a/popup/popup.html +++ b/popup/popup.html @@ -71,12 +71,19 @@ Force Styling +
+ + Blacklist Mode +
- Skip Forcing for this Site + Skip Forcing for this Site
diff --git a/popup/popup.js b/popup/popup.js index a71eb4f..d81ed7d 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -13,9 +13,13 @@ new (class ExtensionPopup { autoUpdateSwitch = document.getElementById("auto-update"); lastFetchedTime = document.getElementById("last-fetched-time"); forceStylingSwitch = document.getElementById("force-styling"); + whitelistModeSwitch = document.getElementById("whitelist-mode"); + whitelistModeLabel = document.getElementById("whitelist-mode-label"); skipForceThemingSwitch = document.getElementById("skip-force-theming"); + siteToggleLabel = document.getElementById("site-toggle-label"); skipForceThemingList = []; reloadButton = document.getElementById("reload"); + modeIndicator = document.getElementById("mode-indicator"); constructor() { if (logging) console.log("Initializing ExtensionPopup"); @@ -45,6 +49,11 @@ new (class ExtensionPopup { ); this.reloadButton.addEventListener("click", this.reloadPage.bind(this)); + this.whitelistModeSwitch.addEventListener( + "change", + this.handleWhitelistModeChange.bind(this) + ); + // Setup auto-update and display last fetched time this.setupAutoUpdate(); this.displayLastFetchedTime(); @@ -97,9 +106,18 @@ new (class ExtensionPopup { this.globalSettings.enableStyling ?? true; this.autoUpdateSwitch.checked = this.globalSettings.autoUpdate ?? false; this.forceStylingSwitch.checked = this.globalSettings.forceStyling ?? false; - this.skipForceThemingSwitch.checked = this.skipForceThemingList.includes( + this.whitelistModeSwitch.checked = + this.globalSettings.whitelistMode ?? false; + + this.updateModeLabels(); + + // In whitelist mode, checked means "include this site" + // In blacklist mode, checked means "skip this site" + const isInList = this.skipForceThemingList.includes( this.currentSiteHostname ); + this.skipForceThemingSwitch.checked = isInList; + this.loadCurrentSiteFeatures(); } @@ -131,6 +149,7 @@ new (class ExtensionPopup { this.globalSettings.enableStyling = this.enableStylingSwitch.checked; this.globalSettings.autoUpdate = this.autoUpdateSwitch.checked; this.globalSettings.forceStyling = this.forceStylingSwitch.checked; + this.globalSettings.whitelistMode = this.whitelistModeSwitch.checked; browser.storage.local .set({ @@ -180,14 +199,20 @@ new (class ExtensionPopup { const index = this.skipForceThemingList.indexOf(this.currentSiteHostname); if (isChecked && index === -1) { + // Add to the list (whitelist: include, blacklist: skip) this.skipForceThemingList.push(this.currentSiteHostname); } else if (!isChecked && index !== -1) { + // Remove from the list (whitelist: exclude, blacklist: include) this.skipForceThemingList.splice(index, 1); } - browser.storage.local.set({ - [SKIP_FORCE_THEMING_KEY]: this.skipForceThemingList, - }); + browser.storage.local + .set({ + [SKIP_FORCE_THEMING_KEY]: this.skipForceThemingList, + }) + .then(() => { + this.updateActiveTabStyling(); + }); } async loadCurrentSiteFeatures() { @@ -335,34 +360,51 @@ new (class ExtensionPopup { const hostname = url.hostname; try { - await browser.tabs.removeCSS(tab.id, { - code: "/* Placeholder for removing CSS */", - }); - } catch (error) {} + // Try to remove any existing CSS first + try { + await browser.tabs.removeCSS(tab.id, { + code: "/* Placeholder for removing CSS */", + }); + } catch (error) { + // Ignore errors as they may occur if no CSS was previously applied + } - if (!this.shouldApplyCSS(hostname)) return; + if (!this.shouldApplyCSS(hostname)) return; - try { const stylesData = await browser.storage.local.get("styles"); const styles = stylesData.styles?.website || {}; - let siteKey = null; + // First try to find a direct match for a CSS file + let bestMatch = null; + let bestMatchLength = 0; + for (const site of Object.keys(styles)) { const siteName = site.replace(/\.css$/, ""); if (siteName.startsWith("+")) { const baseSiteName = siteName.slice(1); - if (hostname.endsWith(baseSiteName)) { - siteKey = site; - break; + if ( + hostname.endsWith(baseSiteName) && + baseSiteName.length > bestMatchLength + ) { + bestMatch = site; + bestMatchLength = baseSiteName.length; } } else if (hostname === siteName || hostname === `www.${siteName}`) { - siteKey = site; + // Exact match has priority + bestMatch = site; break; + } else if ( + hostname.endsWith(siteName) && + siteName.length > bestMatchLength + ) { + bestMatch = site; + bestMatchLength = siteName.length; } } - if (siteKey && styles[siteKey]) { - const features = styles[siteKey]; + // If we found a direct match, use it + if (bestMatch) { + const features = styles[bestMatch]; const siteStorageKey = `${this.BROWSER_STORAGE_KEY}.${hostname}`; const siteData = await browser.storage.local.get(siteStorageKey); const featureSettings = siteData[siteStorageKey] || {}; @@ -376,7 +418,36 @@ new (class ExtensionPopup { if (combinedCSS) { await browser.tabs.insertCSS(tab.id, { code: combinedCSS }); - console.info(`Applied CSS to ${hostname}`); + console.info(`Applied CSS to ${hostname} (direct match)`); + } + } else if (this.globalSettings.forceStyling) { + // Otherwise check for forced styling + const isInList = this.skipForceThemingList.includes(hostname); + const isWhitelistMode = this.globalSettings.whitelistMode; + + // Determine if we should apply forced styling + const shouldApplyForcedStyling = + (isWhitelistMode && isInList) || (!isWhitelistMode && !isInList); + + if (shouldApplyForcedStyling && styles["example.com.css"]) { + const features = styles["example.com.css"]; + const siteStorageKey = `${this.BROWSER_STORAGE_KEY}.${hostname}`; + const siteData = await browser.storage.local.get(siteStorageKey); + const featureSettings = siteData[siteStorageKey] || {}; + + let combinedCSS = ""; + for (const [feature, css] of Object.entries(features)) { + if (featureSettings[feature] !== false) { + combinedCSS += css + "\n"; + } + } + + if (combinedCSS) { + await browser.tabs.insertCSS(tab.id, { code: combinedCSS }); + console.info(`Applied forced CSS to ${hostname}`); + } + } else { + console.info(`Skipping forced styling for ${hostname}`); } } } catch (error) { @@ -434,4 +505,38 @@ new (class ExtensionPopup { } } } + + handleWhitelistModeChange() { + this.updateModeLabels(); + this.saveSettings(); + } + + updateModeIndicator() { + if (this.whitelistModeSwitch.checked) { + this.modeIndicator.textContent = + "In Whitelist Mode (apply only to listed sites)"; + } else { + this.modeIndicator.textContent = + "In Blacklist Mode (apply to all except listed sites)"; + } + } + + updateSiteToggleLabel() { + // Update the label based on the current mode + if (this.whitelistModeSwitch.checked) { + this.siteToggleLabel.textContent = "Enable for this Site"; + } else { + this.siteToggleLabel.textContent = "Skip Forcing for this Site"; + } + } + + updateModeLabels() { + if (this.whitelistModeSwitch.checked) { + this.whitelistModeLabel.textContent = "Whitelist Mode"; + this.siteToggleLabel.textContent = "Enable for this Site"; + } else { + this.whitelistModeLabel.textContent = "Blacklist Mode"; + this.siteToggleLabel.textContent = "Skip Forcing for this Site"; + } + } })(); -- cgit v1.2.3