您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Toggle the configuration panel in OpenAI Playground with a sleek arrow button
// ==UserScript== // @name OpenAI Playground Config Panel Toggle // @namespace https://github.com/NoahTheGinger/ // @version 3.1 // @description Toggle the configuration panel in OpenAI Playground with a sleek arrow button // @author NoahTheGinger // @match https://platform.openai.com/playground/* // @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 }); })();