您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a theme switcher to grok.com with dark, cyberpunk, light, blood red, midnight, deep ocean, celestial, and divine modes, foldable picker with animations, draggable, and script editor compatibility. Enhanced query-bar opacity fix to 75% with broader selectors and debug logging.
- // ==UserScript==
- // @name Grok.com Theme Switcher
- // @namespace http://violentmonkey.github.io/
- // @version 1.2
- // @description Adds a theme switcher to grok.com with dark, cyberpunk, light, blood red, midnight, deep ocean, celestial, and divine modes, foldable picker with animations, draggable, and script editor compatibility. Enhanced query-bar opacity fix to 75% with broader selectors and debug logging.
- // @author virtualdmns
- // @license MIT
- // @match https://grok.com/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- console.log('Grok Theme Switcher: Script loaded.');
- // Define theme styles
- const themes = {
- dark: {
- background: '#1a1a1a',
- text: '#e0e0e0',
- accent: '#00ff88',
- buttonBg: '#333',
- buttonText: '#fff'
- },
- cyberpunk: {
- background: '#0d0221',
- text: '#ff00ff',
- accent: '#00f7ff',
- buttonBg: '#2a0a3b',
- buttonText: '#ff00ff'
- },
- light: {
- background: '#f5f5f5',
- text: '#333',
- accent: '#007bff',
- buttonBg: '#ddd',
- buttonText: '#000'
- },
- bloodred: {
- background: '#2e0000',
- text: '#ff6666',
- accent: '#800000',
- buttonBg: '#4a0000',
- buttonText: '#ff9999'
- },
- midnight: {
- background: '#0a0a1c',
- text: '#c0c0d9',
- accent: '#4b4bff',
- buttonBg: '#1c1c2e',
- buttonText: '#e6e6ff'
- },
- deepocean: {
- background: '#0a2424',
- text: '#66cccc',
- accent: '#00b7eb',
- buttonBg: '#1a3c3c',
- buttonText: '#99e6e6'
- },
- celestial: {
- background: '#1b0a3b',
- text: '#ffd700',
- accent: '#b266ff',
- buttonBg: '#2e1a5c',
- buttonText: '#ffeb99'
- },
- divine: {
- background: '#f5f6f5',
- text: '#4682b4',
- accent: '#c0c0c0',
- buttonBg: '#e6e6fa',
- buttonText: '#191970'
- }
- };
- // Debug function to check query-bar opacity
- function debugQueryBarOpacity() {
- const queryBar = document.querySelector('div[class*="query-bar"]');
- if (queryBar) {
- const computedStyle = window.getComputedStyle(queryBar);
- console.log(`Grok Theme Switcher: Query bar opacity is ${computedStyle.opacity}`);
- } else {
- console.log('Grok Theme Switcher: Query bar not found in DOM.');
- }
- }
- // Inject CSS to avoid CSP issues
- function injectStyles(themeName) {
- console.log(`Grok Theme Switcher: Injecting styles for theme - ${themeName}`);
- const theme = themes[themeName];
- let styleTag = document.getElementById('theme-styles');
- if (!styleTag) {
- styleTag = document.createElement('style');
- styleTag.id = 'theme-styles';
- document.head.appendChild(styleTag);
- }
- styleTag.textContent = `
- @keyframes fade-slide {
- from { opacity: 0; transform: translateY(10px); }
- to { opacity: 1; transform: translateY(0); }
- }
- @keyframes scale-pop {
- from { transform: scale(0.5); opacity: 0; }
- to { transform: scale(1); opacity: 1; }
- }
- @keyframes pulse {
- 0% { transform: scale(1); }
- 50% { transform: scale(1.1); }
- 100% { transform: scale(1); }
- }
- body {
- background-color: ${theme.background} !important;
- color: ${theme.text} !important;
- animation: fade-slide 0.5s ease !important;
- }
- p, span, div:not([class*="editor"]), h1, h2, h3, h4, h5, h6, li, a:not([class*="button"]), img {
- color: ${theme.text} !important;
- background-color: transparent !important;
- border: none !important;
- animation: fade-slide 0.5s ease !important;
- }
- button:not([class*="editor"]), input[type="button"], input[type="submit"], [role="button"]:not([class*="editor"]) {
- background-color: ${theme.buttonBg} !important;
- color: ${theme.buttonText} !important;
- border: none !important;
- transition: all 0.3s ease !important;
- animation: fade-slide 0.5s ease !important;
- }
- div[class*="query-bar"] {
- opacity: 0.75 !important;
- transition: opacity 0.3s ease !important;
- background-color: ${theme.background} !important;
- }
- div[class*="query-bar"] textarea, div[class*="query-bar"] button, div[class*="query-bar"] div {
- background-color: ${theme.background} !important;
- opacity: 1 !important;
- }
- #theme-switcher {
- position: fixed !important;
- z-index: 9999 !important;
- background-color: rgba(0, 0, 0, 0.7) !important;
- padding: 10px !important;
- border-radius: 8px !important;
- cursor: move !important;
- animation: scale-pop 0.3s ease !important;
- display: block !important;
- }
- #theme-switcher.hidden {
- display: none !important;
- }
- #themeSelect {
- padding: 8px !important;
- border-radius: 4px !important;
- cursor: pointer !important;
- background: #fff !important;
- color: #000 !important;
- }
- #theme-toggle-btn {
- position: fixed !important;
- z-index: 9999 !important;
- background-color: rgba(0, 0, 0, 0.7) !important;
- color: #fff !important;
- padding: 8px 12px !important;
- border-radius: 4px !important;
- cursor: pointer !important;
- font-size: 14px !important;
- animation: pulse 2s infinite ease !important;
- display: none !important;
- }
- #theme-toggle-btn.visible {
- display: block !important;
- }
- `;
- console.log('Grok Theme Switcher: Applied opacity 0.75 to query-bar');
- setTimeout(debugQueryBarOpacity, 500); // Check opacity after styles apply
- }
- // Force toggle state
- function forceToggleState(switcher, toggleBtn, isFolded) {
- console.log(`Grok Theme Switcher: Forcing toggle state - folded: ${isFolded}`);
- switcher.classList.toggle('hidden', isFolded);
- toggleBtn.classList.toggle('visible', isFolded);
- localStorage.setItem('themePickerFolded', isFolded.toString());
- }
- // Create floating theme switcher UI
- function createSwitcher() {
- console.log('Grok Theme Switcher: Creating switcher UI.');
- if (document.getElementById('theme-switcher') || document.getElementById('theme-toggle-btn')) {
- console.log('Grok Theme Switcher: Switcher or toggle already exists, skipping.');
- return;
- }
- // Create toggle button
- const toggleBtn = document.createElement('button');
- toggleBtn.id = 'theme-toggle-btn';
- toggleBtn.textContent = 'Theme';
- document.body.appendChild(toggleBtn);
- // Create theme switcher
- const switcher = document.createElement('div');
- switcher.id = 'theme-switcher';
- switcher.innerHTML = `
- <select id="themeSelect">
- <option value="dark">Dark</option>
- <option value="cyberpunk">Cyberpunk</option>
- <option value="light">Light</option>
- <option value="bloodred">Blood Red</option>
- <option value="midnight">Midnight</option>
- <option value="deepocean">Deep Ocean</option>
- <option value="celestial">Celestial</option>
- <option value="divine">Divine</option>
- </select>
- `;
- // Load saved position or default
- let savedPos = JSON.parse(localStorage.getItem('themePickerPos'));
- if (!savedPos || !savedPos.left || !savedPos.top) {
- savedPos = { top: 'auto', bottom: '20px', left: 'auto', right: '20px' };
- }
- Object.assign(switcher.style, savedPos);
- Object.assign(toggleBtn.style, savedPos);
- // Load folded state
- const isFolded = localStorage.getItem('themePickerFolded') === 'true';
- document.body.appendChild(switcher);
- forceToggleState(switcher, toggleBtn, isFolded);
- // Event listener for theme change
- const themeSelect = document.getElementById('themeSelect');
- themeSelect.addEventListener('change', (e) => {
- console.log(`Grok Theme Switcher: Theme selected - ${e.target.value}`);
- injectStyles(e.target.value);
- localStorage.setItem('grokTheme', e.target.value);
- });
- // Event listener for toggle button
- toggleBtn.addEventListener('click', () => {
- console.log('Grok Theme Switcher: Toggle clicked.');
- const isCurrentlyFolded = switcher.classList.contains('hidden');
- forceToggleState(switcher, toggleBtn, !isCurrentlyFolded);
- });
- // Draggable functionality for both switcher and button
- function makeDraggable(element, isButton) {
- let isDragging = false;
- let offsetX, offsetY;
- element.addEventListener('mousedown', (e) => {
- isDragging = true;
- offsetX = e.offsetX;
- offsetY = e.offsetY;
- console.log(`Grok Theme Switcher: Starting drag on ${isButton ? 'button' : 'switcher'}.`);
- });
- document.addEventListener('mousemove', (e) => {
- if (isDragging) {
- let newLeft = e.clientX - offsetX;
- let newTop = e.clientY - offsetY;
- // Keep within viewport
- const rect = element.getBoundingClientRect();
- newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - rect.width));
- newTop = Math.max(0, Math.min(newTop, window.innerHeight - rect.height));
- element.style.left = `${newLeft}px`;
- element.style.top = `${newTop}px`;
- element.style.right = 'auto';
- element.style.bottom = 'auto';
- // Sync other element
- const otherElement = isButton ? switcher : toggleBtn;
- otherElement.style.left = `${newLeft}px`;
- otherElement.style.top = `${newTop}px`;
- otherElement.style.right = 'auto';
- otherElement.style.bottom = 'auto';
- }
- });
- document.addEventListener('mouseup', () => {
- if (isDragging) {
- isDragging = false;
- const pos = {
- top: element.style.top,
- bottom: element.style.bottom,
- left: element.style.left,
- right: element.style.right
- };
- localStorage.setItem('themePickerPos', JSON.stringify(pos));
- console.log(`Grok Theme Switcher: Position saved.`, pos);
- }
- });
- }
- makeDraggable(switcher, false);
- makeDraggable(toggleBtn, true);
- const savedTheme = localStorage.getItem('grokTheme') || 'bloodred';
- themeSelect.value = savedTheme;
- injectStyles(savedTheme);
- }
- // Mutation observer for dynamic content
- function observeDOM() {
- console.log('Grok Theme Switcher: Setting up DOM observer.');
- const observer = new MutationObserver(() => {
- console.log('Grok Theme Switcher: DOM changed, reapplying theme.');
- const savedTheme = localStorage.getItem('grokTheme') || 'bloodred';
- injectStyles(savedTheme);
- debugQueryBarOpacity();
- const switcher = document.getElementById('theme-switcher');
- const toggleBtn = document.getElementById('theme-toggle-btn');
- if (switcher && toggleBtn) {
- const isFolded = localStorage.getItem('themePickerFolded') === 'true';
- forceToggleState(switcher, toggleBtn, isFolded);
- } else if (!switcher && !toggleBtn) {
- console.log('Grok Theme Switcher: Switcher missing, recreating.');
- createSwitcher();
- }
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- attributes: true,
- attributeFilter: ['class', 'style']
- });
- }
- // Wait for DOM to be ready
- function waitForBody() {
- if (document.body) {
- initialize();
- } else {
- console.log('Grok Theme Switcher: Body not ready, polling...');
- setTimeout(waitForBody, 100);
- }
- }
- // Start when DOM is ready or poll if not
- function initialize() {
- console.log('Grok Theme Switcher: Initializing.');
- createSwitcher();
- observeDOM();
- }
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', waitForBody);
- } else {
- waitForBody();
- }
- })();