A userscript to help avoid getting blasted by a wall of white light while hacking at 2am
1
auto-dark-mode.user.js edited
88 lines 2.5 kB view raw
1// ==UserScript== 2// @name Auto Dark Mode 3// @namespace mydarkmode 4// @version 1.0 5// @description Automatically invert light-themed pages when system prefers dark mode 6// @author snailbird.bsky.social 7// @match *://*/* 8// @exclude https://mail.google.com/* 9// @grant GM_addStyle 10// @run-at document-idle 11// ==/UserScript== 12 13(function () { 14 'use strict'; 15 16 const LUMINANCE_THRESHOLD = 0.4; 17 const RECHECK_DELAY_MS = 1500; 18 const CLASS_NAME = 'jsnl-dark-mode'; 19 20 const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); 21 22 function srgbToLinear(c) { 23 c /= 255; 24 return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); 25 } 26 27 function relativeLuminance(r, g, b) { 28 return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b); 29 } 30 31 function parseRgb(color) { 32 if (!color || color === 'transparent' || color === 'rgba(0, 0, 0, 0)') return null; 33 const m = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/); 34 return m ? [+m[1], +m[2], +m[3]] : null; 35 } 36 37 function getPageLuminance() { 38 for (const el of [document.body, document.documentElement]) { 39 if (!el) continue; 40 const rgb = parseRgb(window.getComputedStyle(el).backgroundColor); 41 if (rgb) return relativeLuminance(...rgb); 42 } 43 return 1; 44 } 45 46 let styleInjected = false; 47 48 function injectStyle() { 49 if (styleInjected) return; 50 styleInjected = true; 51 GM_addStyle(` 52 .${CLASS_NAME} { 53 filter: invert(0.90) hue-rotate(180deg); 54 } 55 .${CLASS_NAME} img, 56 .${CLASS_NAME} video, 57 .${CLASS_NAME} svg image, 58 .${CLASS_NAME} picture, 59 .${CLASS_NAME} [style*="background-image"] { 60 filter: invert(1) hue-rotate(180deg); 61 } 62 `); 63 } 64 65 function activate() { 66 injectStyle(); 67 (document.documentElement ?? document.body).classList.add(CLASS_NAME); 68 } 69 70 function deactivate() { 71 (document.documentElement ?? document.body).classList.remove(CLASS_NAME); 72 } 73 74 function evaluate() { 75 if (!darkModeQuery.matches) { 76 deactivate(); 77 return; 78 } 79 if (getPageLuminance() >= LUMINANCE_THRESHOLD) { 80 activate(); 81 } 82 } 83 84 evaluate(); 85 setTimeout(evaluate, RECHECK_DELAY_MS); 86 87 darkModeQuery.addEventListener('change', evaluate); 88})();