您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Change colors on Elethor.com
// ==UserScript== // @name Elethor Chameleon // @namespace http://tampermonkey.net/ // @version 2.1 // @author Eugene // @description Change colors on Elethor.com // @match *://elethor.com/* // @grant GM_addStyle // @license GPL-3.0-or-later // ==/UserScript== /* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ (function() { 'use strict'; const defaultBackgroundColor = '#202c3c'; const defaultActionBarColor = '#39444e'; const defaultTopBarColor = '#505c6c'; const defaultTextColor = '#ffffff'; const defaultWarningTextColor = '#7a3c38'; const defaultSuccessTextColor = '#52b768'; let isColorUIOpen = false; const DEBUG = true; function debug(message) { if (DEBUG) { console.log(`[Elethor Chameleon] ${message}`); } } function setColors() { debug("Setting colors"); const appElement = document.querySelector('#app[data-v-app]'); if (appElement) { const backgroundColor = localStorage.getItem('backgroundColor') || defaultBackgroundColor; appElement.style.backgroundColor = backgroundColor; backgroundColorInput.value = backgroundColor; debug("Background color set"); } else { debug("App element not found"); } const actionBarElement = document.querySelector('#currentAction'); if (actionBarElement) { const actionBarColor = localStorage.getItem('actionBarColor') || defaultActionBarColor; actionBarElement.style.backgroundColor = actionBarColor; actionBarColorInput.value = actionBarColor; debug("Action bar color set"); } else { debug("Action bar element not found"); } const topBarElement = document.querySelector('nav.navbar'); if (topBarElement) { const topBarColor = localStorage.getItem('topBarColor') || defaultTopBarColor; topBarElement.style.backgroundColor = topBarColor; topBarColorInput.value = topBarColor; debug("Top bar color set (navbar)"); } else { debug("Top bar element (navbar) not found"); } const textColor = localStorage.getItem('textColor') || defaultTextColor; document.body.style.color = textColor; textColorInput.value = textColor; applyTextColorToAll(textColor); debug("Text color set"); const warningTextColor = localStorage.getItem('warningTextColor') || defaultWarningTextColor; warningTextColorInput.value = warningTextColor; applyWarningTextColor(warningTextColor); debug("Warning text color set"); const successTextColor = localStorage.getItem('successTextColor') || defaultSuccessTextColor; successTextColorInput.value = successTextColor; applySuccessTextColor(successTextColor); debug("Success text color set"); } function saveColorsToLocalStorage() { debug("Saving colors to localStorage"); const backgroundColor = backgroundColorInput.value; const actionBarColor = actionBarColorInput.value; const topBarColor = topBarColorInput.value; const textColor = textColorInput.value; const warningTextColor = warningTextColorInput.value; const successTextColor = successTextColorInput.value; localStorage.setItem('backgroundColor', backgroundColor); localStorage.setItem('actionBarColor', actionBarColor); localStorage.setItem('topBarColor', topBarColor); localStorage.setItem('textColor', textColor); localStorage.setItem('warningTextColor', warningTextColor); localStorage.setItem('successTextColor', successTextColor); debug("Colors saved to localStorage"); } function applyTextColorToAll(color) { const elementsToColor = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'div', 'a', 'button' ]; elementsToColor.forEach(selector => { const elements = document.querySelectorAll(selector); elements.forEach(el => { if (el.closest('tr th') && el.closest('tr')?.querySelector('th:nth-child(3)')?.textContent.includes('Experience')) { return; } if (!el.className || ((!el.className.includes('text-destructive') || el.className.includes('text-destructive-foreground')) && (!el.className.includes('text-success') || el.className.includes('text-success-foreground')))) { el.style.color = color; } if (el.className && (el.className.includes('text-success-foreground') || el.className.includes('text-warning-foreground') || el.className.includes('text-destructive-foreground'))) { el.style.color = color; } }); }); } function applyWarningTextColor(color) { const warningElements = document.querySelectorAll('[class*="text-destructive"]:not([class*="text-destructive-foreground"])'); warningElements.forEach(el => { el.style.color = color; }); debug(`Applied warning color ${color} to ${warningElements.length} text elements`); const warningBgElements = document.querySelectorAll('[class*="text-destructive-foreground"], [class*="text-warning-foreground"]'); warningBgElements.forEach(el => { if (el.classList.contains('bg-destructive') || el.classList.contains('bg-warning')) { el.style.backgroundColor = color; } }); debug(`Applied warning color ${color} as background to ${warningBgElements.length} elements`); } function applySuccessTextColor(color) { const successElements = document.querySelectorAll('[class*="text-success"]:not([class*="text-success-foreground"])'); successElements.forEach(el => { el.style.color = color; }); debug(`Applied success color ${color} to ${successElements.length} text elements`); const successBgElements = document.querySelectorAll('[class*="text-success-foreground"]'); successBgElements.forEach(el => { if (el.classList.contains('bg-success')) { el.style.backgroundColor = color; } }); debug(`Applied success color ${color} as background to ${successBgElements.length} elements`); } function waitForElements() { debug("Waiting for elements"); const interval = setInterval(() => { const appElement = document.querySelector('#app[data-v-app]'); const actionBarElement = document.querySelector('#currentAction'); const topBarElement = document.querySelector('nav.navbar'); const navbar = document.querySelector('.navbar'); if (appElement) { debug("App element found"); } if (actionBarElement) { debug("Action bar element found"); } if (topBarElement) { debug("Top bar element (navbar) found"); } if (navbar) { debug("Navbar found"); } if ((appElement && actionBarElement && topBarElement) || navbar) { debug("Essential elements found or navbar present"); clearInterval(interval); setColors(); addOpenButton(); positionUI(); observePageChanges(); } }, 1000); } function addOpenButton() { debug("Adding open button"); let navbarItem = document.querySelector('a[href="/corporation"].navbar-item.is-skewed'); if (!navbarItem) { debug("Corporation link not found, trying alternate methods"); const allNavbarItems = document.querySelectorAll('.navbar-item'); if (allNavbarItems.length > 0) { navbarItem = allNavbarItems[allNavbarItems.length - 1]; debug("Using last navbar item as anchor"); } else { const navbar = document.querySelector('.navbar'); if (navbar) { debug("No navbar items found, adding to navbar directly"); const openButton = createOpenButton(); openButton.style.position = 'relative'; openButton.style.marginLeft = '10px'; navbar.appendChild(openButton); return; } else { debug("No navbar found, creating floating button"); const openButton = createOpenButton(); openButton.style.position = 'fixed'; openButton.style.top = '10px'; openButton.style.right = '10px'; openButton.style.zIndex = '10001'; document.body.appendChild(openButton); return; } } } if (navbarItem) { debug("Adding button next to navbar item"); const openButton = createOpenButton(); navbarItem.parentNode.insertBefore(openButton, navbarItem.nextSibling); } else { debug("Failed to find any suitable location for button"); } } function createOpenButton() { const openButton = document.createElement('button'); openButton.id = 'colorChangerOpenButton'; openButton.innerHTML = '🎨'; openButton.style.marginLeft = '10px'; const topBarElement = document.querySelector('nav.navbar'); const topBarColor = topBarElement ? topBarElement.style.backgroundColor : '#2596be'; openButton.style.backgroundColor = topBarColor; openButton.style.color = '#fff'; openButton.style.border = 'none'; openButton.style.padding = '5px'; openButton.style.borderRadius = '3px'; openButton.style.cursor = 'pointer'; openButton.addEventListener('click', () => { debug("Open button clicked"); uiContainer.style.display = uiContainer.style.display === 'none' ? 'flex' : 'none'; isColorUIOpen = uiContainer.style.display === 'flex'; positionUI(); }); return openButton; } function positionUI() { debug("Positioning UI"); const topBarElement = document.querySelector('nav.navbar'); if (topBarElement) { const { height } = topBarElement.getBoundingClientRect(); uiContainer.style.top = `${height + 5}px`; debug(`UI positioned at ${height + 5}px from top`); } else { uiContainer.style.top = '50px'; debug("Using fallback UI position"); } } const uiContainer = document.createElement('div'); uiContainer.id = 'colorChangerUI'; uiContainer.style.position = 'fixed'; uiContainer.style.padding = '10px'; uiContainer.style.backgroundColor = '#505c6c'; uiContainer.style.border = '1px solid #ccc'; uiContainer.style.zIndex = '10000'; uiContainer.style.display = 'none'; uiContainer.style.flexDirection = 'row'; uiContainer.style.alignItems = 'center'; uiContainer.style.whiteSpace = 'nowrap'; uiContainer.style.color = '#ffffff'; uiContainer.style.fontSize = '12px'; uiContainer.style.right = '10px'; uiContainer.style.borderRadius = '5px'; uiContainer.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)'; uiContainer.style.flexWrap = 'wrap'; uiContainer.style.maxWidth = '800px'; const backgroundColorLabel = document.createElement('label'); backgroundColorLabel.textContent = 'Background Color: '; uiContainer.appendChild(backgroundColorLabel); const backgroundColorInput = document.createElement('input'); backgroundColorInput.type = 'color'; uiContainer.appendChild(backgroundColorInput); const actionBarColorLabel = document.createElement('label'); actionBarColorLabel.textContent = 'Action Bar Color: '; actionBarColorLabel.style.marginLeft = '10px'; uiContainer.appendChild(actionBarColorLabel); const actionBarColorInput = document.createElement('input'); actionBarColorInput.type = 'color'; uiContainer.appendChild(actionBarColorInput); const topBarColorLabel = document.createElement('label'); topBarColorLabel.textContent = 'Top Bar Color: '; topBarColorLabel.style.marginLeft = '10px'; uiContainer.appendChild(topBarColorLabel); const topBarColorInput = document.createElement('input'); topBarColorInput.type = 'color'; uiContainer.appendChild(topBarColorInput); const textColorLabel = document.createElement('label'); textColorLabel.textContent = 'Text Color: '; textColorLabel.style.marginLeft = '10px'; uiContainer.appendChild(textColorLabel); const textColorInput = document.createElement('input'); textColorInput.type = 'color'; uiContainer.appendChild(textColorInput); const warningTextColorLabel = document.createElement('label'); warningTextColorLabel.textContent = 'Warning Text: '; warningTextColorLabel.style.marginLeft = '10px'; uiContainer.appendChild(warningTextColorLabel); const warningTextColorInput = document.createElement('input'); warningTextColorInput.type = 'color'; warningTextColorInput.value = defaultWarningTextColor; uiContainer.appendChild(warningTextColorInput); const successTextColorLabel = document.createElement('label'); successTextColorLabel.textContent = 'Success Text: '; successTextColorLabel.style.marginLeft = '10px'; uiContainer.appendChild(successTextColorLabel); const successTextColorInput = document.createElement('input'); successTextColorInput.type = 'color'; successTextColorInput.value = defaultSuccessTextColor; uiContainer.appendChild(successTextColorInput); const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.marginTop = '8px'; buttonContainer.style.width = '100%'; buttonContainer.style.justifyContent = 'flex-end'; uiContainer.appendChild(buttonContainer); const saveButton = document.createElement('button'); saveButton.textContent = 'Save'; saveButton.style.marginLeft = '10px'; saveButton.id = 'saveButton'; buttonContainer.appendChild(saveButton); const resetButton = document.createElement('button'); resetButton.textContent = 'Reset'; resetButton.style.marginLeft = '5px'; resetButton.id = 'resetButton'; buttonContainer.appendChild(resetButton); const exportButton = document.createElement('button'); exportButton.textContent = 'Export'; exportButton.style.marginLeft = '5px'; exportButton.style.backgroundColor = '#2596be'; exportButton.id = 'exportButton'; buttonContainer.appendChild(exportButton); const importButton = document.createElement('button'); importButton.textContent = 'Import'; importButton.style.marginLeft = '5px'; importButton.style.backgroundColor = '#2596be'; importButton.id = 'importButton'; buttonContainer.appendChild(importButton); exportButton.addEventListener('click', () => { const colorScheme = { backgroundColor: backgroundColorInput.value, actionBarColor: actionBarColorInput.value, topBarColor: topBarColorInput.value, textColor: textColorInput.value, warningTextColor: warningTextColorInput.value, successTextColor: successTextColorInput.value }; const colorSchemeString = JSON.stringify(colorScheme); navigator.clipboard.writeText(colorSchemeString) .then(() => { debug('Color scheme exported to clipboard successfully'); exportButton.textContent = '✓ Copied!'; setTimeout(() => { exportButton.textContent = 'Export'; }, 2000); }) .catch(err => { debug('Failed to copy: ' + err); exportButton.textContent = '✗ Failed'; setTimeout(() => { exportButton.textContent = 'Export'; }, 2000); }); }); importButton.addEventListener('click', async () => { try { const text = await navigator.clipboard.readText(); const colorScheme = JSON.parse(text); debug('Importing color scheme: ' + text); backgroundColorInput.value = colorScheme.backgroundColor || defaultBackgroundColor; actionBarColorInput.value = colorScheme.actionBarColor || defaultActionBarColor; topBarColorInput.value = colorScheme.topBarColor || defaultTopBarColor; textColorInput.value = colorScheme.textColor || defaultTextColor; warningTextColorInput.value = colorScheme.warningTextColor || defaultWarningTextColor; successTextColorInput.value = colorScheme.successTextColor || defaultSuccessTextColor; const appElement = document.querySelector('#app[data-v-app]'); if (appElement) { appElement.style.backgroundColor = backgroundColorInput.value; } const actionBarElement = document.querySelector('#currentAction'); if (actionBarElement) { actionBarElement.style.backgroundColor = actionBarColorInput.value; } const topBarElement = document.querySelector('nav.navbar'); if (topBarElement) { topBarElement.style.backgroundColor = topBarColorInput.value; } document.body.style.color = textColorInput.value; applyTextColorToAll(textColorInput.value); applyWarningTextColor(warningTextColorInput.value); applySuccessTextColor(successTextColorInput.value); saveColorsToLocalStorage(); importButton.textContent = '✓ Imported & Saved!'; setTimeout(() => { importButton.textContent = 'Import'; }, 2000); } catch (error) { debug('Import error: ' + error); alert('Failed to import color scheme. Please ensure the clipboard has a valid format.'); importButton.textContent = '✗ Failed'; setTimeout(() => { importButton.textContent = 'Import'; }, 2000); } }); document.body.appendChild(uiContainer); backgroundColorInput.addEventListener('input', () => { const appElement = document.querySelector('#app[data-v-app]'); if (appElement) { appElement.style.backgroundColor = backgroundColorInput.value; } }); actionBarColorInput.addEventListener('input', () => { const actionBarElement = document.querySelector('#currentAction'); if (actionBarElement) { actionBarElement.style.backgroundColor = actionBarColorInput.value; } }); topBarColorInput.addEventListener('input', () => { const topBarElement = document.querySelector('nav.navbar'); if (topBarElement) { topBarElement.style.backgroundColor = topBarColorInput.value; } }); textColorInput.addEventListener('input', () => { document.body.style.color = textColorInput.value; applyTextColorToAll(textColorInput.value); }); warningTextColorInput.addEventListener('input', () => { applyWarningTextColor(warningTextColorInput.value); }); successTextColorInput.addEventListener('input', () => { applySuccessTextColor(successTextColorInput.value); }); saveButton.addEventListener('click', () => { saveColorsToLocalStorage(); setColors(); saveButton.textContent = '✓ Saved!'; setTimeout(() => { saveButton.textContent = 'Save'; }, 2000); }); resetButton.addEventListener('click', () => { localStorage.removeItem('backgroundColor'); localStorage.removeItem('actionBarColor'); localStorage.removeItem('topBarColor'); localStorage.removeItem('textColor'); localStorage.removeItem('warningTextColor'); localStorage.removeItem('successTextColor'); setColors(); resetButton.textContent = '✓ Reset!'; setTimeout(() => { resetButton.textContent = 'Reset'; }, 2000); }); GM_addStyle(` #colorChangerUI input[type="color"] { cursor: pointer; margin-left: 5px; border: none; height: 20px; width: 20px; padding: 0; background: none; } #colorChangerUI button { cursor: pointer; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; font-size: 12px; transition: all 0.2s ease; } #colorChangerUI button:hover { opacity: 0.8; transform: translateY(-1px); } #colorChangerUI button:active { transform: translateY(1px); } #saveButton { background-color: #4CAF50 !important; } #resetButton { background-color: #f44336 !important; } #exportButton, #importButton { background-color: #2196F3 !important; } #colorChangerOpenButton { transition: transform 0.2s ease !important; } #colorChangerOpenButton:hover { transform: scale(1.1) !important; } #colorChangerUI label { margin-left: 10px; } #colorChangerUI label:first-child { margin-left: 0; } `); function observePageChanges() { debug("Starting page observer"); const observer = new MutationObserver((mutations) => { let needsUpdate = false; let hasDestructiveText = false; let hasSuccessText = false; let hasForegroundClasses = false; mutations.forEach((mutation) => { if (mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { if (node.className && node.className.includes) { if (node.className.includes('text-destructive')) { hasDestructiveText = true; } if (node.className.includes('text-success')) { hasSuccessText = true; } if (node.className.includes('text-success-foreground') || node.className.includes('text-warning-foreground') || node.className.includes('text-destructive-foreground')) { hasForegroundClasses = true; } } const destructiveElements = node.querySelectorAll('[class*="text-destructive"]'); if (destructiveElements.length > 0) { hasDestructiveText = true; } const successElements = node.querySelectorAll('[class*="text-success"]'); if (successElements.length > 0) { hasSuccessText = true; } const foregroundElements = node.querySelectorAll( '[class*="text-success-foreground"], [class*="text-warning-foreground"], [class*="text-destructive-foreground"]' ); if (foregroundElements.length > 0) { hasForegroundClasses = true; } } }); if (hasDestructiveText || hasForegroundClasses) { debug("Found new text-destructive or foreground elements, applying warning color"); applyWarningTextColor(warningTextColorInput.value); } if (hasSuccessText || hasForegroundClasses) { debug("Found new text-success or foreground elements, applying success color"); applySuccessTextColor(successTextColorInput.value); } if (hasForegroundClasses) { debug("Found new foreground elements, applying text color"); applyTextColorToAll(textColorInput.value); } needsUpdate = true; } }); if (needsUpdate) { debug("Page changed, reapplying colors"); if (!isColorUIOpen) { setColors(); } else { debug("UI is open - skipping setColors() to prevent overriding user selections"); } if (!document.querySelector('#colorChangerOpenButton')) { debug("Button disappeared, adding again"); addOpenButton(); } } }); observer.observe(document.body, { childList: true, subtree: true }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', waitForElements); } else { waitForElements(); } })();