// ==UserScript== // @name Greasy Fork Theme Engine [BETA] // @namespace https://naeembolchhi.github.io/ // @version 0.8 // @description A sleek Geasy Fork redesign with support for custom colors. Supports both light mode and dark mode. // @author NaeemBolchhi // @license GPL-3.0-or-later // @icon data:image/svg+xml;utf8, // @match https://greasyfork.org/* // @match https://sleazyfork.org/* // @run-at document-start // @grant GM_addStyle // @downloadURL none // ==/UserScript== // Main event initiator. (function() { 'use strict'; // Set default theme to dark if theme choice is unavailable. if (!localStorage.getItem('theme')) {localStorage.setItem('theme',"dark");} // Only initiate theme engine if the URL doesn't match. if (window.location.pathname != "/theme") { // Pendulum const pendulum = setInterval(function () { try { if (!document.querySelector('head')) { return; } themeStyles(true); // if favicon } catch(e) {console.error("early-load-failed");catchErrors(e);} }, 100); // Only execute if window is interactive or fully loaded at this point. if (document.readyState === 'interactive' || document.readyState === 'complete') { setTimeout((function() { clearInterval(pendulum); themeStyles(); removeStyles(); // check theme choice in localstorage // any favicon function // add the toggle for theme changing /* DOM Changes START */ addFOOTER(); forkNAV(); forkHOME(); /* DOM Changes END */ // fix favicon again, just in case loadTime(); }), 100); } // Modifying head when available. let observer = new MutationObserver(function() { if (document.body) { clearInterval(pendulum); themeStyles(); removeStyles(); // any favicon function observer.disconnect(); } }); observer.observe(document.documentElement, {childList: true, subtree: true}); // Execute DOM modifications when ready state changes. document.onreadystatechange = function () { // Modify body when document is interactive. if (document.readyState === 'interactive') { // check theme choice in localstorage // add the toggle for theme changing /* DOM Changes */ addFOOTER(); forkNAV(); forkHOME(); } // Modify body when document is complete. if (document.readyState === 'complete') { // fix favicon again, just in case loadTime(); } } } })(); // Catch errors. function catchErrors(e) { console.log(e instanceof TypeError) console.log(e.message) console.log(e.name) console.log(e.fileName) console.log(e.lineNumber) console.log(e.columnNumber) console.log(e.stack) } // SVG Icons const forumSVG = '', helpSVG = '', librarySVG = '', logSVG = '', otherSVG = '', scriptSVG = '', searchSVG = '', userSVG = '', clearSVG = '', findSVG = ''; // Function for inserting new elements in the DOM. function elemake(tag, innr, attr) { let element = document.createElement(tag); if (innr) {element.innerHTML = innr;} if (!attr) {return element;} for (let x = 0; x < attr.key.length; x++) { element.setAttribute(attr.key[x], attr.val[x]); } return element; } // Dark Theme Colors const duskCSS = ` :root { --engine-body-bg: #fbfbfb; --engine-nav-bg: #f6f6f6; --engine-nav-shade: #e0e0e0; --engine-text-color: #000000; --engine-accent-color-1: #a42121; } `; // Light Theme Colors const dawnCSS = ` :root { --engine-body-bg: #ffffff; --engine-nav-bg: #f6f6f6; --engine-nav-shade: #e0e0e0; --engine-text-color: #000000; --engine-accent-color-1: #a42121; } `; // General Redesign Excluding Colors const normCSS = ` :root { --engine-border-radius: 4px; } html, :host { line-height: 1.5; -webkit-text-size-adjust: 100%; -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-feature-settings: normal; font-variation-settings: normal; } *, *::before, *::after { -webkit-tap-highlight-color: transparent; } html, body { height: 100%; body: 100%; } body { display: flex; flex-direction: column; background-color: var(--engine-body-bg); } a { text-decoration: none; } #main-header { background: var(--engine-nav-bg); color: var(--engine-text-color); box-shadow: initial; padding: 1rem 0; } #main-header, #main-header a, #main-header a:visited, #main-header a:active { text-decoration: none; color: var(--engine-text-color); fill: var(--engine-text-color); } #main-header > .width-constraint { display: flex; align-items: center; justify-content: space-between; height: 100%; } #site-nav > nav a:hover { color: var(--engine-body-text); } #language-selector-locale { background: transparent; border: 1px solid var(--engine-nav-shade); border-radius: var(--engine-border-radius); cursor: pointer; } #language-selector-locale:hover, #language-selector-locale:focus { color: var(--engine-accent-color-1); background: var(--engine-nav-shade); } #nav-user-info { display: flex; gap: .8rem; } #nav-user-info select, #nav-user-info input { font-size: .8rem; } #nav-user-info .sign-in-link a { display: block; padding: 1px 6px; border: 1px solid var(--engine-nav-shade); border-radius: var(--engine-border-radius); color: var(--engine-text-color); text-decoration: none; } #nav-user-info .sign-in-link a:hover, #nav-user-info .sign-in-link a:focus { background: var(--engine-nav-shade); color: var(--engine-accent-color-1); } #site-nav > nav nav { background: var(--engine-nav-bg); color: var(--engine-text-color); padding: 1rem; transform: translateX(1rem); border-radius: 0 0 var(--engine-border-radius) var(--engine-border-radius); } #site-nav > nav { display: flex; gap: 16px; } nav a:hover + nav, nav nav:hover, nav a:focus + nav { display: flex; } #site-nav { height: 100%; width: fit-content; display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between; } #site-nav > nav, #nav-user-info { text-align: center; position: static; width: fit-content; } #site-nav > nav nav { gap: 16px; } #site-nav > nav > li + li { margin: 0; } #site-nav > nav > li > a, #site-nav > nav nav > li > a { display: flex; flex-direction: row; align-content: center; justify-content: center; line-height: 1; gap: 6px; border: 1px solid var(--engine-nav-shade); padding: .5rem .65rem; border-radius: var(--engine-border-radius); } #site-nav > nav > li > a:hover, #site-nav > nav > li > a:focus, #site-nav > nav nav > li > a:hover, #site-nav > nav nav > li > a:focus { color: var(--engine-accent-color-1); fill: var(--engine-accent-color-1); background: var(--engine-nav-shade); } #site-nav > nav > li > a > svg, #site-nav > nav nav > li > a > svg { height: 16px; width: auto; } nav .with-submenu { padding-right: 0; } nav .with-submenu > a::after { display: none; } nav .with-submenu a { position: relative; z-index: 2; } #site-nav > nav nav { z-index: 1; } .script-list, .user-list, .text-content, .discussion-list, .list-option-group ul, #script-info { border-color: transparent; box-shadow: initial; background: var(--engine-body-bg); } .width-constraint { width: 100%; } .engine-search-main { --height: 3.5rem; display: flex; width: 100%; height: var(--height); max-width: 46.75rem; background: var(--engine-nav-bg); border-radius: var(--engine-border-radius); overflow: hidden; box-shadow: 0 3px 0 0 var(--engine-nav-shade); } .engine-search-input { flex-grow: 1; background: transparent; border: 0; outline: 0; font-size: 1.1rem; padding: .8rem 0 .8rem .8rem; color: var(--engine-text-color); fill: var(--engine-text-color); } .engine-search-clear, .engine-search-submit { height: var(--height); width: calc(var(--height) * 1.2); background: transparent; border: 0; outline: 0; display: flex; align-items: center; justify-content: center; cursor: pointer; } .engine-search-clear { display: none; } .engine-search-clear svg { height: calc(var(--height) / 3.5); width: auto; } .engine-search-submit svg { height: calc(var(--height) / 3); width: auto; } .engine-search-clear:hover, .engine-search-clear:focus { fill: var(--engine-accent-color-1); } .engine-search-submit:hover, .engine-search-submit:focus { background: rgba(0,0,0,0.06); fill: var(--engine-accent-color-1); } .engine-search-main.active .engine-search-submit { background: rgba(0,0,0,0.06); } .engine-search-main.active .engine-search-clear { display: flex; } .all-center-home { height: 100%; width: 100%; padding: 1rem 1rem 8rem 1rem; margin: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; } #engine-top-sites { display: flex; align-items: center; justify-content: center; gap: .5rem; margin-top: 1rem; flex-wrap: wrap; width: 100%; max-width: 46.75rem; } #engine-top-sites a { border: 1px solid var(--engine-nav-shade); border-radius: var(--engine-border-radius); padding: .25rem .35rem; color: var(--engine-body-text); } #engine-top-sites a:hover, #engine-top-sites a:focus { color: var(--engine-accent-color-1); background: var(--engine-nav-bg); } #main-footer { padding: 1rem; background: var(--engine-nav-bg); } #main-footer .width-constraint { display: flex; align-items: center; justify-content: space-between; } #main-footer .width-constraint > span:first-of-type { display: flex; gap: 4px; } #main-footer a { color: var(--engine-body-text); } #main-footer a:hover, #main-footer a:focus { color: var(--engine-accent-color-1); } .engine-welcome { margin-bottom: 1rem; font-size: 1.1rem; } #site-name { display: flex; gap: .5rem; width: fit-content; } `; // Remove Bruteforced Styles function removeStyles() { let styleTMP = document.querySelectorAll('head style[data-temp]'); for (let x = 0; x < styleTMP.length; x++) { styleTMP[x].remove(); } } // Regular Styles function themeStyles(temp) { if (document.querySelector('#normCSS')) {return;} if (!temp) { document.head.appendChild(elemake("style",normCSS,{"key":["type","id"],"val":["text/css","normCSS"]})); document.head.appendChild(elemake("style",duskCSS,{"key":["type","id"],"val":["text/css","duskCSS"]})); document.head.appendChild(elemake("style",dawnCSS,{"key":["type","id"],"val":["text/css","dawnCSS"]})); } else { document.head.appendChild(elemake("style",normCSS,{"key":["type","data-temp"],"val":["text/css","normCSS"]})); document.head.appendChild(elemake("style",duskCSS,{"key":["type","data-temp"],"val":["text/css","duskCSS"]})); document.head.appendChild(elemake("style",dawnCSS,{"key":["type","data-temp"],"val":["text/css","dawnCSS"]})); } } // Calculate loading time. function loadTime() { let loadTime = window.performance.timing.domContentLoadedEventEnd - window.performance.timing.navigationStart; try { document.querySelector('#main-footer .width-constraint > span:nth-of-type(2)').innerHTML = 'Loaded in ' + (loadTime/1000).toFixed(2) + ' secs'; } catch {} } // Add a simple footer on EVERY page function addFOOTER() { let footer = `
Greasy Fork | GPL-3.0 •••
`.replace(/>\s+<'); document.body.appendChild(elemake("footer",footer,{"key":["id"],"val":["main-footer"]})); } // Update NAV with Icons function forkNAV() { let navList = document.querySelector('#site-nav > nav'), scriptL = navList.querySelector('.scripts-index-link a'), forumL = navList.querySelector('.forum-link a'), otherL = navList.querySelector('.with-submenu a'), helpL = navList.querySelector('.help-link'); scriptL.innerHTML = scriptSVG + '' + scriptL.innerText + ''; forumL.innerHTML = forumSVG + '' + forumL.innerText + ''; otherL.innerHTML = otherSVG + '' + otherL.innerText + ''; helpL.innerHTML = '' + helpSVG + '' + helpL.innerText + ''; let searchL = navList.querySelector('nav li a[href$="/search"]'), userL = navList.querySelector('nav li a[href$="/users"]'), libraryL = navList.querySelector('nav li a[href$="/libraries"]'), logL = navList.querySelector('nav li a[href$="/moderator_actions"]'); searchL.innerHTML = searchSVG + '' + searchL.innerText.replace('Advanced search','Search') + ''; userL.innerHTML = userSVG + '' + userL.innerText.replace('User list','Users') + ''; libraryL.innerHTML = librarySVG + '' + libraryL.innerText + ''; logL.innerHTML = logSVG + '' + logL.innerText.replace('Moderator log','Mod Logs') + ''; } // Update HOMEPAGE with new Search function forkHOME() { if (!document.getElementById('home-script-nav')) {return;} let topSites = document.querySelectorAll('#home-top-sites a'), siteTags = ''; for (let x = 0; x < topSites.length; x++) { siteTags = siteTags + topSites[x].outerHTML; } document.querySelector('body > div.width-constraint > section.text-content').innerHTML = ` What are we forking today?
${clearSVG} ${findSVG}
${siteTags}
`.replace(/>\s+<'); let input = document.querySelector('.engine-search-input'), clear = document.querySelector('.engine-search-clear'), submit = document.querySelector('.engine-search-submit'); input.parentNode.parentNode.classList.add('all-center-home'); function checkInput() { if (input.value === '') { input.parentNode.classList.remove('active'); } else { input.parentNode.classList.add('active'); } } input.addEventListener('input', checkInput); clear.addEventListener('click', function() { clear.parentNode.children[0].value = ''; checkInput(); clear.parentNode.children[0].focus(); }); submit.addEventListener('click', function() { submit.parentNode.submit(); }); logoHOME(); } // Clickable HOMEPAGE logo function logoHOME() { let logo = document.getElementById('site-name'); if (logo.querySelector('a')) {return;} let limg = logo.querySelector('img'), ltxt = logo.querySelector('h1'); logo.insertBefore(elemake("a","",{"key":["href"],"val":["/"]}), logo.children[logo.children.length-1]); logo.querySelector('a').appendChild(limg); let ltxtTMP = ltxt.innerText; ltxt.innerText = ""; ltxt.appendChild(elemake("a",ltxtTMP,{"key":["href"],"val":["/"]})); }