Last active
March 20, 2025 10:09
-
-
Save 0nelight/48731a24fe32c96566ee4289f7fb9ab3 to your computer and use it in GitHub Desktop.
Adds a Conversation Overview Area to Grok-AI-WebUi for easy navigation (no doomscrooling anymore)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Grok Conversation Overview Overlay | |
// @namespace http://tampermonkey.net/ | |
// @version 0.31 | |
// @description Displays a hierarchical list of prompts, answers, and code blocks with scroll and copy functionality | |
// @author Grok | |
// @match https://grok.com/* | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
function buildOverview() { | |
// Alle .message-bubble Elemente auswählen | |
const bubbles = document.querySelectorAll('.message-bubble'); | |
const items = []; | |
// Bubbles verarbeiten | |
bubbles.forEach(bubble => { | |
const parent = bubble.parentElement; | |
// Prompt oder Antwort basierend auf Elternklassen unterscheiden | |
if (parent.classList.contains('items-end')) { | |
items.push({type: 'prompt', element: parent}); | |
} else if (parent.classList.contains('items-start')) { | |
items.push({type: 'answer', element: parent}); | |
// Code-Blöcke innerhalb der Antwort finden | |
const notProseDivs = bubble.querySelectorAll('.not-prose'); | |
notProseDivs.forEach(div => { | |
const codeElement = div.querySelector('code'); | |
if (codeElement) { | |
items.push({type: 'code', element: div, codeElement: codeElement}); | |
} | |
}); | |
} | |
}); | |
let overviewDiv = document.getElementById('conversation-overview'); | |
if (!overviewDiv) { | |
overviewDiv = document.createElement('div'); | |
overviewDiv.id = 'conversation-overview'; | |
overviewDiv.style.position = 'fixed'; | |
overviewDiv.style.top = '70px'; | |
overviewDiv.style.right = '10px'; | |
overviewDiv.style.bottom = '10px'; | |
overviewDiv.style.background = '#fff'; | |
overviewDiv.style.padding = '10px'; | |
overviewDiv.style.border = '1px solid #ccc'; | |
overviewDiv.style.zIndex = '1'; | |
overviewDiv.style.overflowY = 'auto'; | |
overviewDiv.style.fontSize = '12px'; | |
document.body.appendChild(overviewDiv); | |
} | |
// HTML für die hierarchische Liste erstellen | |
let html = '<strong>Conversation Overview:</strong><ul style="list-style: none; padding: 0;">'; | |
let promptCount = 0; | |
let answerCount = 0; | |
items.forEach((item, index) => { | |
if (item.type === 'prompt') { | |
promptCount++; | |
const preview = item.element.querySelector('.message-bubble')?.textContent.trim().substring(0, 30) || 'Prompt'; | |
html += `<li><a href="#" data-index="${index}" style="text-decoration: none; color: blue; cursor: pointer;">Prompt ${promptCount}: ${preview}...</a></li>`; | |
} else if (item.type === 'answer') { | |
answerCount++; | |
const preview = item.element.querySelector('.message-bubble')?.textContent.trim().substring(0, 30) || 'Answer'; | |
html += `<li><a href="#" data-index="${index}" style="text-decoration: none; color: blue; cursor: pointer;">Answer ${answerCount}: ${preview}...</a></li>`; | |
} else if (item.type === 'code') { | |
const codePreview = item.codeElement.textContent.trim().substring(0, 30) || 'Code block'; | |
html += `<li style="padding-left:20px"><a href="#" data-index="${index}" style="text-decoration: none; color: blue; cursor: pointer;">Code block: ${codePreview}...</a> <button data-index="${index}" style="margin-left:5px; position:relative;">Copy</button></li>`; | |
} | |
}); | |
html += '</ul>'; | |
overviewDiv.innerHTML = html; | |
// Event-Listener für Scrollen hinzufügen | |
overviewDiv.querySelectorAll('a').forEach(link => { | |
link.addEventListener('click', (e) => { | |
e.preventDefault(); | |
const index = link.getAttribute('data-index'); | |
const item = items[index]; | |
item.element.scrollIntoView({behavior: 'smooth', block: 'start'}); | |
}); | |
}); | |
// Event-Listener für Kopieren hinzufügen | |
overviewDiv.querySelectorAll('button').forEach(button => { | |
button.addEventListener('click', () => { | |
const index = button.getAttribute('data-index'); | |
const item = items[index]; | |
const codeText = item.codeElement.textContent; | |
navigator.clipboard.writeText(codeText).then(() => { | |
const confirmSpan = document.createElement('span'); | |
confirmSpan.textContent = 'Copied!'; | |
confirmSpan.style.position = 'absolute'; | |
confirmSpan.style.left = '100%'; | |
confirmSpan.style.marginLeft = '5px'; | |
confirmSpan.style.color = '#28a745'; | |
confirmSpan.style.fontSize = '12px'; | |
button.appendChild(confirmSpan); | |
setTimeout(() => { | |
confirmSpan.remove(); | |
}, 2000); | |
}).catch(err => { | |
console.error('Fehler beim Kopieren: ', err); | |
const errorSpan = document.createElement('span'); | |
errorSpan.textContent = 'Error'; | |
errorSpan.style.position = 'absolute'; | |
errorSpan.style.left = '100%'; | |
errorSpan.style.marginLeft = '5px'; | |
errorSpan.style.color = '#dc3545'; | |
errorSpan.style.fontSize = '12px'; | |
button.appendChild(errorSpan); | |
setTimeout(() => { | |
errorSpan.remove(); | |
}, 2000); | |
}); | |
}); | |
}); | |
} | |
// Initialer Aufruf beim Laden der Seite | |
window.addEventListener('load', buildOverview); | |
// Aktualisierung alle 5 Sekunden | |
setInterval(buildOverview, 5000); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment