Skip to content

Instantly share code, notes, and snippets.

@b0o
Last active March 22, 2021 03:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save b0o/acf9a27bce427f4d456b9a12acb92fe3 to your computer and use it in GitHub Desktop.
Save b0o/acf9a27bce427f4d456b9a12acb92fe3 to your computer and use it in GitHub Desktop.
auto-darkmode.user.js
// ==UserScript==
// @name Auto darkmode
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Toggle darkmode on supported sites based on your OS's darkmode setting
// @author You
// @match https://www.tradingview.com/chart/*
// @match https://www.coinex.com/*
// @exclude https://www.coinex.com/assets/trading_chart/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const sites = []
/*** CoinEx ***/
sites.push({
hostnames: ["www.coinex.com"],
fn: async (state) => {
const checkDarkmode = () => document.children[0].classList.contains("theme-night") == state
if (checkDarkmode()) return
const switchMode = async (themeSwitcher) => {
if (checkDarkmode()) return true
themeSwitcher.click()
return until(checkDarkmode)
}
const getThemeSwitcher = async () => until(
() => document.querySelector(".icon-day, .icon-night"), { interval: 20, maxAttempts: 10 })
const themeSwitcher = await getThemeSwitcher()
return switchMode(themeSwitcher)
}
})
/*** TradingView ***/
sites.push({
hostnames: ["www.tradingview.com"],
fn: async (state) => {
const checkDarkmode = () => document.children[0].classList.contains("theme-dark") == state
if (checkDarkmode()) return
const switchMode = async (themeSwitcher) => {
if (checkDarkmode()) return true
themeSwitcher.click()
return until(checkDarkmode)
}
const toggleMenu = async (menuButton, state) => {
const query = () => !!document.querySelector("#theme-switcher") === !!state
const q = query()
if (q) return q
menuButton.click()
return until(query)
}
const tryGetThemeSwitcher = () => document.querySelector("#theme-switcher")
const getThemeSwitcher = async () => until(tryGetThemeSwitcher)
const getMenuButton = async () => until(
() => document.querySelector("*[class*='topLeftButton-'] div[data-role=button]"), { interval: 100, maxAttempts: 300 })
const menuButton = await getMenuButton()
let themeSwitcher = tryGetThemeSwitcher()
const initialMenuState = !!themeSwitcher
if (!initialMenuState) {
await toggleMenu(menuButton, true)
themeSwitcher = await getThemeSwitcher()
}
await switchMode(themeSwitcher)
if (!initialMenuState) await toggleMenu(menuButton, false)
}
})
const until = (check, options = {}) => new Promise((resolve, reject) => {
const opts = {
test: (a) => a,
maxAttempts: 50,
interval: 50,
...options,
}
const f = (attempts = 0) => {
const res = check()
if (!opts.test(res)) {
if (attempts > opts.maxAttempts) {
reject(new Error(`until: timeout: ${check}`))
} else {
setTimeout(() => f(attempts + 1), opts.interval)
}
return
}
resolve(res)
}
f()
})
const getSite = (hostname = location.hostname) => {
for (let s of sites) {
for (let h of s.hostnames) {
switch (h.constructor.name) {
case "String":
if (h === hostname) return s
break
case "RegExp":
if (h.test(hostname)) return s
break
case "URL":
if (h.hostname === hostname) return s
break
}
}
}
}
const run = () => {
const site = getSite()
if (!site) return
const mq = window.matchMedia('(prefers-color-scheme: dark)')
mq.addEventListener("change", (e) => site.fn(e.matches))
site.fn(mq.matches)
}
run()
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment