// ==UserScript== // @name Greasy Fork Theme Engine [BETA] // @namespace https://naeembolchhi.github.io/ // @version 0.11 // @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/* // @exclude */assets/* // @run-at document-start // @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 */ logoSVG(); 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 */ logoSVG(); 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 greasySVG = '', 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; } `.replace(/\n/g,'').replace(/\s{2}/g,' ').replace(/([\{\;\:])\s/g,'$1'); // 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; } `.replace(/\n/g,'').replace(/\s{2}/g,' ').replace(/([\{\;\:])\s/g,'$1'); // General Redesign Excluding Colors const normCSS = ` :root { --engine-border-radius: 4px; } html { font-size: 10px; } html, html > body { height: 100%; width: 100%; line-height: 1.5; -webkit-text-size-adjust: 100%; -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; } html > body { display: flex; flex-direction: column; background-color: var(--engine-body-bg); font-size: 1.6rem; } *, *::before, *::after { -webkit-tap-highlight-color: transparent; box-sizing: border-box; } a, a:visited, a:active { text-decoration: none; color: var(--engine-text-color); fill: var(--engine-text-color); } #main-header { background: var(--engine-nav-bg); color: var(--engine-text-color); box-shadow: initial; padding: 1.6rem; } #main-header > .width-constraint { height: 100%; margin: 0 auto; padding: 0; } #main-header a, #main-header a:visited, #main-header a:active { color: inherit; fill: inherit; } #site-nav { height: 100%; width: -moz-fit-content; width: fit-content; display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between; } #site-nav > nav { display: flex; gap: 16px; } #site-nav > nav a:hover { color: var(--engine-text-color); } #site-nav > nav nav { background: var(--engine-nav-bg); color: var(--engine-text-color); padding: 1.6rem; transform: translateX(1.6rem); border-radius: 0 0 var(--engine-border-radius) var(--engine-border-radius); gap: 16px; z-index: 1; } #site-nav > nav > li + li { margin: 0; } #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: 1.3rem; text-align: center; position: static; width: -moz-fit-content; width: fit-content; } #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); } #nav-user-info select, #nav-user-info input { font-size: 1.3rem; } nav a:hover + nav, nav a:focus + nav { display: flex; } nav nav:hover { display: flex; } #site-nav > nav { text-align: center; position: static; width: -moz-fit-content; width: fit-content; } #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: 0.8rem 1rem; 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: 1.6rem; width: 1.6rem; } nav .with-submenu { padding-right: 0; } nav .with-submenu > a::after { display: none; } nav .with-submenu a { position: relative; z-index: 2; } .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%; } @media screen and (max-width: 1228px) { .width-constraint { margin: 0 auto; } } body > .width-constraint { flex-grow: 1; } body > .width-constraint .all-center-home { height: 100%; width: 100%; padding: 1.6rem 1.6rem 12.8rem 1.6rem; margin: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.6rem; --_height: 5.6rem; } body > .width-constraint .all-center-home .engine-welcome { font-size: 1.5rem; } .engine-search-main { display: flex; width: 100%; height: var(--_height); max-width: calc(var(--_height) * 13.35714286); 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-main .engine-search-input { flex-grow: 1; background: transparent; border: 0; outline: 0; font-size: 1.7rem; padding: 1.3rem 0 1.3rem 1.3rem; color: var(--engine-text-color); fill: var(--engine-text-color); } .engine-search-main .engine-search-clear, .engine-search-main .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-main .engine-search-clear:hover, .engine-search-main .engine-search-clear:focus, .engine-search-main .engine-search-submit:hover, .engine-search-main .engine-search-submit:focus { fill: var(--engine-accent-color-1); } .engine-search-main .engine-search-clear { display: none; } .engine-search-main .engine-search-clear svg { height: calc(var(--_height) / 3.5); width: calc(var(--_height) / 3.5); } .engine-search-main .engine-search-submit svg { height: calc(var(--_height) / 3); width: calc(var(--_height) / 3); } .engine-search-main .engine-search-submit:hover, .engine-search-main .engine-search-submit:focus { background: rgba(0, 0, 0, 0.06); } .engine-search-main.active .engine-search-submit { background: rgba(0, 0, 0, 0.06); } .engine-search-main.active .engine-search-clear { display: flex; } #engine-top-sites { display: flex; align-items: center; justify-content: center; gap: 0.8rem; flex-wrap: wrap; width: 100%; max-width: calc(var(--_height) * 13.35714286); } #engine-top-sites a { border: 1px solid var(--engine-nav-shade); border-radius: var(--engine-border-radius); padding: 0.4rem 0.7rem; color: var(--engine-text-color); } #engine-top-sites a:hover, #engine-top-sites a:focus { color: var(--engine-accent-color-1); background: var(--engine-nav-bg); } #main-footer { padding: 1.6rem; 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: 0.4rem; } #main-footer a { color: inherit; } #main-footer a:hover, #main-footer a:focus { color: var(--engine-accent-color-1); } #main-header .width-constraint { display: flex; align-items: center; justify-content: space-between; } #main-header .width-constraint #site-name { --_rem: 0.8rem; } @media only screen and (max-width: 1536px) { #main-header .width-constraint #site-name { --_rem: calc(0.8rem + -1px); } } @media only screen and (max-width: 1280px) { #main-header .width-constraint #site-name { --_rem: calc(0.8rem + -2px); } } @media only screen and (max-width: 1024px) { #main-header .width-constraint #site-name { --_rem: calc(0.8rem + -3px); } } @media only screen and (max-width: 768px) { #main-header .width-constraint #site-name { --_rem: calc(0.8rem + -4px); } } @media only screen and (max-width: 640px) { #main-header .width-constraint #site-name { --_rem: calc(0.8rem + -5px); } } #main-header .width-constraint #site-name a.greasy-svg { height: calc(9.2 * var(--_rem)); width: calc(50 * var(--_rem)); } #main-header .width-constraint #site-name a.greasy-svg svg { height: 100%; width: auto; } #main-header .width-constraint #site-name > *:not(.greasy-svg) { display: none; } #site-name h1, #site-name a, #site-name div { display: flex; align-items: center; justify-content: center; } `; // 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("link","",{"key":["rel","href","type","id"],"val":["stylesheet","http://127.0.0.1:12428/norm.css","text/css","duskCSS"]})); 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("link","",{"key":["rel","href","type","data-temp"],"val":["stylesheet","http://127.0.0.1:12428/norm.css","text/css","duskCSS"]})); 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(); }); } // Turn the logo into SVG function logoSVG() { let logo = document.getElementById('site-name'); logo.innerHTML = ` ${greasySVG} `.replace(/>\s+<'); }