// ==UserScript== // @name winterify cohost // @namespace datagirl.xyz // @match https://cohost.org/* // @grant none // @version 1.6.1 // @author snow flurry // @description 11/14/2022, 1:16:16 PM // ==/UserScript== // Changelog: // 1.5: // - Use a MutationObserver instead of Interval (less brute forcing) // - Removed foreground snow effect (() => { // if you want snowfall mode to run by default, set this to true. const defaultOn = true; const divId = 'userscript-snowfall'; function makeWinter() { let activateBtn = document.createElement("button"); activateBtn.innerHTML = "❄️"; activateBtn.id = "userscript-winterify-activate"; activateBtn.style.padding = "0.5em 0.75em"; // only create the snowfall if it doesn't already exist // (so we don't mess up the DOM more than we already are) let snowfall = document.getElementById(divId); if (snowfall == null) { let snowfall = document.createElement("div"); snowfall.id = divId; snowfall.style.position = "fixed"; snowfall.style.top = snowfall.style.bottom = snowfall.style.left = snowfall.style.right = "0"; snowfall.style.pointerEvents = "none"; const setBg = (snowfall, isDark) => { // this darkens the background, but the 20% opacity (hopefully!) doesn't darken it too much. darkMode = isDark ? "" : "#000"; snowfall.style.background = `url('https://staging.cohostcdn.org/attachment/cc9ae945-a270-4059-8992-70f74128c332/snowfall_anim.gif') ${darkMode}`; }; snowfall.style.opacity = "0.2"; snowfall.style.zIndex = "-1"; snowfall.style.display = defaultOn ? "block" : "none"; setBg(snowfall); // try to respond to light and dark modes if (window.matchMedia) { const darkMatch = window.matchMedia('(prefers-color-scheme: dark)'); setBg(snowfall, darkMatch.matches); darkMatch.addEventListener('change', (ev) => { setBg(snowfall, ev.matches); }); // and append it to the body document.body.append(snowfall); } else { // assume dark, I guess? setBg(snowfall, true); } activateBtn.addEventListener("click", function(ev) { let snowfall = document.getElementById(divId); ev.target.innerHTML = "❄️"; snowfall.style.display = (snowfall.style.display == "none") ? "block" : "none"; }); let nav = document.querySelector("nav"); if (nav != null) { nav.prepend(activateBtn); } } } // TODO: this feels like a bad idea, but I wasn't able to find a better way // to handle this by messing with __reactContainer$[bytes]. If you know of a // better way, send an ask on cohost (@flurry) pls! const app = document.getElementById("app"); const observer = new MutationObserver(() => { if (document.getElementById(divId) == null) { makeWinter(); } }); observer.observe(app, { subtree: true, childList: true }); })();