// ==UserScript==
// @name Dark Mode+
// @match https://sketchful.io/
// @grant none
// @version 1.2
// @description Sketchful dark theme improvements
// @author bebell
// @run-at document-end
// jshint esversion: 6
// @namespace https://gf.qytechs.cn/users/281093
// ==/UserScript==
let grayCanvas = localStorage.grayCanvas
? JSON.parse(localStorage.grayCanvas)
: true;
const pageHTML = document.querySelector("html");
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
const themes = document.querySelector("#menuSettingsTheme");
const settingsContainer = document.querySelector(
"#menuSettings > div.row.justify-content-center > div"
);
const styleRules = [
".dark .table { color: white !important; }",
".table { color: black !important; }",
".dark { background-color: #1d1f22 !important; }",
".dark .table th, html.dark .table thead, html.dark .table td { border-color: #454d55 !important; }",
".table th, .table thead, .table td { border-color: #dee2e6 !important; }",
".dark .table.table-striped tbody tr:nth-of-type(odd) { background-color: rgba(255,255,255,.05)!important; }",
".table.table-striped tbody tr:nth-of-type(odd) { background-color: rgba(0,0,0,.05)!important; }",
".dark #gameChatList li:not(.chatAdmin) b { color: #BBB }",
"#gameChatList li:not(.chatAdmin) b { color: black }",
".dark .gameAvatarRank { color: #148FA2 }",
".dark #gameWinners li b { color: white !important }",
".dark .gameSticky { color: white !important }",
"#gameSticky font { color: black!important }",
".dark #gameSticky font { color: #eee!important }",
];
const sheet =
window.document.styleSheets[window.document.styleSheets.length - 1];
styleRules.forEach((rule) => sheet.insertRule(rule));
let btn;
let stored = localStorage.dark;
let darkMode = stored
? JSON.parse(stored)
: JSON.parse(localStorage.getItem("settings")).dark;
if (darkMode) pageHTML.classList.add("dark");
else pageHTML.classList.remove("dark");
canvas.style.filter = darkMode
? `brightness(${localStorage.canvasBrightness})` || ""
: "";
themes.onchange = (e) => {
if (e.target.value === "Dark" && !grayCanvas) {
pageHTML.classList.add("dark");
e.stopImmediatePropagation();
}
};
document.querySelector("#menu > div.menuNav > ul > li:nth-child(5) > a").onclick = () => {
themes.value = darkMode ? "Dark" : "Light";
};
function darkClassObserver(mutations, observer) {
for (let mutation of mutations) {
if (mutation.attributeName !== "class") return;
darkMode = pageHTML.classList.contains("dark");
localStorage.dark = darkMode;
canvas.style.filter = darkMode
? `brightness(${localStorage.canvasBrightness})` || ""
: "";
fixColors();
grayCanvas && toggleCanvasDarkMode();
}
}
const gameObserver = new MutationObserver(darkClassObserver);
gameObserver.observe(pageHTML, { attributes: true });
(function addBrightnessSlider() {
const sliderContainer = document
.querySelector("#menuSettingsVolumeIcon")
.parentNode.cloneNode(true);
sliderContainer.getElementsByTagName("h5")[0].textContent =
"Canvas Brightness";
const icon = sliderContainer.children[0];
icon.onload = () => {
icon.src = "https://faust.s-ul.eu/Sa78AixS";
};
const slider = sliderContainer.querySelector("#menuSettingsVolume");
slider.value = localStorage.canvasBrightness || 1;
slider.onchange = changeBrightness;
const grayCanvasToggle = document.createElement("div");
grayCanvasToggle.setAttribute(
"style",
"display: flex; justify-content: space-between"
);
const label = document.createElement("label");
label.style.fontSize = "20px";
label.textContent = "Gray Canvas";
let btnSwitch = document.createElement("label");
let input = document.createElement("input");
let span = document.createElement("span");
span.setAttribute("class", "slider round");
input.type = "checkbox";
input.checked = grayCanvas;
input.onchange = () => {
grayCanvas = input.checked;
localStorage.grayCanvas = grayCanvas;
if (!grayCanvas && darkMode) {
themes[0].selected = true;
themes.dispatchEvent(new Event("change"));
pageHTML.classList.add("dark");
themes.value = darkMode ? "Dark" : "Light";
}
};
btnSwitch.setAttribute("class", "switch");
btnSwitch.append(input, span);
grayCanvasToggle.append(label, btnSwitch);
settingsContainer.append(sliderContainer, grayCanvasToggle);
})();
(function toggleButtons() {
btn = document.querySelector("#saveButton").cloneNode();
btn.style.right = "100px";
btn.setAttribute("data-original-title", "Toggle Theme");
btn.title = "Toggle Theme";
updateToggleStyle();
btn.onclick = toggleDarkMode;
document.querySelector("#gameInterface").append(btn);
})();
function changeBrightness() {
canvas.style.filter = `brightness(${this.value})`;
localStorage.canvasBrightness = this.value;
}
function updateToggleStyle() {
btn.style.backgroundImage = darkMode ? "url(https://i.imgur.com/UBpXB1r.png)" :
"url(https://i.imgur.com/5phmZod.png)";
}
function toggleDarkMode() {
if (!grayCanvas) {
pageHTML.classList.toggle("dark");
} else {
themes[darkMode ? 0 : 1].selected = true;
themes.dispatchEvent(new Event("change"));
}
}
function toggleCanvasDarkMode() {
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imgData.data;
for (let i = 0; i < data.length; i += 4) {
const [r, g, b] = [data[i], data[i + 1], data[i + 2]];
if (r === 255 && g === 255 && b === 255 && darkMode) {
let color = 68;
data[i] = color;
data[i + 1] = color;
data[i + 2] = color;
}
else if (r === 68 && g === 68 && b === 68 && !darkMode) {
let color = 255;
data[i] = color;
data[i + 1] = color;
data[i + 2] = color;
}
}
ctx.putImageData(imgData, 0, 0);
}
function fixColors() {
let names = document.getElementsByClassName("gameAvatarName");
updateToggleStyle();
if (!names.length)
names = document.getElementsByClassName("gameSettingsAvatarName");
for (let name of names) {
if (darkMode && name.style.color === "black") {
name.style.color = "#ccc";
} else if (!darkMode && name.style.color === "rgb(204, 204, 204)") {
name.style.color = "black";
}
}
}
const colorObserver = new MutationObserver(() => {
fixColors();
});
colorObserver.observe(document.querySelector("#gamePlayersList"), {
childList: true,
});