OpenAI Playground Config Panel Toggle

Toggle the configuration panel in OpenAI Playground with a sleek arrow button

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

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

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

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

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

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         OpenAI Playground Config Panel Toggle
// @namespace    https://github.com/NoahTheGinger/
// @version      3.2
// @description  Toggle the configuration panel in OpenAI Playground with a sleek arrow button
// @author       NoahTheGinger
// @match        https://platform.openai.com/chat
// @match        https://platform.openai.com/chat/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    let configPanel = null;
    let chatContainer = null;
    let toggleButton = null;
    let isPanelHidden = false;
    let parentContainer = null;

    // Function to find the configuration panel
    function findConfigPanel() {
        // Look for the panel containing Model, Variables, Tools sections
        const panels = document.querySelectorAll('div[class*="neIqM"], div[class*="_0-y9H"]');
        for (const panel of panels) {
            const text = panel.innerText || '';
            if (text.includes('Model') && text.includes('Variables') && text.includes('Tools')) {
                return panel.closest('div[class*="_0-y9H"]') || panel;
            }
        }
        return null;
    }

    // Function to find the chat container and parent
    function findContainers() {
        // Find the config panel first
        const config = findConfigPanel();
        if (!config) return { config: null, chat: null, parent: null };

        // Find the parent that contains both config and chat
        let parent = config.parentElement;
        while (parent) {
            // Look for a flex container that has both panels
            if (parent.style.display === 'flex' || 
                (parent.classList && Array.from(parent.classList).some(c => c.includes('flex')))) {
                
                const children = Array.from(parent.children);
                if (children.length >= 2) {
                    // Find the chat container (should be after config panel)
                    const chatIndex = children.indexOf(config) + 1;
                    if (chatIndex < children.length) {
                        return {
                            config: config,
                            chat: children[chatIndex],
                            parent: parent
                        };
                    }
                }
            }
            parent = parent.parentElement;
        }
        
        return { config: config, chat: null, parent: null };
    }

    // Function to create the toggle button
    function createToggleButton() {
        const button = document.createElement('button');
        button.innerHTML = `
            <svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
                <path d="M7.5 3L4.5 6L7.5 9" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
        `;
        
        button.style.cssText = `
            position: absolute;
            right: -16px;
            top: 50%;
            transform: translateY(-50%);
            z-index: 1000;
            background: #ffffff;
            border: 1px solid #e5e5e5;
            border-radius: 6px;
            padding: 6px;
            cursor: pointer;
            transition: all 0.2s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 28px;
            height: 28px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
            color: #666;
        `;

        button.addEventListener('mouseenter', () => {
            button.style.background = '#f7f7f7';
            button.style.borderColor = '#d5d5d5';
            button.style.color = '#333';
        });

        button.addEventListener('mouseleave', () => {
            button.style.background = '#ffffff';
            button.style.borderColor = '#e5e5e5';
            button.style.color = '#666';
        });

        button.addEventListener('click', togglePanel);
        
        return button;
    }

    // Function to update button position
    function updateButtonPosition() {
        if (!toggleButton || !configPanel) return;

        if (isPanelHidden) {
            // When hidden, attach to chat container's left edge but with proper offset
            if (chatContainer) {
                chatContainer.style.position = 'relative';
                toggleButton.style.position = 'absolute';
                toggleButton.style.right = 'auto';
                toggleButton.style.left = '8px'; // Changed from -16px to 8px to stay visible
                
                if (toggleButton.parentElement !== chatContainer) {
                    chatContainer.appendChild(toggleButton);
                }
            }
        } else {
            // When visible, attach to config panel's right edge
            configPanel.style.position = 'relative';
            toggleButton.style.position = 'absolute';
            toggleButton.style.left = 'auto';
            toggleButton.style.right = '-16px';
            
            if (toggleButton.parentElement !== configPanel) {
                configPanel.appendChild(toggleButton);
            }
        }
    }

    // Function to toggle the panel
    function togglePanel() {
        if (!configPanel || !chatContainer) {
            // Try to find containers again
            const containers = findContainers();
            configPanel = containers.config;
            chatContainer = containers.chat;
            parentContainer = containers.parent;
        }

        if (!configPanel || !chatContainer) return;

        isPanelHidden = !isPanelHidden;

        if (isPanelHidden) {
            // Store original values
            configPanel.dataset.originalWidth = configPanel.style.width || '';
            configPanel.dataset.originalFlex = configPanel.style.flex || '';
            chatContainer.dataset.originalFlex = chatContainer.style.flex || '';
            
            // Hide the config panel
            configPanel.style.transition = 'all 0.3s ease';
            configPanel.style.width = '0';
            configPanel.style.minWidth = '0';
            configPanel.style.overflow = 'hidden';
            configPanel.style.opacity = '0';
            configPanel.style.flex = '0 0 0';
            configPanel.style.padding = '0';
            configPanel.style.margin = '0';
            
            // Expand the chat container
            chatContainer.style.transition = 'all 0.3s ease';
            chatContainer.style.flex = '1 1 100%';
            chatContainer.style.width = '100%';
            chatContainer.style.maxWidth = '100%';
            
            // Update button icon (right arrow)
            toggleButton.innerHTML = `
                <svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
                    <path d="M4.5 3L7.5 6L4.5 9" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            `;
            
            // Move button after a delay
            setTimeout(() => {
                updateButtonPosition();
            }, 150);
        } else {
            // First move the button back
            updateButtonPosition();
            
            // Then restore the config panel
            setTimeout(() => {
                configPanel.style.transition = 'all 0.3s ease';
                configPanel.style.width = configPanel.dataset.originalWidth || '';
                configPanel.style.minWidth = '';
                configPanel.style.overflow = '';
                configPanel.style.opacity = '1';
                configPanel.style.flex = configPanel.dataset.originalFlex || '';
                configPanel.style.padding = '';
                configPanel.style.margin = '';
                
                // Restore chat container
                chatContainer.style.transition = 'all 0.3s ease';
                chatContainer.style.flex = chatContainer.dataset.originalFlex || '';
                chatContainer.style.width = '';
                chatContainer.style.maxWidth = '';
                
                // Update button icon (left arrow)
                toggleButton.innerHTML = `
                    <svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
                        <path d="M7.5 3L4.5 6L7.5 9" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                `;
            }, 50);
        }
    }

    // Function to initialize the script
    function init() {
        // Find the containers
        const containers = findContainers();
        configPanel = containers.config;
        chatContainer = containers.chat;
        parentContainer = containers.parent;

        if (configPanel && chatContainer && !toggleButton) {
            // Create and add the toggle button
            toggleButton = createToggleButton();
            configPanel.style.position = 'relative';
            configPanel.appendChild(toggleButton);
            
            console.log('OpenAI Playground Toggle initialized');
        }
    }

    // Wait for the page to load and initialize
    function waitForLoad() {
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            setTimeout(init, 1000);
        } else {
            document.addEventListener('DOMContentLoaded', () => setTimeout(init, 1000));
        }
    }

    waitForLoad();

    // Re-initialize on navigation changes (SPA)
    let lastUrl = location.href;
    new MutationObserver(() => {
        const url = location.href;
        if (url !== lastUrl) {
            lastUrl = url;
            setTimeout(init, 1000);
        }
    }).observe(document, { subtree: true, childList: true });

    // Also watch for dynamic content changes
    const observer = new MutationObserver((mutations) => {
        if (!configPanel || !chatContainer) {
            init();
        }
    });

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

})();