diff --git a/background.js b/background.js new file mode 100644 index 0000000..5db2bc6 --- /dev/null +++ b/background.js @@ -0,0 +1,5 @@ +// background.js +chrome.browserAction.onClicked.addListener((tab) => { + // Send a message to the content script to toggle dark mode + chrome.tabs.sendMessage(tab.id, { action: 'toggleDarkMode' }); +}); diff --git a/content.js b/content.js new file mode 100644 index 0000000..e701fb3 --- /dev/null +++ b/content.js @@ -0,0 +1,185 @@ +let isDarkMode = false; // Track current mode (light or dark) + +// Color Palette for Dark Mode +const darkModeStyles = { + backgroundColor: '#121212', // Dark background for general elements + color: '#e0e0e0', // General text color + linkColor: '#bb86fc', // Link color for dark mode + activeLinkColor: '#ff79c6', // Active link color + buttonBackground: '#333333', // Button background color for dark mode + buttonTextColor: '#e0e0e0', // Button text color + inputBackground: '#333333', // Input background color for dark mode + inputTextColor: '#e0e0e0', // Input text color + codeBackground: '#1e1e1e', // Code block background color for dark mode + borderColor: '#444444', // Border color for inputs, buttons, etc. + containerBackground: '#181818', // Even darker shade for containers like .s-topbar + siteSpecificHeaderFooterBackground: '#eeeeee', // Light background color for certain headers +}; + +// Function to apply dark mode via JavaScript only (without using CSS) +function applyDarkMode() { + // Apply the general background and text color to the body + document.body.style.backgroundColor = darkModeStyles.backgroundColor; + document.body.style.color = darkModeStyles.color; + + // 1. Loop through all elements to find light background colors and change them + const allElements = document.querySelectorAll('*'); + allElements.forEach(el => { + const computedBackgroundColor = window.getComputedStyle(el).backgroundColor; + const computedBackgroundImage = window.getComputedStyle(el).backgroundImage; + + // Check for light backgrounds (RGB or hex-based light colors) and ignore background images + if (isLightBackground(computedBackgroundColor) && computedBackgroundImage === 'none') { + el.style.backgroundColor = darkModeStyles.backgroundColor; // Set to dark mode color + } else if (computedBackgroundImage && (computedBackgroundImage.includes('linear-gradient') || computedBackgroundImage.includes('radial-gradient'))) { + // Handle gradients with pure white or light colors + el.style.backgroundImage = adjustLightGradients(computedBackgroundImage); + } + + // Apply text color to all elements except code blocks and pre blocks + if (el.tagName !== 'CODE' && el.tagName !== 'PRE') { + el.style.color = darkModeStyles.color; + } + + // Handle padding and margin issues by checking padding area background + handlePaddingAndMarginBackground(el); + }); + + // 2. Handle site-specific elements such as headers and footers (e.g., Craigslist, MDN, etc.) + const siteSpecificElements = document.querySelectorAll('header, footer, .header, .footer'); + siteSpecificElements.forEach(el => { + const bgColor = window.getComputedStyle(el).backgroundColor; + if (bgColor === 'rgb(238, 238, 238)' || bgColor === 'rgba(238, 238, 238, 1)') { + el.style.backgroundColor = darkModeStyles.siteSpecificHeaderFooterBackground; + } + }); + + // 3. Handle other specific elements like buttons, inputs, code blocks, etc. + handleFormElements(); + handleCodeBlocks(); + handleLinks(); +} + +// Helper function to determine if a background color is light +function isLightBackground(rgbColor) { + if (!rgbColor) return false; // If there's no color or invalid color, return false + const rgb = rgbColor.match(/^rgba?\((\d+), (\d+), (\d+)/); // Match rgb values + if (rgb) { + const r = parseInt(rgb[1], 10); + const g = parseInt(rgb[2], 10); + const b = parseInt(rgb[3], 10); + // Simple luminance calculation to detect light colors + const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b; + return luminance > 150; // Threshold for light background + } + return false; // If it's not an RGB value, assume it's not light +} + +// Function to adjust light colors in a gradient (specifically pure white or light colors) +function adjustLightGradients(gradient) { + const gradientRegex = /(linear-gradient|radial-gradient)\((.*?)\)/; + return gradient.replace(gradientRegex, (match, type, gradientContent) => { + // Regex to match rgb or rgba color values in the gradient + const lightColorRegex = /rgba?\((\d+), (\d+), (\d+)(?:, (\d*\.?\d+))?\)/g; + + // Replace each light color (e.g., rgb(255, 255, 255)) with a darker color + const adjustedGradient = gradientContent.replace(lightColorRegex, (colorMatch, r, g, b, a) => { + // Calculate luminance for detecting light colors + const luminance = 0.2126 * parseInt(r, 10) + 0.7152 * parseInt(g, 10) + 0.0722 * parseInt(b, 10); + + // If the luminance is higher than a threshold (200), it's a light color + if (luminance > 200) { + // Replace light colors with a dark background color (e.g., #282828 or similar) + return `rgb(40, 40, 40)`; // Dark theme color + } + return colorMatch; // Keep dark colors unchanged + }); + + // Return the updated gradient + return `${type}(${adjustedGradient})`; + }); +} + +// Function to ensure padding and margin background colors are applied +function handlePaddingAndMarginBackground(el) { + const padding = window.getComputedStyle(el).padding; + const margin = window.getComputedStyle(el).margin; + const bgColor = window.getComputedStyle(el).backgroundColor; + + // Check if the element has padding or margin and is missing a background + if ((padding !== '0px' || margin !== '0px') && (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent')) { + el.style.backgroundColor = darkModeStyles.backgroundColor; // Ensure padding area has a background color + } +} + +// Function to handle links with dark mode styling +function handleLinks() { + const links = document.querySelectorAll('a'); + links.forEach(link => { + link.style.color = darkModeStyles.linkColor; + if (link.hasAttribute('aria-selected') && link.getAttribute('aria-selected') === 'true') { + link.style.color = darkModeStyles.activeLinkColor; // Active state color for links + } + }); +} + +// Function to handle form elements (buttons, inputs) +function handleFormElements() { + const buttons = document.querySelectorAll('button'); + buttons.forEach(button => { + button.style.backgroundColor = darkModeStyles.buttonBackground; + button.style.color = darkModeStyles.buttonTextColor; + button.style.borderColor = darkModeStyles.borderColor; + if (button.hasAttribute('aria-pressed') && button.getAttribute('aria-pressed') === 'true') { + button.style.backgroundColor = darkModeStyles.activeLinkColor; // Active state for buttons + } + }); + + const inputs = document.querySelectorAll('input, textarea, select'); + inputs.forEach(input => { + input.style.backgroundColor = darkModeStyles.inputBackground; + input.style.color = darkModeStyles.inputTextColor; + input.style.borderColor = darkModeStyles.borderColor; + }); +} + +// Function to handle code blocks with dark mode styling +function handleCodeBlocks() { + const codeBlocks = document.querySelectorAll('code, pre'); + codeBlocks.forEach(code => { + code.style.backgroundColor = darkModeStyles.codeBackground; + code.style.color = darkModeStyles.color; // Use the dark text color for code + }); +} + +// Function to revert to light mode (optional) +function revertLightMode() { + // Reset all styles + document.body.style.backgroundColor = ''; + document.body.style.color = ''; + const allElements = document.querySelectorAll('*'); + allElements.forEach(el => { + el.style.backgroundColor = ''; + el.style.backgroundImage = ''; + el.style.color = ''; + }); +} + +// Listen for the toggle dark mode action +chrome.runtime.onMessage.addListener((message) => { + if (message.action === 'toggleDarkMode') { + if (isDarkMode) { + revertLightMode(); + } else { + applyDarkMode(); + } + isDarkMode = !isDarkMode; + } +}); + +// Apply dark mode on page load +if (isDarkMode) { + applyDarkMode(); +} else { + revertLightMode(); +} diff --git a/icons/icon128.png b/icons/icon128.png new file mode 100644 index 0000000..5240c3d Binary files /dev/null and b/icons/icon128.png differ diff --git a/icons/icon16.png b/icons/icon16.png new file mode 100644 index 0000000..4390ec9 Binary files /dev/null and b/icons/icon16.png differ diff --git a/icons/icon48.png b/icons/icon48.png new file mode 100644 index 0000000..0632b1e Binary files /dev/null and b/icons/icon48.png differ diff --git a/icons/icon96.png b/icons/icon96.png new file mode 100644 index 0000000..aca8598 Binary files /dev/null and b/icons/icon96.png differ diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..aff01c4 --- /dev/null +++ b/manifest.json @@ -0,0 +1,29 @@ +{ + "manifest_version": 2, + "name": "Dark Mode Toggle", + "version": "1.0", + "description": "Toggle dark mode using inline styles without affecting fingerprinting tools.", + "permissions": [ + "activeTab" + ], + "background": { + "scripts": ["background.js"] + }, + "browser_action": { + "default_icon": "icons/icon48.png", + "default_title": "Toggle Dark Mode" + }, + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"] + } + ], + "icons": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "96": "icons/icon96.png", + "128": "icons/icon128.png" + } + } + \ No newline at end of file