Greasy Fork

Greasy Fork is available in English.

Claude Interface Enhancement v2

Adds colorful icons to Claude and Gemini buttons, colors bold/italic text, and adds smooth visual effects throughout both interfaces.

当前为 2025-11-08 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Claude Interface Enhancement v2
// @description  Adds colorful icons to Claude and Gemini buttons, colors bold/italic text, and adds smooth visual effects throughout both interfaces.
// @version      2
// @namespace    ClaudeEnhancement
// @icon         https://www.google.com/s2/favicons?sz=64&domain=claude.ai
// @match        https://claude.ai/*
// @match        https://claude.ai/chat/*
// @match        https://gemini.google.com/*
// @match        https://gemini.google.com/app/*
// @run-at       document-start
// @grant        none
// @license      AGPL-3.0-or-later
// ==/UserScript==

(() => {
    'use strict';

    // ===== Configuration =====
    const CONFIG = {
        shortcuts: {
            newChat: {
                key: 'n',
                modifierRequired: true // Ctrl/Cmd required
            }
        },
        selectors: {
            newChat: [
                // Claude selectors
                'button[aria-label*="new chat" i]',
                'button[aria-label*="start" i]',
                'a[href="/"]',
                'button:has(svg path[d*="M12 4"])',
                // Gemini selectors
                'button[aria-label*="new chat" i]',
                'button[jsname*="r8qRAd"]',
                'a[href="/app"]'
            ]
        },
        animations: {
            enabled: true,
            duration: '0.3s',
            fadeInDuration: '0.6s'
        }
    };

    const COLORS = {
        ORANGE: 'darkorange',
        GREEN: 'springgreen',
        LIME: 'limegreen',
        DARK_GREEN: '#00ad00',
        RED: 'crimson',
        DESTRUCTIVE: '#e02e2a',
        YELLOW: 'gold',
        INDIGO: 'indigo',
        GRAY: 'gray',
        DIMGRAY: 'dimgray',
        SKYBLUE: 'deepskyblue',
        BLUE: '#4285f4',
        VIOLET: 'darkviolet',
        PURPLE: '#9c27b0',
        CYAN: '#00bcd4',
        PINK: '#e91e63',
        TEAL: '#009688'
    };

    const OPACITY = {
        HIGH: '0.9',
        MEDIUM: '0.8',
        LOW: '0.7',
        FULL: '1'
    };

    // ===== Styles =====
    const STYLES = `
        /**************************************
                Animations & Keyframes
        **************************************/

        @keyframes claude-fade-in {
            from {
                opacity: 0;
                transform: translateY(10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        @keyframes claude-pulse {
            0%, 100% {
                opacity: 1;
            }
            50% {
                opacity: 0.7;
            }
        }

        @keyframes claude-glow {
            0%, 100% {
                box-shadow: 0 0 5px currentColor;
            }
            50% {
                box-shadow: 0 0 20px currentColor;
            }
        }

        /**************************************
                Button Color Schemes + Effects
                (Works for both Claude & Gemini)
        **************************************/

        /* Copy button - Orange */
        button[aria-label*="Copy" i] svg,
        button[data-testid*="copy" i] svg,
        button:has(svg path[d*="M9 9V4.5"]) svg,
        button[aria-label*="복사" i] svg,
        button[data-tooltip*="Copy" i] svg {
            color: ${COLORS.ORANGE} !important;
            opacity: ${OPACITY.HIGH};
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button[aria-label*="Copy" i]:hover svg,
        button[data-testid*="copy" i]:hover svg,
        button:has(svg path[d*="M9 9V4.5"]):hover svg,
        button[aria-label*="복사" i]:hover svg,
        button[data-tooltip*="Copy" i]:hover svg {
            filter: drop-shadow(0 0 8px ${COLORS.ORANGE}) !important;
            opacity: ${OPACITY.FULL} !important;
        }

        /* Edit button - Yellow */
        button[aria-label*="Edit" i] svg,
        button:has(svg path[d*="M12.0303"]) svg,
        button[aria-label*="수정" i] svg {
            color: ${COLORS.YELLOW} !important;
            opacity: ${OPACITY.MEDIUM};
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button[aria-label*="Edit" i]:hover svg,
        button:has(svg path[d*="M12.0303"]):hover svg,
        button[aria-label*="수정" i]:hover svg {
            filter: drop-shadow(0 0 8px ${COLORS.YELLOW}) !important;
            opacity: ${OPACITY.FULL} !important;
        }

        /* Regenerate/Retry button - Sky Blue */
        button[aria-label*="Retry" i] svg,
        button[aria-label*="Regenerate" i] svg,
        button:has(svg path[d*="M21.168"]) svg,
        button[aria-label*="다시 생성" i] svg {
            color: ${COLORS.SKYBLUE} !important;
            opacity: ${OPACITY.HIGH};
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button[aria-label*="Retry" i]:hover svg,
        button[aria-label*="Regenerate" i]:hover svg,
        button:has(svg path[d*="M21.168"]):hover svg,
        button[aria-label*="다시 생성" i]:hover svg {
            filter: drop-shadow(0 0 8px ${COLORS.SKYBLUE}) !important;
            opacity: ${OPACITY.FULL} !important;
            transform: rotate(180deg) !important;
        }

        /* Good response (thumbs up) - Green */
        button[aria-label*="Good" i] svg,
        button[data-testid*="good" i] svg,
        button:has(svg path[d*="M7.493 18.5"]) svg,
        button[aria-label*="좋아요" i] svg {
            color: ${COLORS.DARK_GREEN} !important;
            opacity: ${OPACITY.HIGH};
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button[aria-label*="Good" i]:hover svg,
        button[data-testid*="good" i]:hover svg,
        button:has(svg path[d*="M7.493 18.5"]):hover svg,
        button[aria-label*="좋아요" i]:hover svg {
            filter: drop-shadow(0 0 8px ${COLORS.DARK_GREEN}) !important;
            opacity: ${OPACITY.FULL} !important;
        }

        button[aria-label*="Good" i]:hover,
        button[data-testid*="good" i]:hover,
        button[aria-label*="좋아요" i]:hover {
            background: rgba(0, 173, 0, 0.12) !important;
            box-shadow: 0 0 12px rgba(0, 173, 0, 0.2) !important;
        }

        /* Bad response (thumbs down) - Red */
        button[aria-label*="Bad" i] svg,
        button[data-testid*="bad" i] svg,
        button:has(svg path[d*="M16.5 7.493"]) svg,
        button[aria-label*="싫어요" i] svg {
            color: ${COLORS.RED} !important;
            opacity: ${OPACITY.HIGH};
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button[aria-label*="Bad" i]:hover svg,
        button[data-testid*="bad" i]:hover svg,
        button:has(svg path[d*="M16.5 7.493"]):hover svg,
        button[aria-label*="싫어요" i]:hover svg {
            filter: drop-shadow(0 0 8px ${COLORS.RED}) !important;
            opacity: ${OPACITY.FULL} !important;
        }

        button[aria-label*="Bad" i]:hover,
        button[data-testid*="bad" i]:hover,
        button[aria-label*="싫어요" i]:hover {
            background: rgba(220, 53, 69, 0.12) !important;
            box-shadow: 0 0 12px rgba(220, 53, 69, 0.2) !important;
        }

        /* Share button - Sky Blue */
        button[aria-label*="Share" i] svg,
        button[aria-label*="공유" i] svg {
            color: ${COLORS.SKYBLUE} !important;
            opacity: ${OPACITY.MEDIUM};
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button[aria-label*="Share" i]:hover svg,
        button[aria-label*="공유" i]:hover svg {
            filter: drop-shadow(0 0 8px ${COLORS.SKYBLUE}) !important;
            opacity: ${OPACITY.FULL} !important;
        }

        /* Delete button - Red */
        button[aria-label*="Delete" i] svg,
        button[aria-label*="삭제" i] svg {
            color: ${COLORS.DESTRUCTIVE} !important;
        }

        button[aria-label*="Delete" i]:hover,
        button[aria-label*="삭제" i]:hover {
            background: rgba(224, 46, 42, 0.15) !important;
            box-shadow: 0 0 15px rgba(224, 46, 42, 0.3) !important;
        }

        /* More actions button - Gray */
        button[aria-label*="More" i] svg,
        button[aria-label*="더보기" i] svg {
            color: ${COLORS.GRAY} !important;
            opacity: ${OPACITY.LOW};
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button[aria-label*="More" i]:hover svg,
        button[aria-label*="더보기" i]:hover svg {
            opacity: ${OPACITY.FULL} !important;
        }

        /**************************************
            Bold Text Coloring
            (Works for both Claude & Gemini)
        **************************************/

        /* Light mode - Purple */
        .font-user-message b,
        .font-user-message strong,
        .font-claude-message b,
        .font-claude-message strong,
        [class*="message"] b,
        [class*="message"] strong,
        [class*="prose"] b,
        [class*="prose"] strong,
        div[class*="whitespace-pre-wrap"] b,
        div[class*="whitespace-pre-wrap"] strong,
        .model-response-text b,
        .model-response-text strong,
        .user-query b,
        .user-query strong,
        message-content b,
        message-content strong,
        b, strong {
            color: ${COLORS.PURPLE} !important;
            font-weight: 600 !important;
            transition: color 0.2s ease !important;
        }

        /* Dark mode - Green */
        .dark .font-user-message b,
        .dark .font-user-message strong,
        .dark .font-claude-message b,
        .dark .font-claude-message strong,
        .dark [class*="message"] b,
        .dark [class*="message"] strong,
        .dark [class*="prose"] b,
        .dark [class*="prose"] strong,
        .dark div[class*="whitespace-pre-wrap"] b,
        .dark div[class*="whitespace-pre-wrap"] strong,
        .dark .model-response-text b,
        .dark .model-response-text strong,
        .dark .user-query b,
        .dark .user-query strong,
        .dark message-content b,
        .dark message-content strong,
        .dark b,
        .dark strong {
            color: ${COLORS.GREEN} !important;
            font-weight: 600 !important;
        }

        /**************************************
            Italic Text Coloring
            (Works for both Claude & Gemini)
        **************************************/

        /* Light mode - Cyan */
        .font-user-message i,
        .font-user-message em,
        .font-claude-message i,
        .font-claude-message em,
        [class*="message"] i,
        [class*="message"] em,
        [class*="prose"] i,
        [class*="prose"] em,
        .model-response-text i,
        .model-response-text em,
        .user-query i,
        .user-query em,
        message-content i,
        message-content em,
        i, em {
            color: ${COLORS.CYAN} !important;
            font-style: italic !important;
            opacity: 0.9;
        }

        /* Dark mode - Sky Blue */
        .dark .font-user-message i,
        .dark .font-user-message em,
        .dark .font-claude-message i,
        .dark .font-claude-message em,
        .dark [class*="message"] i,
        .dark [class*="message"] em,
        .dark [class*="prose"] i,
        .dark [class*="prose"] em,
        .dark .model-response-text i,
        .dark .model-response-text em,
        .dark .user-query i,
        .dark .user-query em,
        .dark message-content i,
        .dark message-content em,
        .dark i,
        .dark em {
            color: ${COLORS.SKYBLUE} !important;
        }

        /**************************************
            Links Enhancement
        **************************************/

        .font-claude-message a,
        [class*="message"] a,
        [class*="prose"] a,
        .model-response-text a,
        message-content a {
            color: ${COLORS.BLUE} !important;
            text-decoration: underline;
            text-decoration-color: ${COLORS.BLUE}50;
            transition: all 0.2s ease !important;
        }

        .font-claude-message a:hover,
        [class*="message"] a:hover,
        [class*="prose"] a:hover,
        .model-response-text a:hover,
        message-content a:hover {
            color: ${COLORS.SKYBLUE} !important;
            text-decoration-color: ${COLORS.SKYBLUE} !important;
            text-shadow: 0 0 8px ${COLORS.SKYBLUE}80 !important;
        }

        /**************************************
            Code Enhancement
        **************************************/

        /* Inline code */
        code:not(pre code) {
            color: ${COLORS.PINK} !important;
            background: ${COLORS.PINK}15 !important;
            padding: 2px 6px !important;
            border-radius: 4px !important;
            font-weight: 500 !important;
        }

        .dark code:not(pre code) {
            color: ${COLORS.CYAN} !important;
            background: ${COLORS.CYAN}15 !important;
        }

        /* Code block headers */
        pre > div:first-child,
        [class*="code-block"] > div:first-child {
            background: linear-gradient(135deg, ${COLORS.PURPLE}30, ${COLORS.BLUE}30) !important;
            border-bottom: 2px solid ${COLORS.PURPLE}50 !important;
        }

        /**************************************
            Message Animations
        **************************************/

        /* Fade in new messages */
        .font-claude-message,
        .font-user-message,
        [class*="message-content"],
        .model-response-text,
        .user-query,
        message-content {
            animation: claude-fade-in ${CONFIG.animations.fadeInDuration} ease-out !important;
        }

        /**************************************
            Button Enhancements
        **************************************/

        button {
            transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        button:hover {
            transform: scale(1.05) !important;
        }

        button:active {
            transform: scale(0.95) !important;
        }

        /* Icon smooth transitions */
        button svg {
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        /* Focus effects */
        button:focus-visible {
            outline: 2px solid ${COLORS.BLUE} !important;
            outline-offset: 2px !important;
            box-shadow: 0 0 0 4px ${COLORS.BLUE}30 !important;
        }

        /**************************************
            List Enhancements
        **************************************/

        /* Colored list markers */
        .font-claude-message ul li::marker,
        [class*="message"] ul li::marker,
        [class*="prose"] ul li::marker,
        .model-response-text ul li::marker,
        message-content ul li::marker {
            color: ${COLORS.PURPLE} !important;
        }

        .font-claude-message ol li::marker,
        [class*="message"] ol li::marker,
        [class*="prose"] ol li::marker,
        .model-response-text ol li::marker,
        message-content ol li::marker {
            color: ${COLORS.BLUE} !important;
            font-weight: bold !important;
        }

        .dark .font-claude-message ul li::marker,
        .dark [class*="message"] ul li::marker,
        .dark [class*="prose"] ul li::marker,
        .dark .model-response-text ul li::marker,
        .dark message-content ul li::marker {
            color: ${COLORS.GREEN} !important;
        }

        /**************************************
            Scrollbar Styling
        **************************************/

        ::-webkit-scrollbar {
            width: 10px;
            height: 10px;
        }

        ::-webkit-scrollbar-track {
            background: transparent;
        }

        ::-webkit-scrollbar-thumb {
            background: ${COLORS.GRAY}40;
            border-radius: 5px;
            transition: background 0.2s ease !important;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: ${COLORS.GRAY}60;
        }

        .dark ::-webkit-scrollbar-thumb {
            background: ${COLORS.GRAY}60;
        }

        .dark ::-webkit-scrollbar-thumb:hover {
            background: ${COLORS.GRAY}80;
        }

        /**************************************
            Blockquote Styling
        **************************************/

        blockquote {
            border-left: 4px solid ${COLORS.PURPLE} !important;
            padding-left: 16px !important;
            opacity: 0.9;
        }

        .dark blockquote {
            border-left-color: ${COLORS.GREEN} !important;
        }

        /**************************************
            Misc Enhancements
        **************************************/

        /* Code block border radius */
        pre {
            border-radius: 8px !important;
        }

        /* Smooth transitions */
        * {
            transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1) !important;
        }
    `;

    // ===== Utility Functions =====

    const log = (...args) => {
        console.log('[Claude Enhancement v2]', ...args);
    };

    const injectStyles = () => {
        const existing = document.getElementById('claude-enhancement-styles-v2');
        if (existing) {
            existing.remove();
        }

        const styleSheet = document.createElement('style');
        styleSheet.textContent = STYLES;
        styleSheet.setAttribute('id', 'claude-enhancement-styles-v2');

        const appendStyleSheet = (head) => {
            if (head) {
                head.appendChild(styleSheet);
                log('✓ Visual effects loaded');
            } else {
                document.documentElement.appendChild(styleSheet);
            }
        };

        if (document.head) {
            appendStyleSheet(document.head);
        } else {
            document.addEventListener('DOMContentLoaded', () => appendStyleSheet(document.head), { once: true });
        }
    };

    /**
     * Apply colors to bold text
     */
    const applyBoldColors = () => {
        const isDark = document.documentElement.classList.contains('dark') ||
                      document.body.classList.contains('dark');

        const boldColor = isDark ? COLORS.GREEN : COLORS.PURPLE;
        const italicColor = isDark ? COLORS.SKYBLUE : COLORS.CYAN;

        const boldElements = document.querySelectorAll('b:not([data-styled]), strong:not([data-styled])');
        const italicElements = document.querySelectorAll('i:not([data-styled]), em:not([data-styled])');

        boldElements.forEach(el => {
            el.setAttribute('data-styled', 'true');
            el.style.setProperty('color', boldColor, 'important');
            el.style.setProperty('font-weight', '600', 'important');
        });

        italicElements.forEach(el => {
            el.setAttribute('data-styled', 'true');
            el.style.setProperty('color', italicColor, 'important');
        });
    };

    const dispatchNewChatClick = () => {
        for (const selector of CONFIG.selectors.newChat) {
            const target = document.querySelector(selector);
            if (target) {
                target.dispatchEvent(new MouseEvent('click', { bubbles: true }));
                log('New chat triggered');
                return true;
            }
        }
        return false;
    };

    const isShortcutMatch = (event) => {
        const { key, modifierRequired } = CONFIG.shortcuts.newChat;
        if (event.key.toLowerCase() !== key) return false;
        if (event.altKey || event.shiftKey) return false;
        if (modifierRequired && !event.metaKey && !event.ctrlKey) return false;
        return true;
    };

    const handleKeyboardShortcut = (event) => {
        if (event.defaultPrevented || event.repeat) return;
        if (!isShortcutMatch(event)) return;
        if (event.target.matches('input, textarea, [contenteditable="true"]')) return;

        if (dispatchNewChatClick()) {
            event.preventDefault();
        }
    };

    /**
     * Observe DOM changes
     */
    const observeDOM = () => {
        let timeout;

        const observer = new MutationObserver(() => {
            clearTimeout(timeout);
            timeout = setTimeout(() => {
                applyBoldColors();
            }, 100);
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    };

    // ===== Initialization =====
    const init = () => {
        log('Initializing with visual effects...');

        injectStyles();

        const applyWhenReady = () => {
            if (document.body) {
                applyBoldColors();
                observeDOM();

                setTimeout(applyBoldColors, 1000);
                setTimeout(applyBoldColors, 3000);
            } else {
                setTimeout(applyWhenReady, 100);
            }
        };

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', applyWhenReady);
        } else {
            applyWhenReady();
        }

        document.addEventListener('keydown', handleKeyboardShortcut, true);

        log('✓ Ready! Keyboard: Ctrl/Cmd + N for new chat');
    };

    init();

})();