dark-mode-toggle-addon/content.js

185 lines
7.6 KiB
JavaScript

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();
}