Enable dark mode with a toggle button and automatically based on location
// ==UserScript==
// @name Dark Mode Auto Toggle
// @version 0.2.3
// @description Enable dark mode with a toggle button and automatically based on location
// @namespace https://greasyfork.org/en/users/28298
// @author https://greasyfork.org/en/users/28298
// @license MIT
// @match *://*/*
// @grant GM_getValue
// @grant GM_setValue
// @homepage https://greasyfork.org/en/scripts/523690
// ==/UserScript==
// @grant none
// original author: Michael Wang https://greasyfork.org/en/scripts/472251-dark-mode/code
// with help of claude ai
(function() {
'use strict';
//////////////////////////////////////////////////////////////////////////
// manually tell domain's original mode, because auto detection would fail
const domainModes = {
'claude.ai' : 'dark',
'chat.openai.com' : 'dark',
'deepseek.com' : 'dark',
'perplexity.ai' : 'dark',
'cloud.microsoft' : 'dark',
'linux.do' : 'dark',
'duckduckgo.com' : 'dark',
'www.google.com' : 'dark',
'youtube.com' : 'dark',
'greasyfork.org' : 'dark',
'web.telegram.org': 'dark',
'192.168.1.1' : 'dark',
'192.168.1.2' : 'dark',
'192.168.1.3' : 'dark',
'127.0.0.1' : 'dark',
};
/////////////////////////////////////////////////////////////////////////
// Create style element for dark mode
const darkStyle = document.createElement('style');
darkStyle.textContent = `
html {
filter: invert(1) hue-rotate(180deg) contrast(0.8);
}
/** reverse filter for media elements */
img, video, picture, canvas, iframe, embed {
filter: invert(1) hue-rotate(180deg);
}
`;
// Initialize based on page's current state
let darkMode = false; // Start with no filter
// Function to detect if page is already dark
function isPageDark() {
const url = window.location.hostname;
// Check if domain is in our list
for (const domain in domainModes) {
if (url.includes(domain)) {
return domainModes[domain] === 'dark';
}
}
// auto detection
function isDarkMode() {
try {
const bgcolor = window.getComputedStyle(document.body).backgroundColor;
const rgb = color.match(/\d+/g);
if (!rgb) return 255 < 128; // Default to light if can't detect
// Use perceived brightness formula
return (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000 < 128;
} catch (e) {
return false;
}
}
function checkDarkModeClasses() {
const html = document.documentElement;
const body = document.body;
const darkClasses = ['dark', 'dark-mode', 'dark-theme', 'theme-dark'];
return darkClasses.some(className =>
html.classList.contains(className) || body.classList.contains(className)
);
}
function checkDarkModeAttributes() {
const html = document.documentElement;
return html.getAttribute('data-theme') === 'dark' ||
html.getAttribute('data-color-mode') === 'dark';
}
// Check computed colors
const isDarkByColor = isDarkMode();
// Check classes and attributes
const isDarkByClass = checkDarkModeClasses();
const isDarkByAttribute = checkDarkModeAttributes();
// Site is likely in dark mode if any of these are true
return isDarkByClass || isDarkByAttribute || isDarkByColor;
}
// Initialize darkMode based on stored preference or page state
const pageIsDark = isPageDark();
// Create toggle button
const button = document.createElement('button');
button.innerHTML = pageIsDark ? '☀️' : '🌛';
button.style.position = 'fixed';
button.style.top = '45px';
button.style.right = '10px';
button.style.zIndex = '1000';
button.style.background = 'none';
button.style.border = 'none';
button.style.fontSize = '24px';
button.style.cursor = 'pointer';
button.style.color = 'inherit';
// Function to get sunrise/sunset times
async function getSunTimes() {
// approximate times
const now = new Date();
return {
sunrise: new Date(now.setHours(8, 0, 0, 0)),
sunset: new Date(now.setHours(18, 0, 0, 0))
};
}
// Function to toggle dark mode
function toggleDarkMode(forceDark) {
if (forceDark !== undefined) {
// Auto dark mode (sunrise/sunset)
if (pageIsDark) {
// If page is already dark, don't change anything
return;
}
darkMode = forceDark;
} else {
// Manual toggle - always allow regardless of pageIsDark
darkMode = !darkMode;
}
if (darkMode) {
document.head.appendChild(darkStyle);
button.innerHTML = pageIsDark ? '🌛' : '☀️';
} else {
if (darkStyle.parentNode) {
document.head.removeChild(darkStyle);
}
button.innerHTML = pageIsDark ? '☀️' : '🌛';
}
}
// Function to check and update dark mode based on time
async function updateDarkMode() {
const sunTimes = await getSunTimes();
const now = new Date();
const isDark = now < sunTimes.sunrise || now > sunTimes.sunset;
toggleDarkMode(isDark);
}
// Add settings button
const settingsButton = document.createElement('button');
settingsButton.innerHTML = '⚙';
settingsButton.style.position = 'fixed';
settingsButton.style.top = '40px';
settingsButton.style.right = '15px';
settingsButton.style.zIndex = '1000';
settingsButton.style.background = 'none';
settingsButton.style.border = 'none';
settingsButton.style.fontSize = '12px';
settingsButton.style.cursor = 'pointer';
settingsButton.style.color = 'inherit';
// Settings panel to reset location
settingsButton.addEventListener('click', () => {
if (confirm('Reset location settings?')) {
GM_setValue('userLocation', null);
location.reload();
}
});
// Initial update
updateDarkMode();
// Update every half hour (1800000)
setInterval(updateDarkMode, 1800000);
// Manual toggle still works
button.addEventListener('click', () => toggleDarkMode());
// Add buttons to page
document.body.appendChild(button);
})();