您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows pinning chats in the ChatGPT sidebar
// ==UserScript== // @name Pin Chats in ChatGPT // @version 20240522 // @description Allows pinning chats in the ChatGPT sidebar // @author jamesdeluk // @match https://chatgpt.com/* // @grant none // @namespace https://greasyfork.org/users/242246 // ==/UserScript== (function () { "use strict"; async function waitForElement(selector) { while (!document.querySelector(selector)) { await new Promise((resolve) => requestAnimationFrame(resolve)); } // Load pinned chats from local storage var pinnedChats = JSON.parse(localStorage.getItem("pinnedChats") || "[]"); // Add toggle pin button to each chat item function addPinButton(chatItem, chatId, chatTitle) { var pinButton = document.createElement("button"); pinButton.innerHTML = "📌"; pinButton.className = "pin-button"; pinButton.title = "Toggle pin"; pinButton.onclick = function (event) { event.preventDefault(); event.stopPropagation(); togglePinChat(chatId, chatTitle, pinButton); }; var chatTextDiv = chatItem.querySelector( ".relative.grow.overflow-hidden.whitespace-nowrap" ); chatTextDiv.parentElement.insertBefore(pinButton, chatTextDiv); } // Toggle pin/unpin chat function function togglePinChat(chatId, chatTitle, button) { var chatIndex = pinnedChats.findIndex((chat) => chat.id === chatId); if (chatIndex === -1) { pinnedChats.push({ id: chatId, title: chatTitle }); } else { pinnedChats.splice(chatIndex, 1); } localStorage.setItem("pinnedChats", JSON.stringify(pinnedChats)); renderPinnedChats(); } // Render pinned chats function renderPinnedChats() { var todaySection = '' var headers = document.querySelectorAll("h3"); for (var i = 0; i < headers.length; i++) { if (headers[i].textContent.trim() === "Today") { todaySection = headers[i].closest("div"); } } var pinnedSection = document.getElementById("pinned-chats-section"); if (!pinnedSection) { pinnedSection = document.createElement("div"); pinnedSection.id = "pinned-chats-section"; todaySection.parentElement.insertBefore(pinnedSection, todaySection); } pinnedSection.innerHTML = ""; var header = document.createElement("h3"); header.className = "pb-2 pt-3 px-2 text-xs font-medium text-ellipsis overflow-hidden break-all text-token-text-secondary"; header.innerText = "Pinned"; pinnedSection.appendChild(header); pinnedChats.forEach((chat) => { var chatItem = document.createElement("li"); chatItem.className = "group relative rounded-lg active:opacity-90 hover:bg-token-sidebar-surface-secondary"; chatItem.innerHTML = ` <a href="/c/${chat.id}" class="flex items-center gap-2 p-2"> <div class="relative grow overflow-hidden whitespace-nowrap">${chat.title} <div class="absolute bottom-0 right-0 top-0 bg-gradient-to-l to-transparent from-token-sidebar-surface-primary group-hover:from-token-sidebar-surface-secondary w-8 from-0% group-hover:w-20"></div> </div> </a> `; pinnedSection.appendChild(chatItem); }); } // Initial rendering of pinned chats renderPinnedChats(); // Observe sidebar for new chat items var sidebarObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1 && node.matches("li")) { var chatId = node .querySelector("a") .getAttribute("href") .split("/") .pop(); var chatTitle = node.querySelector( ".relative.grow.overflow-hidden.whitespace-nowrap" ).innerText; addPinButton(node, chatId, chatTitle); } }); } }); }); var sidebar = document.querySelector("nav"); if (sidebar) { sidebarObserver.observe(sidebar, { childList: true, subtree: true }); // Add pin buttons to existing chat items sidebar.querySelectorAll("li").forEach((chatItem) => { var chatId = chatItem .querySelector("a") .getAttribute("href") .split("/") .pop(); var chatTitle = chatItem.querySelector( ".relative.grow.overflow-hidden.whitespace-nowrap" ).innerText; addPinButton(chatItem, chatId, chatTitle); }); } } waitForElement(".relative.grow.overflow-hidden.whitespace-nowrap"); })();