Dark Mode+

Sketchful dark theme improvements

目前为 2020-07-29 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Dark Mode+
  3. // @match https://sketchful.io/
  4. // @grant none
  5. // @version 1.2
  6. // @description Sketchful dark theme improvements
  7. // @author bebell
  8. // @run-at document-end
  9. // jshint esversion: 6
  10. // @namespace https://greasyfork.org/users/281093
  11. // ==/UserScript==
  12.  
  13. let grayCanvas = localStorage.grayCanvas
  14. ? JSON.parse(localStorage.grayCanvas)
  15. : true;
  16. const pageHTML = document.querySelector("html");
  17. const canvas = document.querySelector("#canvas");
  18. const ctx = canvas.getContext("2d");
  19. const themes = document.querySelector("#menuSettingsTheme");
  20. const settingsContainer = document.querySelector(
  21. "#menuSettings > div.row.justify-content-center > div"
  22. );
  23. const styleRules = [
  24. ".dark .table { color: white !important; }",
  25. ".table { color: black !important; }",
  26. ".dark { background-color: #1d1f22 !important; }",
  27. ".dark .table th, html.dark .table thead, html.dark .table td { border-color: #454d55 !important; }",
  28. ".table th, .table thead, .table td { border-color: #dee2e6 !important; }",
  29. ".dark .table.table-striped tbody tr:nth-of-type(odd) { background-color: rgba(255,255,255,.05)!important; }",
  30. ".table.table-striped tbody tr:nth-of-type(odd) { background-color: rgba(0,0,0,.05)!important; }",
  31. ".dark #gameChatList li:not(.chatAdmin) b { color: #BBB }",
  32. "#gameChatList li:not(.chatAdmin) b { color: black }",
  33. ".dark .gameAvatarRank { color: #148FA2 }",
  34. ".dark #gameWinners li b { color: white !important }",
  35. ".dark .gameSticky { color: white !important }",
  36. "#gameSticky font { color: black!important }",
  37. ".dark #gameSticky font { color: #eee!important }",
  38. ];
  39.  
  40. const sheet =
  41. window.document.styleSheets[window.document.styleSheets.length - 1];
  42. styleRules.forEach((rule) => sheet.insertRule(rule));
  43.  
  44. let btn;
  45. let stored = localStorage.dark;
  46. let darkMode = stored
  47. ? JSON.parse(stored)
  48. : JSON.parse(localStorage.getItem("settings")).dark;
  49.  
  50. if (darkMode) pageHTML.classList.add("dark");
  51. else pageHTML.classList.remove("dark");
  52.  
  53. canvas.style.filter = darkMode
  54. ? `brightness(${localStorage.canvasBrightness})` || ""
  55. : "";
  56.  
  57. themes.onchange = (e) => {
  58. if (e.target.value === "Dark" && !grayCanvas) {
  59. pageHTML.classList.add("dark");
  60. e.stopImmediatePropagation();
  61. }
  62. };
  63.  
  64. document.querySelector("#menu > div.menuNav > ul > li:nth-child(5) > a").onclick = () => {
  65. themes.value = darkMode ? "Dark" : "Light";
  66. };
  67.  
  68. function darkClassObserver(mutations, observer) {
  69. for (let mutation of mutations) {
  70. if (mutation.attributeName !== "class") return;
  71. darkMode = pageHTML.classList.contains("dark");
  72. localStorage.dark = darkMode;
  73. canvas.style.filter = darkMode
  74. ? `brightness(${localStorage.canvasBrightness})` || ""
  75. : "";
  76. fixColors();
  77. grayCanvas && toggleCanvasDarkMode();
  78. }
  79. }
  80.  
  81. const gameObserver = new MutationObserver(darkClassObserver);
  82.  
  83. gameObserver.observe(pageHTML, { attributes: true });
  84.  
  85. (function addBrightnessSlider() {
  86. const sliderContainer = document
  87. .querySelector("#menuSettingsVolumeIcon")
  88. .parentNode.cloneNode(true);
  89. sliderContainer.getElementsByTagName("h5")[0].textContent =
  90. "Canvas Brightness";
  91. const icon = sliderContainer.children[0];
  92. icon.onload = () => {
  93. icon.src = "https://faust.s-ul.eu/Sa78AixS";
  94. };
  95. const slider = sliderContainer.querySelector("#menuSettingsVolume");
  96. slider.value = localStorage.canvasBrightness || 1;
  97. slider.onchange = changeBrightness;
  98.  
  99. const grayCanvasToggle = document.createElement("div");
  100. grayCanvasToggle.setAttribute(
  101. "style",
  102. "display: flex; justify-content: space-between"
  103. );
  104. const label = document.createElement("label");
  105.  
  106. label.style.fontSize = "20px";
  107. label.textContent = "Gray Canvas";
  108.  
  109. let btnSwitch = document.createElement("label");
  110. let input = document.createElement("input");
  111. let span = document.createElement("span");
  112. span.setAttribute("class", "slider round");
  113. input.type = "checkbox";
  114. input.checked = grayCanvas;
  115. input.onchange = () => {
  116. grayCanvas = input.checked;
  117. localStorage.grayCanvas = grayCanvas;
  118. if (!grayCanvas && darkMode) {
  119. themes[0].selected = true;
  120. themes.dispatchEvent(new Event("change"));
  121. pageHTML.classList.add("dark");
  122. themes.value = darkMode ? "Dark" : "Light";
  123. }
  124. };
  125. btnSwitch.setAttribute("class", "switch");
  126. btnSwitch.append(input, span);
  127. grayCanvasToggle.append(label, btnSwitch);
  128. settingsContainer.append(sliderContainer, grayCanvasToggle);
  129. })();
  130.  
  131. (function toggleButtons() {
  132. btn = document.querySelector("#saveButton").cloneNode();
  133. btn.style.right = "100px";
  134. btn.setAttribute("data-original-title", "Toggle Theme");
  135. btn.title = "Toggle Theme";
  136. updateToggleStyle();
  137. btn.onclick = toggleDarkMode;
  138.  
  139. document.querySelector("#gameInterface").append(btn);
  140. })();
  141.  
  142. function changeBrightness() {
  143. canvas.style.filter = `brightness(${this.value})`;
  144. localStorage.canvasBrightness = this.value;
  145. }
  146.  
  147. function updateToggleStyle() {
  148. btn.style.backgroundImage = darkMode ? "url(https://i.imgur.com/UBpXB1r.png)" :
  149. "url(https://i.imgur.com/5phmZod.png)";
  150. }
  151.  
  152. function toggleDarkMode() {
  153. if (!grayCanvas) {
  154. pageHTML.classList.toggle("dark");
  155. } else {
  156. themes[darkMode ? 0 : 1].selected = true;
  157. themes.dispatchEvent(new Event("change"));
  158. }
  159. }
  160.  
  161. function toggleCanvasDarkMode() {
  162. const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  163. const data = imgData.data;
  164.  
  165. for (let i = 0; i < data.length; i += 4) {
  166. const [r, g, b] = [data[i], data[i + 1], data[i + 2]];
  167.  
  168. if (r === 255 && g === 255 && b === 255 && darkMode) {
  169. let color = 68;
  170. data[i] = color;
  171. data[i + 1] = color;
  172. data[i + 2] = color;
  173. }
  174. else if (r === 68 && g === 68 && b === 68 && !darkMode) {
  175. let color = 255;
  176. data[i] = color;
  177. data[i + 1] = color;
  178. data[i + 2] = color;
  179. }
  180. }
  181.  
  182. ctx.putImageData(imgData, 0, 0);
  183. }
  184.  
  185. function fixColors() {
  186. let names = document.getElementsByClassName("gameAvatarName");
  187. updateToggleStyle();
  188. if (!names.length)
  189. names = document.getElementsByClassName("gameSettingsAvatarName");
  190. for (let name of names) {
  191. if (darkMode && name.style.color === "black") {
  192. name.style.color = "#ccc";
  193. } else if (!darkMode && name.style.color === "rgb(204, 204, 204)") {
  194. name.style.color = "black";
  195. }
  196. }
  197. }
  198.  
  199. const colorObserver = new MutationObserver(() => {
  200. fixColors();
  201. });
  202.  
  203. colorObserver.observe(document.querySelector("#gamePlayersList"), {
  204. childList: true,
  205. });