diff options
Diffstat (limited to 'data-viewer')
-rw-r--r-- | data-viewer/data-viewer.css | 234 | ||||
-rw-r--r-- | data-viewer/data-viewer.html | 116 | ||||
-rw-r--r-- | data-viewer/data-viewer.js | 605 |
3 files changed, 840 insertions, 115 deletions
diff --git a/data-viewer/data-viewer.css b/data-viewer/data-viewer.css index fd5c3e7..3add494 100644 --- a/data-viewer/data-viewer.css +++ b/data-viewer/data-viewer.css @@ -6,7 +6,7 @@ background-color: var(--secondary-bg); border-radius: var(--radius-md); padding: 16px; - margin-bottom: 24px; + margin-bottom: 4px; border-left: 3px solid var(--accent-color); } @@ -14,11 +14,12 @@ margin-top: 8px; color: var(--text-secondary); font-size: 13px; - padding-left: 58px; + /* padding-left: 58px; */ } /* General layout adjustments */ .app-content { + width: 90%; max-width: 960px; margin: 0 auto; padding: 20px; @@ -36,7 +37,7 @@ body { /* Data section styling */ .data-section { - margin-bottom: 24px; + margin-bottom: 4px; background-color: var(--secondary-bg); border-radius: var(--radius-md); padding: 16px; @@ -109,7 +110,7 @@ body { } .website-panel { - margin-bottom: 8px; + margin-bottom: 4px; background-color: var(--bg-color); border-radius: var(--radius-md); overflow: hidden; @@ -346,18 +347,7 @@ body { /* Clear list button styling */ .clear-list-button { - margin-top: 8px; - margin-bottom: 16px; - background-color: var(--secondary-bg); - border-color: var(--border-color); - font-size: 12px; - padding: 6px 12px; -} - -.clear-list-button:hover { - background-color: rgba(220, 53, 69, 0.1); - border-color: var(--danger-color); - color: var(--danger-color); + margin-bottom: 20px; } /* Null and object value styling */ @@ -373,7 +363,7 @@ body { /* Danger zone styling */ .danger-zone { - margin-top: 24px; + margin-top: 8px; padding: 16px; background-color: var(--danger-bg-color); border: 1px solid var(--danger-border-color); @@ -446,3 +436,213 @@ body { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); } } + +/* Styling for the website lists section */ +.tables-container { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 16px; + margin-top: 16px; +} + +.list-title-section { + margin-bottom: 16px; +} + +.list-title-section h3 { + margin-top: 0; + margin-bottom: 12px; + color: var(--text-primary); + font-size: 18px; +} + +.list-section { + background-color: var(--bg-color); + border-radius: var(--radius-sm); + padding: 16px; +} + +.list-section h4 { + margin-top: 0; + margin-bottom: 8px; + color: var(--accent-color); +} + +.list-description { + margin-top: 0; + margin-bottom: 16px; + font-size: 13px; + color: var(--text-secondary); + font-style: italic; +} + +.remove-site-button { + background-color: var(--danger-color); + color: white; + border: none; + border-radius: 50%; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: var(--transition); +} + +.remove-site-button:hover { + background-color: var(--danger-hover-color); + transform: scale(1.1); +} + +.remove-site-button i { + font-size: 12px; +} + +.clear-list-button { + margin-bottom: 20px; +} + +/* Backup and Restore Styling */ +.backup-restore-container { + background-color: var(--bg-color); + border-radius: var(--radius-sm); + padding: 16px; + border-left: 3px solid var(--accent-color); +} + +.backup-description { + margin-top: 0; + margin-bottom: 16px; + color: var(--text-secondary); + font-size: 14px; + line-height: 1.5; +} + +.backup-actions { + display: flex; + gap: 16px; + margin-bottom: 16px; +} + +.import-container, +#export-settings { + flex: 1; +} + +.import-label { + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} + +.import-status { + font-size: 14px; + margin-top: 8px; + padding: 8px 0; + border-radius: var(--radius-sm); +} + +.status-success { + color: var(--success-color); + font-weight: 500; +} + +.status-error { + color: var(--danger-color); + font-weight: 500; +} + +/* Repository URL styling */ +.repository-url-container { + background-color: var(--bg-color); + border-radius: var(--radius-sm); + padding: 16px; + border-left: 3px solid var(--accent-color); +} + +.repository-url-controls { + display: flex; + flex-direction: column; + gap: 12px; + margin-bottom: 16px; +} + +.repository-url-input { + /* width: 100%; */ + padding: 10px 12px; + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + background-color: var(--bg-color); + color: var(--text-primary); + font-size: 14px; +} + +.repository-url-input:focus { + outline: none; + border-color: var(--accent-color); +} + +.repository-url-buttons { + display: flex; + gap: 12px; +} + +.repository-url-status { + font-size: 14px; + margin-top: 8px; + padding: 8px 0; + border-radius: var(--radius-sm); +} + +/* Add responsive adjustments for mobile */ +@media (max-width: 1024px) { + .tables-container { + grid-template-columns: 1fr; + gap: 12px; + } +} + +@media (max-width: 768px) { + .repository-url-buttons { + flex-direction: column; + gap: 8px; + } + + .repository-url-buttons button { + width: 100%; + } +} + +/* Global toggles container styling */ +.global-toggles-container { + background-color: var(--bg-color); + border-radius: var(--radius-sm); + padding: 16px; + border-left: 3px solid var(--accent-color); +} + +.toggle-row { + display: flex; + flex-wrap: wrap; + gap: 16px; + margin-bottom: 12px; +} + +.toggle-row .toggle-container { + flex: 1; + min-width: 180px; + margin-bottom: 0; +} + +@media (max-width: 768px) { + .toggle-row { + flex-direction: column; + gap: 8px; + } + + .toggle-row .toggle-container { + margin-bottom: 4px; + } +} diff --git a/data-viewer/data-viewer.html b/data-viewer/data-viewer.html index b0d4a5f..0f4ba9b 100644 --- a/data-viewer/data-viewer.html +++ b/data-viewer/data-viewer.html @@ -16,7 +16,7 @@ <header class="app-header"> <div id="header-container"> <div class="logo-container"> - <img src="../assets/images/logo_48.png" alt="ZenInternet Logo" class="logo-img"> + <img src="../assets/images/logo.png" alt="ZenInternet Logo" class="logo-img"> <h1 class="app-title">Zen Internet Settings</h1> </div> <div class="miniheader"> @@ -27,22 +27,61 @@ </header> <main class="app-content"> - <div class="actions"> - <button id="back-button" class="action-button secondary"> - <i class="fas fa-arrow-left"></i> Back to Extension - </button> + <!-- Backup & Restore section moved to top --> + <div class="data-section"> + <h2 class="section-title">Backup & Restore ✨</h2> + <div class="backup-restore-container"> + <p class="backup-description"> + Export your settings to a JSON file or import settings from a previously exported file. + <br><strong>Note:</strong> This includes global settings, website lists, and website-specific + feature toggles, but not the actual style data which will be re-fetched. + </p> + <div class="backup-actions"> + <button id="export-settings" class="action-button primary"> + <i class="fas fa-upload"></i> Export Settings + </button> + <div class="import-container"> + <label for="import-file" class="action-button secondary import-label"> + <i class="fas fa-download"></i> Import Settings + </label> + <input type="file" id="import-file" accept=".json" hidden> + </div> + </div> + <div id="import-status" class="import-status"></div> + </div> </div> - <div class="toggle-setting-container"> - <div class="toggle-container"> - <label class="toggle-switch"> - <input type="checkbox" id="disable-transparency"> - <span class="slider round"></span> - </label> - <span class="toggle-label">Disable Transparency Globally</span> - </div> - <div class="setting-description"> - This will disable all transparency features while keeping other styling effects active + <!-- Global toggles grouped into a single section with a heading --> + <div class="data-section"> + <h2 class="section-title">Global Feature Controls ✨</h2> + <div class="global-toggles-container"> + <div class="toggle-row"> + <div class="toggle-container"> + <label class="toggle-switch"> + <input type="checkbox" id="disable-transparency"> + <span class="slider round"></span> + </label> + <span class="toggle-label">Disable Transparency</span> + </div> + <div class="toggle-container"> + <label class="toggle-switch"> + <input type="checkbox" id="disable-hover"> + <span class="slider round"></span> + </label> + <span class="toggle-label">Disable Hover Effects</span> + </div> + <div class="toggle-container"> + <label class="toggle-switch"> + <input type="checkbox" id="disable-footer"> + <span class="slider round"></span> + </label> + <span class="toggle-label">Keep Footers</span> + </div> + </div> + <div class="setting-description"> + These settings control specific feature types across all websites. + Changes apply only to newly opened or reloaded tabs. + </div> </div> </div> @@ -56,6 +95,32 @@ <div id="skip-list-data" class="data-container"></div> </div> + <!-- Repository URL section moved above danger zone --> + <div class="data-section"> + <h2 class="section-title">Custom Styles Repository ✨</h2> + <div class="repository-url-container"> + <p class="setting-description"> + Change the URL where styles are fetched from. Use this if you want to use a different styles + repository. + <br><strong>Note:</strong> After changing the URL, you should clear existing styles data for + best results. + </p> + <div class="repository-url-controls"> + <input type="text" id="repository-url" class="repository-url-input" + placeholder="Enter repository URL..."> + <div class="repository-url-buttons"> + <button id="set-repository-url" class="action-button primary"> + <i class="fas fa-save"></i> Set URL + </button> + <button id="reset-repository-url" class="action-button secondary"> + <i class="fas fa-undo"></i> Reset to Default + </button> + </div> + </div> + <div id="repository-url-status" class="repository-url-status"></div> + </div> + </div> + <div class="danger-zone"> <h3 class="danger-title">Danger Zone</h3> <div class="danger-actions"> @@ -69,17 +134,18 @@ <h2 class="section-title">Websites and CSS</h2> <div id="combined-websites-data" class="data-container"></div> </div> - </main> - <footer class="app-footer"> - <a href="https://sameerasw.github.io/my-internet/" class="footer-link" target="_blank"> - <i class="fas fa-book"></i> Styles Repository - </a> - <div class="footer-divider"></div> - <a href="https://github.com/sameerasw/zeninternet" class="footer-link" target="_blank"> - <i class="fa-brands fa-github"></i> Project Repository - </a> - </footer> + + <footer class="app-footer"> + <a href="https://sameerasw.github.io/my-internet/" class="footer-link" target="_blank"> + <i class="fas fa-book"></i> Styles Repository + </a> + <div class="footer-divider"></div> + <a href="https://github.com/sameerasw/zeninternet" class="footer-link" target="_blank"> + <i class="fa-brands fa-github"></i> Project Repository + </a> + </footer> + </main> </div> <script src="data-viewer.js"></script> </body> diff --git a/data-viewer/data-viewer.js b/data-viewer/data-viewer.js index f6dd566..be1b798 100644 --- a/data-viewer/data-viewer.js +++ b/data-viewer/data-viewer.js @@ -1,18 +1,38 @@ document.addEventListener("DOMContentLoaded", function () { const BROWSER_STORAGE_KEY = "transparentZenSettings"; const SKIP_FORCE_THEMING_KEY = "skipForceThemingList"; + const SKIP_THEMING_KEY = "skipThemingList"; + const FALLBACK_BACKGROUND_KEY = "fallbackBackgroundList"; + const REPOSITORY_URL_KEY = "stylesRepositoryUrl"; + const DEFAULT_REPOSITORY_URL = + "https://sameerasw.github.io/my-internet/styles.json"; const globalSettingsElement = document.getElementById("global-settings-data"); const skipListElement = document.getElementById("skip-list-data"); const combinedWebsitesElement = document.getElementById( "combined-websites-data" ); - const backButton = document.getElementById("back-button"); const deleteAllButton = document.getElementById("delete-all-data"); const versionElement = document.getElementById("addon-version"); const disableTransparencyToggle = document.getElementById( "disable-transparency" ); + // New toggle elements + const disableHoverToggle = document.getElementById("disable-hover"); + const disableFooterToggle = document.getElementById("disable-footer"); + + // Repository URL Elements + const repositoryUrlInput = document.getElementById("repository-url"); + const setRepositoryUrlButton = document.getElementById("set-repository-url"); + const resetRepositoryUrlButton = document.getElementById( + "reset-repository-url" + ); + const repositoryUrlStatus = document.getElementById("repository-url-status"); + + // Backup & Restore Elements + const exportButton = document.getElementById("export-settings"); + const importFileInput = document.getElementById("import-file"); + const importStatusElement = document.getElementById("import-status"); // Load and display the data loadAllData(); @@ -20,16 +40,20 @@ document.addEventListener("DOMContentLoaded", function () { // Display addon version displayAddonVersion(); - // Event listener for the back button - backButton.addEventListener("click", function () { - window.close(); - }); - // Event listener for disable transparency toggle disableTransparencyToggle.addEventListener("change", function () { saveTransparencySettings(this.checked); }); + // Event listeners for new toggles + disableHoverToggle.addEventListener("change", function () { + saveHoverSettings(this.checked); + }); + + disableFooterToggle.addEventListener("change", function () { + saveFooterSettings(this.checked); + }); + // Event listener for delete all data button deleteAllButton.addEventListener("click", function () { if ( @@ -41,6 +65,132 @@ document.addEventListener("DOMContentLoaded", function () { } }); + // Repository URL event listeners + setRepositoryUrlButton.addEventListener("click", setRepositoryUrl); + resetRepositoryUrlButton.addEventListener("click", resetRepositoryUrl); + + // New event listeners for export and import functionality + exportButton.addEventListener("click", exportSettings); + importFileInput.addEventListener("change", importSettings); + + // Load the repository URL from storage + loadRepositoryUrl(); + + async function loadRepositoryUrl() { + try { + const data = await browser.storage.local.get(REPOSITORY_URL_KEY); + const repositoryUrl = data[REPOSITORY_URL_KEY] || DEFAULT_REPOSITORY_URL; + repositoryUrlInput.value = repositoryUrl; + } catch (error) { + console.error("Error loading repository URL:", error); + repositoryUrlInput.value = DEFAULT_REPOSITORY_URL; + } + } + + async function setRepositoryUrl() { + try { + const newUrl = repositoryUrlInput.value.trim(); + + if (!newUrl) { + showRepositoryUrlStatus("Repository URL cannot be empty", "error"); + return; + } + + // Simple URL validation + try { + new URL(newUrl); + } catch (e) { + showRepositoryUrlStatus("Invalid URL format", "error"); + return; + } + + // Save the new URL to storage + await browser.storage.local.set({ [REPOSITORY_URL_KEY]: newUrl }); + + showRepositoryUrlStatus("Repository URL saved successfully", "success"); + + // Prompt the user to clear styles data + if ( + confirm( + "Would you like to clear existing styles data to avoid conflicts with the new repository?\n\nThis will clear saved styles and website-specific settings, but keep your global settings." + ) + ) { + await clearStylesData(); + } + } catch (error) { + console.error("Error setting repository URL:", error); + showRepositoryUrlStatus(`Error saving URL: ${error.message}`, "error"); + } + } + + async function resetRepositoryUrl() { + try { + repositoryUrlInput.value = DEFAULT_REPOSITORY_URL; + await browser.storage.local.set({ + [REPOSITORY_URL_KEY]: DEFAULT_REPOSITORY_URL, + }); + + showRepositoryUrlStatus("Repository URL reset to default", "success"); + + // Prompt to clear styles data + if ( + confirm( + "Would you like to clear existing styles data to avoid conflicts?\n\nThis will clear saved styles and website-specific settings, but keep your global settings." + ) + ) { + await clearStylesData(); + } + } catch (error) { + console.error("Error resetting repository URL:", error); + showRepositoryUrlStatus(`Error resetting URL: ${error.message}`, "error"); + } + } + + async function clearStylesData() { + try { + // Get all storage data to filter what to keep and what to remove + const allData = await browser.storage.local.get(null); + + // Create a new object with just the data we want to keep + const dataToKeep = {}; + + // Keep global settings + if (allData[BROWSER_STORAGE_KEY]) { + dataToKeep[BROWSER_STORAGE_KEY] = allData[BROWSER_STORAGE_KEY]; + } + + // Keep repository URL + if (allData[REPOSITORY_URL_KEY]) { + dataToKeep[REPOSITORY_URL_KEY] = allData[REPOSITORY_URL_KEY]; + } + + // Clear all storage first + await browser.storage.local.clear(); + + // Then restore the data we want to keep + await browser.storage.local.set(dataToKeep); + + // Refresh the data display + loadAllData(); + + showRepositoryUrlStatus("Styles data cleared successfully", "success"); + } catch (error) { + console.error("Error clearing styles data:", error); + showRepositoryUrlStatus(`Error clearing data: ${error.message}`, "error"); + } + } + + function showRepositoryUrlStatus(message, type) { + repositoryUrlStatus.textContent = message; + repositoryUrlStatus.className = `repository-url-status status-${type}`; + + // Clear the message after 5 seconds + setTimeout(() => { + repositoryUrlStatus.textContent = ""; + repositoryUrlStatus.className = "repository-url-status"; + }, 5000); + } + async function deleteAllData() { try { // Clear all storage data @@ -68,20 +218,202 @@ document.addEventListener("DOMContentLoaded", function () { settings.disableTransparency = isDisabled; await browser.storage.local.set({ [BROWSER_STORAGE_KEY]: settings }); - alert( - `Transparency has been ${ - isDisabled ? "disabled" : "enabled" - } globally. This will affect all websites.` - ); + // No notification - just save the setting silently } catch (error) { console.error("Error saving transparency settings:", error); - alert( - "An error occurred while saving the transparency setting: " + - error.message - ); } } + // New functions to save hover and footer settings + async function saveHoverSettings(isDisabled) { + try { + const data = await browser.storage.local.get(BROWSER_STORAGE_KEY); + const settings = data[BROWSER_STORAGE_KEY] || {}; + + // Update the disableHover setting + settings.disableHover = isDisabled; + + await browser.storage.local.set({ [BROWSER_STORAGE_KEY]: settings }); + // No notification - just save the setting silently + } catch (error) { + console.error("Error saving hover settings:", error); + } + } + + async function saveFooterSettings(isDisabled) { + try { + const data = await browser.storage.local.get(BROWSER_STORAGE_KEY); + const settings = data[BROWSER_STORAGE_KEY] || {}; + + // Update the disableFooter setting + settings.disableFooter = isDisabled; + + await browser.storage.local.set({ [BROWSER_STORAGE_KEY]: settings }); + // No notification - just save the setting silently + } catch (error) { + console.error("Error saving footer settings:", error); + } + } + + // Export settings functionality + async function exportSettings() { + try { + // Retrieve all storage data to find site-specific settings + const allData = await browser.storage.local.get(null); + + // Get the fallback background list once + const fallbackBackgroundList = allData[FALLBACK_BACKGROUND_KEY] || []; + + // Extract only the settings we want to backup + const settingsToBackup = { + [BROWSER_STORAGE_KEY]: allData[BROWSER_STORAGE_KEY] || {}, + [SKIP_FORCE_THEMING_KEY]: allData[SKIP_FORCE_THEMING_KEY] || [], + [SKIP_THEMING_KEY]: allData[SKIP_THEMING_KEY] || [], + [FALLBACK_BACKGROUND_KEY]: fallbackBackgroundList, + [REPOSITORY_URL_KEY]: + allData[REPOSITORY_URL_KEY] || DEFAULT_REPOSITORY_URL, + }; + + // Remove fallbackBackgroundList from global settings if it exists there + if (settingsToBackup[BROWSER_STORAGE_KEY].fallbackBackgroundList) { + delete settingsToBackup[BROWSER_STORAGE_KEY].fallbackBackgroundList; + } + + // Also extract site-specific settings (keys that start with BROWSER_STORAGE_KEY.) + const siteSpecificSettings = {}; + for (const [key, value] of Object.entries(allData)) { + if (key.startsWith(BROWSER_STORAGE_KEY + ".")) { + siteSpecificSettings[key] = value; + } + } + + // Add export timestamp and version + const manifest = browser.runtime.getManifest(); + const exportData = { + exportDate: new Date().toISOString(), + addonVersion: manifest.version, + settings: settingsToBackup, + siteSettings: siteSpecificSettings, + }; + + // Convert to JSON + const jsonData = JSON.stringify(exportData, null, 2); + + // Create a blob and download link + const blob = new Blob([jsonData], { type: "application/json" }); + const url = URL.createObjectURL(blob); + + // Create a temporary anchor and trigger download + const a = document.createElement("a"); + a.href = url; + a.download = `zen-internet-settings-${ + new Date().toISOString().split("T")[0] + }.json`; + document.body.appendChild(a); + a.click(); + + // Cleanup + setTimeout(() => { + document.body.removeChild(a); + URL.revokeObjectURL(url); + }, 0); + + // Show success message + showImportStatus("Settings exported successfully!", "success"); + } catch (error) { + console.error("Error exporting settings:", error); + showImportStatus(`Export failed: ${error.message}`, "error"); + } + } + + // Import settings functionality + async function importSettings(event) { + try { + const file = event.target.files[0]; + if (!file) return; + + const reader = new FileReader(); + + reader.onload = async (e) => { + try { + const importData = JSON.parse(e.target.result); + + // Validate the imported data structure + if ( + !importData.settings || + !importData.settings[BROWSER_STORAGE_KEY] + ) { + throw new Error("Invalid settings file format"); + } + + // Confirm the import + if ( + confirm( + `Are you sure you want to import settings from ${importData.exportDate}? This will overwrite your current settings.` + ) + ) { + // First store the global settings, lists, and repository URL + const importOperations = { + [BROWSER_STORAGE_KEY]: importData.settings[BROWSER_STORAGE_KEY], + [SKIP_FORCE_THEMING_KEY]: + importData.settings[SKIP_FORCE_THEMING_KEY] || [], + [SKIP_THEMING_KEY]: importData.settings[SKIP_THEMING_KEY] || [], + [REPOSITORY_URL_KEY]: + importData.settings[REPOSITORY_URL_KEY] || + DEFAULT_REPOSITORY_URL, + }; + + // Then add any site-specific settings if they exist + if (importData.siteSettings) { + for (const [key, value] of Object.entries( + importData.siteSettings + )) { + importOperations[key] = value; + } + } + + // Apply all settings at once + await browser.storage.local.set(importOperations); + + showImportStatus( + "Settings imported successfully! Reloading...", + "success" + ); + + // Reload the page after a short delay + setTimeout(() => { + window.location.reload(); + }, 1500); + } else { + // User cancelled + importFileInput.value = ""; + showImportStatus("Import cancelled", "error"); + } + } catch (parseError) { + console.error("Error parsing import file:", parseError); + showImportStatus(`Import failed: ${parseError.message}`, "error"); + } + }; + + reader.readAsText(file); + } catch (error) { + console.error("Error handling import:", error); + showImportStatus(`Import failed: ${error.message}`, "error"); + } + } + + // Helper function to show import status messages + function showImportStatus(message, type) { + importStatusElement.textContent = message; + importStatusElement.className = `import-status status-${type}`; + + // Clear the message after 5 seconds + setTimeout(() => { + importStatusElement.textContent = ""; + importStatusElement.className = "import-status"; + }, 5000); + } + async function displayAddonVersion() { const manifest = browser.runtime.getManifest(); versionElement.textContent = `Version: ${manifest.version}`; @@ -90,24 +422,26 @@ document.addEventListener("DOMContentLoaded", function () { async function loadAllData() { try { // Load all data from storage - const data = await browser.storage.local.get(null); - - // Display global settings - const globalSettings = data[BROWSER_STORAGE_KEY] || {}; - displayGlobalSettings(globalSettings); - - // Set the disable transparency toggle state - disableTransparencyToggle.checked = - globalSettings.disableTransparency || false; + const allData = await browser.storage.local.get(null); - // Display skip/enable list - const skipList = data[SKIP_FORCE_THEMING_KEY] || []; - displaySkipList(skipList, globalSettings.whitelistMode); + // Extract global settings + const globalSettings = allData[BROWSER_STORAGE_KEY] || {}; - // Display combined websites and settings - displayCombinedWebsiteData(data); + // Extract skip lists + const skipForceList = allData[SKIP_FORCE_THEMING_KEY] || []; + const skipThemingList = allData[SKIP_THEMING_KEY] || []; + const fallbackBackgroundList = allData[FALLBACK_BACKGROUND_KEY] || []; - console.info("Data loaded successfully"); + // Display the data + displayGlobalSettings(globalSettings); + displayCombinedSkipLists( + skipForceList, + skipThemingList, + fallbackBackgroundList, + globalSettings.whitelistMode || false, + globalSettings.whitelistStyleMode || false + ); + displayCombinedWebsiteData(allData); } catch (error) { console.error("Error loading data:", error); } @@ -155,46 +489,123 @@ document.addEventListener("DOMContentLoaded", function () { globalSettingsElement.appendChild(table); } - function displaySkipList(skipList, isWhitelistMode) { + function displayCombinedSkipLists( + skipForceList, + skipThemingList, + fallbackBackgroundList, + isWhitelistMode, + isWhitelistStyleMode + ) { skipListElement.innerHTML = ""; - const modeType = isWhitelistMode ? "Whitelist" : "Blacklist"; - const actionType = isWhitelistMode ? "Enabled" : "Skipped"; + // Create title and description section + const titleSection = document.createElement("div"); + titleSection.className = "list-title-section"; + + const forceModeName = isWhitelistMode ? "Whitelist" : "Blacklist"; + const styleModeName = isWhitelistStyleMode ? "Whitelist" : "Blacklist"; - const modeInfo = document.createElement("div"); - modeInfo.classList.add("mode-info"); - modeInfo.innerHTML = `<strong>Current Mode:</strong> ${modeType} Mode - ${ + titleSection.innerHTML = ` + <h3>Website Lists Overview</h3> + <div class="mode-info"> + <div><strong>Force Styling Mode:</strong> ${forceModeName} Mode (${ isWhitelistMode - ? "Only apply forced styling to sites in the list" - : "Apply forced styling to all sites except those in the list" - }`; - skipListElement.appendChild(modeInfo); - - // Add Clear List button - if (skipList.length > 0) { - const clearListButton = document.createElement("button"); - clearListButton.classList.add( + ? "only apply to sites in the list" + : "apply to all except sites in the list" + })</div> + <div><strong>General Styling Mode:</strong> ${styleModeName} Mode (${ + isWhitelistStyleMode + ? "only apply to sites in the list" + : "apply to all except sites in the list" + })</div> + </div> + `; + + skipListElement.appendChild(titleSection); + + // Add Clear All Lists button + if ( + skipForceList.length > 0 || + skipThemingList.length > 0 || + fallbackBackgroundList.length > 0 + ) { + const clearAllButton = document.createElement("button"); + clearAllButton.classList.add( "action-button", - "secondary", + "danger", "clear-list-button" ); - clearListButton.innerHTML = '<i class="fas fa-trash"></i> Clear List'; - clearListButton.addEventListener("click", function () { - if ( - confirm( - `Are you sure you want to clear the entire ${modeType} list? This will affect how styling is applied to websites.` - ) - ) { - clearSkipList(); - } - }); - skipListElement.appendChild(clearListButton); + clearAllButton.innerHTML = '<i class="fas fa-trash"></i> Clear All Lists'; + clearAllButton.addEventListener("click", clearAllSkipLists); + skipListElement.appendChild(clearAllButton); } - if (skipList.length === 0) { - skipListElement.innerHTML += - '<div class="no-data">No websites in the list.</div>'; - return; + // Create container for the three tables + const tablesContainer = document.createElement("div"); + tablesContainer.className = "tables-container"; + + // Create force styling list + const forceListSection = createSingleListSection( + skipForceList, + isWhitelistMode, + "Force Styling List", + isWhitelistMode + ? "Sites where forced styling IS applied" + : "Sites where forced styling is NOT applied", + SKIP_FORCE_THEMING_KEY + ); + + // Create regular styling list + const regularListSection = createSingleListSection( + skipThemingList, + isWhitelistStyleMode, + "Regular Styling List", + isWhitelistStyleMode + ? "Sites where regular styling IS applied" + : "Sites where regular styling is NOT applied", + SKIP_THEMING_KEY + ); + + // Create fallback background list + const fallbackListSection = createSingleListSection( + fallbackBackgroundList, + false, // Fallback background is not whitelist/blacklist based + "Fallback Background List", + "Sites where a default background added, no transparency", + FALLBACK_BACKGROUND_KEY + ); + + tablesContainer.appendChild(forceListSection); + tablesContainer.appendChild(regularListSection); + tablesContainer.appendChild(fallbackListSection); + skipListElement.appendChild(tablesContainer); + } + + function createSingleListSection( + list, + isWhitelistMode, + title, + description, + storageKey + ) { + const section = document.createElement("div"); + section.className = "list-section"; + + const sectionTitle = document.createElement("h4"); + sectionTitle.textContent = title; + section.appendChild(sectionTitle); + + const sectionDescription = document.createElement("p"); + sectionDescription.className = "list-description"; + sectionDescription.textContent = description; + section.appendChild(sectionDescription); + + if (list.length === 0) { + const emptyMessage = document.createElement("div"); + emptyMessage.className = "no-data"; + emptyMessage.textContent = "No websites in this list"; + section.appendChild(emptyMessage); + return section; } const table = document.createElement("table"); @@ -203,33 +614,81 @@ document.addEventListener("DOMContentLoaded", function () { // Table header const thead = document.createElement("thead"); const headerRow = document.createElement("tr"); - headerRow.innerHTML = `<th>${actionType} Websites</th>`; + headerRow.innerHTML = `<th>Website</th><th>Action</th>`; thead.appendChild(headerRow); table.appendChild(thead); // Table body const tbody = document.createElement("tbody"); - for (const site of skipList) { + for (const site of list) { const row = document.createElement("tr"); - row.innerHTML = `<td>${site}</td>`; + + // Website column + const siteCell = document.createElement("td"); + siteCell.textContent = site; + row.appendChild(siteCell); + + // Action column + const actionCell = document.createElement("td"); + const removeButton = document.createElement("button"); + removeButton.className = "remove-site-button"; + removeButton.innerHTML = '<i class="fas fa-times"></i>'; + removeButton.title = "Remove from list"; + removeButton.addEventListener("click", function () { + removeSiteFromList(site, storageKey); + }); + actionCell.appendChild(removeButton); + row.appendChild(actionCell); + tbody.appendChild(row); } table.appendChild(tbody); - skipListElement.appendChild(table); + section.appendChild(table); + return section; + } + + async function removeSiteFromList(site, listKey) { + try { + // Get current list + const data = await browser.storage.local.get(listKey); + const list = data[listKey] || []; + + // Remove the site + const newList = list.filter((item) => item !== site); + + // Save updated list + await browser.storage.local.set({ [listKey]: newList }); + + // Refresh the display + loadAllData(); + + console.log(`Removed ${site} from ${listKey}`); + } catch (error) { + console.error(`Error removing site from list: ${error}`); + alert(`An error occurred: ${error.message}`); + } } - async function clearSkipList() { + async function clearAllSkipLists() { try { - await browser.storage.local.remove(SKIP_FORCE_THEMING_KEY); - alert(`${SKIP_FORCE_THEMING_KEY} has been cleared successfully.`); - loadAllData(); // Reload data to reflect changes + if ( + confirm( + "Are you sure you want to clear ALL website lists? This will remove all entries from:\n- Force Styling List\n- Regular Styling List\n- Fallback Background List\n\nThis action cannot be undone." + ) + ) { + await browser.storage.local.set({ + [SKIP_FORCE_THEMING_KEY]: [], + [SKIP_THEMING_KEY]: [], + [FALLBACK_BACKGROUND_KEY]: [], + }); + loadAllData(); // Reload to show empty lists + console.log("All skip lists cleared"); + } } catch (error) { - console.error("Error clearing skip list:", error); - alert( - "An error occurred while trying to clear the list: " + error.message - ); + console.error("Error clearing skip lists:", error); + alert("An error occurred while clearing the lists: " + error.message); } } |