Dark Reader

Toggle dark mode using an icon placed at the bottom left of your screen. Hotkey: Command + Shift + B

  1. // ==UserScript==
  2. // @name Dark Reader
  3. // @description Toggle dark mode using an icon placed at the bottom left of your screen. Hotkey: Command + Shift + B
  4. // @author Schimon Jehudah, Adv.
  5. // @namespace i2p.schimon.dimmer
  6. // @copyright 2023, Schimon Jehudah (http://schimon.i2p)
  7. // @license MIT; https://opensource.org/licenses/MIT
  8. // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48dGV4dCB5PSIuOWVtIiBmb250LXNpemU9IjkwIj7wn5SFPC90ZXh0Pjwvc3ZnPgo=
  9. // @match *://*/*
  10. // @exclude devtools://*
  11. // @version 24.10.17
  12. // @require https://unpkg.com/darkreader@latest/darkreader.js
  13. // @noframes
  14. // @grant GM.getValue
  15. // @grant GM.setValue
  16. // ==/UserScript==
  17.  
  18. /* TODO
  19.  
  20. Toggle color of button.
  21. btn.style.filter = 'hue-rotate(500deg)'
  22. See https://noscript.net/ or
  23. use a plain character '●'.
  24. btn.style.color = 'black' */
  25.  
  26.  
  27. if (document.doctype == null) { return; }
  28.  
  29. //enable()
  30.  
  31. const
  32. namespace = 'i2p-schimon-dimmer',
  33. btn = document.createElement(namespace);
  34.  
  35. // create button
  36. (async function createButton() {
  37. // create element
  38. document.body.append(btn);
  39. // set content
  40. btn.textContent = '🔆';
  41. btn.id = namespace;
  42. btn.style.all = 'unset';
  43. // set position
  44. btn.style.position = 'fixed';
  45. btn.style.bottom = 0;
  46. btn.style.left = 0;
  47. // set appearance
  48. btn.style.marginTop = '100px';
  49. btn.style.marginRight = '10px';
  50. btn.style.minWidth = '50px';
  51. btn.style.minHeight = '50px';
  52. btn.style.fontSize = '20px';
  53. btn.style.zIndex = 10000;
  54. btn.style.opacity = 0.5;
  55. //btn.style.transition = 'all .5s ease .5s';
  56. btn.onmouseover = () => {
  57. document
  58. .getElementById(namespace)
  59. .style.opacity = 0.9;
  60. };
  61. btn.onmouseout = () => {
  62. document
  63. .getElementById(namespace)
  64. .style.opacity = 0.3;
  65. };
  66. // center character
  67. btn.style.justifyContent = 'center';
  68. btn.style.alignItems = 'center';
  69. btn.style.display = 'flex';
  70. // disable selection marks
  71. btn.style.outline = 'none';
  72. btn.style.userSelect = 'none';
  73. btn.style.cursor = 'default';
  74. // set button behaviour
  75. btn.onclick = () => {
  76. //btn.onclick = async () => {
  77. try {
  78. toggle();
  79. //await toggle();
  80. } catch (err) {
  81. toggleByShape();
  82. console.warn('No support for Greasemonkey API');
  83. console.error(err);
  84. }
  85. };
  86. try {
  87. if (await GM.getValue('dimmer')) {
  88. enable()
  89. } else {
  90. disable();
  91. }
  92. } catch (err) {
  93. console.warn('No support for Greasemonkey API');
  94. console.error(err);
  95. }
  96. })();
  97.  
  98. // set hotkey
  99. document.onkeyup = function(e) {
  100. //if (e.ctrlKey && e.shiftKey && e.which == 190) { // Ctrl + Shift + <
  101. //if (e.metaKey && e.shiftKey && e.which == 68) { // Command + Shift + D
  102. if (e.metaKey && e.shiftKey && e.which == 66) { // Command + Shift + B
  103. toggle();
  104. }
  105. };
  106.  
  107. // toggle mode
  108. async function toggle() {
  109. if (await GM.getValue('dimmer')) {
  110. await GM.setValue('dimmer', false);
  111. disable();
  112. } else {
  113. await GM.setValue('dimmer', true);
  114. enable();
  115. }
  116. }
  117.  
  118. // toggle mode
  119. function toggleByShape() {
  120. if (btn.textContent == '🔆') {
  121. enable()
  122. } else {
  123. disable();
  124. }
  125. }
  126.  
  127. function disable() {
  128. DarkReader.disable({
  129. brightness: 100,
  130. contrast: 90,
  131. sepia: 10
  132. });
  133. btn.textContent = '🔆';
  134. //return '🔆';
  135. }
  136.  
  137. function enable() {
  138. DarkReader.setFetchMethod(window.fetch); // https://eligrey.com/
  139. DarkReader.enable({
  140. brightness: 100,
  141. contrast: 90,
  142. sepia: 10
  143. });
  144. btn.textContent = '🔅';
  145. //return '🔅';
  146. }
  147.  
  148. // Set mode temporarily per session or until storage is cleared
  149.  
  150. function getPreference(key) {
  151. return window.localStorage.getItem(key);
  152. }
  153.  
  154. function setPreference(key, value) {
  155. return window.localStorage.setItem(key, value);
  156. }