Claude Interface Enhancement v2

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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();

})();