// ==UserScript== // @name AI Conversation Navigator // @namespace https://greasyfork.org // @version 2.4 // @description Floating navigator for your prompts in ChatGPT, Gemini, Aistudio, Kimi, Grok, GLM conversations // @author Bui Quoc Dung // @match https://chatgpt.com/* // @match https://gemini.google.com/* // @match https://aistudio.google.com/* // @match https://grok.com/* // @match https://www.kimi.com/* // @match https://chat.deepseek.com/* // @match https://chat.z.ai/* // @grant GM_addStyle // @license MIT // @downloadURL none // ==/UserScript== (function () { 'use strict'; const COMMON_TITLE = 'Your Prompts'; const BASE_CONTAINER_CSS = ` right: 20px; width: 250px; max-height: 90vh; overflow-y: auto; z-index: 9999; border-radius: 2px; box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3); transition: width 0.3s, padding 0.3s, opacity 0.3s, transform 0.3s; font-family: Calibri, sans-serif; font-size: 15px; color: CanvasText; position: fixed; `; const getShiftStyle = (width, selector = '') => ` body.navigator-expanded ${selector} { margin-left: 0 !important; margin-right: ${width}px !important; max-width: calc(100% - ${width}px) !important; transition: margin-right 0.3s ease; } `; const SITE_CONFIG = { chatgpt: { match: /chatgpt\.com/, msgSelector: 'div[data-message-author-role="user"]', top: '35px', width: 270, bgClass: "text-token-text-primary bg-token-main-surface-primary rounded-lg shadow-lg" }, gemini: { match: /gemini\.google\.com/, msgSelector: 'p.query-text-line', top: '55px', width: 270 }, aistudio: { match: /aistudio\.google\.com/, msgSelector: '.user-prompt-container', top: '55px', width: 250, shiftTarget: 'ms-autoscroll-container' }, grok: { match: /grok\.com/, msgSelector: '.relative.group.flex.flex-col.justify-center.items-end', top: '55px', width: 280, }, deepseek: { match: /chat\.deepseek\.com/, msgSelector: '.ds-message:nth-child(odd)', top: '55px', width: 270, shiftTarget: '#root > div > div > div:nth-child(2) > div:nth-child(3) > div > div:nth-child(2) > div' }, kimi: { match: /www\.kimi\.com/, msgSelector: '.user-content', top: '55px', width: 270 }, glm: { match: /chat\.z\.ai/, msgSelector: '.chat-user', top: '55px', width: 280 } }; const site = Object.values(SITE_CONFIG).find(s => s.match.test(location.hostname)); if (!site) return; GM_addStyle(getShiftStyle(site.width, site.shiftTarget || '')); let userMsgCounter = 0; let conversationObserver = null; let isCollapsed = false; window.navigatorUpdateTimeout = null; function updateBodyClassForLayout() { const container = document.getElementById('message-nav'); const content = document.getElementById('message-nav-content'); if (container && content && content.style.display !== 'none') { document.body.classList.add('navigator-expanded'); } else { document.body.classList.remove('navigator-expanded'); } } function createContainer() { let container = document.getElementById('message-nav'); if (!container) { container = document.createElement('div'); container.id = 'message-nav'; container.className = site.bgClass || ''; container.style.cssText = `top: ${site.top}; ${BASE_CONTAINER_CSS}`; const header = document.createElement('div'); Object.assign(header.style, { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '5px', cursor: 'pointer', fontWeight: 'bold' }); header.textContent = COMMON_TITLE; const toggleBtn = document.createElement('button'); Object.assign(toggleBtn.style, { background: 'none', border: 'none', cursor: 'pointer', fontSize: '16px' }); toggleBtn.textContent = '⯈'; header.appendChild(toggleBtn); const content = document.createElement('div'); content.id = 'message-nav-content'; content.style.padding = '5px'; container.appendChild(header); container.appendChild(content); document.body.appendChild(container); if (isCollapsed) { content.style.display = 'none'; container.style.width = '130px'; toggleBtn.textContent = '⯆'; } const toggleHandler = (e) => { e.stopPropagation(); isCollapsed = !isCollapsed; if (!isCollapsed) { content.style.display = 'block'; container.style.width = '250px'; toggleBtn.textContent = '⯈'; } else { content.style.display = 'none'; container.style.width = '130px'; toggleBtn.textContent = '⯆'; } updateBodyClassForLayout(); }; toggleBtn.addEventListener('click', toggleHandler); updateBodyClassForLayout(); } return container; } function assignIdToMessage(msgElem) { if (!msgElem.id) { userMsgCounter++; msgElem.id = 'user-msg-' + userMsgCounter; msgElem.dataset.index = userMsgCounter; } } function createListItem(msgElem) { const index = msgElem.dataset.index || '?'; const text = msgElem.innerText.trim(); const preview = text.length > 80 ? text.slice(0, 80) + '...' : text; const listItem = document.createElement('li'); listItem.textContent = `${index}. ${preview}`; Object.assign(listItem.style, { cursor: 'pointer', padding: '5px 5px' }); listItem.addEventListener('click', () => { listItem.parentElement.querySelectorAll('li').forEach(li => li.style.fontWeight = 'normal'); listItem.style.fontWeight = 'bold'; msgElem.scrollIntoView({ behavior: 'smooth', block: 'start' }); }); return listItem; } function updateMessageList() { const container = createContainer(); const content = document.getElementById('message-nav-content'); if (!content) return; let list = content.querySelector('ul'); if (!list) { list = document.createElement('ul'); list.style.cssText = 'padding: 0; margin: 0; list-style: none;'; content.appendChild(list); } const userMessages = document.querySelectorAll(site.msgSelector); const existingListItems = list.querySelectorAll('li'); let shouldReset = false; if (userMessages.length < existingListItems.length) { shouldReset = true; } if (!shouldReset && userMessages.length > 0 && existingListItems.length > 0) { const firstMsgDOM = userMessages[0]; const firstListItem = existingListItems[0]; if (!firstMsgDOM.id || (firstListItem.dataset.msgId && firstMsgDOM.id !== firstListItem.dataset.msgId)) { shouldReset = true; } } if (shouldReset) { list.innerHTML = ''; userMsgCounter = 0; } const currentItems = list.querySelectorAll('li'); if (userMessages.length > currentItems.length) { for (let i = currentItems.length; i < userMessages.length; i++) { const msgElem = userMessages[i]; assignIdToMessage(msgElem); const listItem = createListItem(msgElem); listItem.dataset.msgId = msgElem.id; list.appendChild(listItem); } } } function observeConversation() { if (conversationObserver) conversationObserver.disconnect(); conversationObserver = new MutationObserver(() => { clearTimeout(window.navigatorUpdateTimeout); window.navigatorUpdateTimeout = setTimeout(() => updateMessageList(), 500); }); conversationObserver.observe(document.body, { childList: true, subtree: true, attributes: false }); } setTimeout(() => updateMessageList(), 500); observeConversation(); })();