Collapsible GPT List for ChatGPT.com

Enhances the sidebar functionality by enabling the GPT List to collapse.

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

作者のサイトでサポートを受ける。または、このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Collapsible GPT List for ChatGPT.com
// @namespace    https://chatgpt.com/
// @version      1.1
// @description  Enhances the sidebar functionality by enabling the GPT List to collapse.
// @author       Seth Rose
// @homepage     https://x.com/TheSethRose
// @supportURL   https://bsky.app/profile/sethrose.dev
// @supportURL   https://x.com/TheSethRose
// @match        https://chatgpt.com/*
// @match        https://chat.com/*
// @match        https://chat.openai.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
    "use strict";

    let isFirstTargetProcessed = false;

    function getElementByXPath(xpath) {
        const result = document.evaluate(
            xpath,
            document,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        );
        return result.singleNodeValue;
    }

    function makeCollapsible() {
        if (isFirstTargetProcessed) return;

        const targetXPath = "/html/body/div[1]/div[1]/div/div/div/nav/div[2]/div/div[4]";
        const targetDiv = getElementByXPath(targetXPath);
        if (!targetDiv) return;

        // Avoid duplicates
        if (
            targetDiv.previousElementSibling &&
            targetDiv.previousElementSibling.classList.contains("collapsible-toggle")
        ) {
            return;
        }

        // Create the toggle container
        const toggleButton = document.createElement("div");
        toggleButton.className =
            "collapsible-toggle z-20 select-none text-xs font-semibold text-token-text-primary " +
            "flex items-center justify-between h-[26px] px-2 pl-";
        toggleButton.style.cursor = "pointer";
        toggleButton.style.margin = "0";
        toggleButton.style.paddingBottom = "0"; // extra attempt at removing spacing

        // Inner HTML: start collapsed
        toggleButton.innerHTML = `
            <span id="toggleText">Expand GPT List</span>
            <div class="flex h-[26px] w-[26px] items-center justify-center text-token-text-secondary" style="margin:0;padding:0;">
                <button aria-label="Toggle GPTs" class="ml-3 flex rounded-lg items-center text-token-text-primary">
                    <svg class="w-6 h-6 text-gray-800 dark:text-white"
                         aria-hidden="true"
                         xmlns="http://www.w3.org/2000/svg"
                         width="24" height="24"
                         fill="none"
                         viewBox="0 0 24 24">
                        <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
                              stroke-width="2" d="m8 10 4 4 4-4"/>
                    </svg>
                </button>
            </div>
        `;

        // Style the div to be collapsible
        targetDiv.style.maxHeight = "0";
        targetDiv.style.overflow = "hidden";
        targetDiv.style.transition = "max-height 0.3s ease";
        targetDiv.style.margin = "0";
        targetDiv.style.padding = "0";

        // Insert the toggle button
        targetDiv.parentNode.insertBefore(toggleButton, targetDiv);

        // References for text/icon
        const toggleTextSpan = toggleButton.querySelector("#toggleText");
        const svgPath = toggleButton.querySelector("svg path");

        // Click event toggles everything
        toggleButton.addEventListener("click", () => {
            if (targetDiv.style.maxHeight === "0px") {
                // Expand
                targetDiv.style.maxHeight = targetDiv.scrollHeight + "px";
                toggleTextSpan.textContent = "Collapse GPT List";
                svgPath.setAttribute("d", "m16 14-4-4-4 4"); // Arrow up
            } else {
                // Collapse
                targetDiv.style.maxHeight = "0";
                toggleTextSpan.textContent = "Expand GPT List";
                svgPath.setAttribute("d", "m8 10 4 4 4-4"); // Arrow down
            }
        });

        isFirstTargetProcessed = true;
    }

    // Delay to ensure the target element is rendered
    window.addEventListener("load", () => {
        setTimeout(makeCollapsible, 500);
    });
})();