Greasy Fork is available in English.

ChatGPT custom instructions button

Doesn't seem to work in Chrome/Edge. Adds a 'Custom instructions' button to the bottom of the side panel. You have to do this manually once first for the script to work.

// ==UserScript==
// @name         ChatGPT custom instructions button
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Doesn't seem to work in Chrome/Edge. Adds a 'Custom instructions' button to the bottom of the side panel. You have to do this manually once first for the script to work.
// @author       Nick Bell
// @match        https://chat.openai.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let buttonAdded = false;

    function simulateClick(target) {
        const event = new MouseEvent('click', {
            bubbles: true,
            cancelable: true,
            view: window
        });
        target.dispatchEvent(event);
    }

    // Function to add the button next to menuElement
    function addButtonNextToMenuElement() {
        const menuElement = document.querySelector("div.border-t:nth-child(4)");
        if (menuElement && !buttonAdded) {
            const button = document.createElement("button");
            button.innerHTML = "Custom instructions";
            button.style = "font-family: 'Courier New';font-size: 9pt; color:white; padding: 0.2rem; border: 1px white solid;";
            button.addEventListener('mouseup', function() {
                setTimeout(function() {
                    // Programmatically click the identified button
                    const targetElement = document.querySelector("[id='headlessui-menu-button-:r9:']");
                    if (targetElement) {
                        simulateClick(targetElement);
                    }

                    // Start polling for ciElement
                    const ciElementIntervalId = setInterval(function() {
                        const ciElement = document.querySelector("[id='headlessui-menu-item-:r22:']");
                        if (ciElement) {
                            clearInterval(ciElementIntervalId);
                            simulateClick(ciElement);
                        }
                    }, 500);
                }, 100);  // 100ms delay
            });
            menuElement.parentNode.insertBefore(button, menuElement.nextSibling);
            buttonAdded = true;
        }
    }

    // Mutation observer to watch for changes in the DOM
    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            addButtonNextToMenuElement();
        });
    });

    // Configuration of the observer
    const config = {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
    };

    // Pass in the target node, as well as the observer options
    observer.observe(document.body, config);
})();