Highlights Active ChatGPT Conversation Title

Underlines the currently active conversation title and scrolls it into view

// ==UserScript==
// @name         Highlights Active ChatGPT Conversation Title
// @namespace    violentmonkey.github.io
// @version      1.1
// @description  Underlines the currently active conversation title and scrolls it into view
// @author       Bui Quoc Dung
// @match        https://chatgpt.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  let hasScrolledToActive = false;  

  function updateUnderline() {
    const currentPath = location.pathname;
    const links = document.querySelectorAll('a.group.__menu-item');

    links.forEach(link => {
      const href = link.getAttribute('href');
      const span = link.querySelector('span');

      if (span) {
        if (href === currentPath) {
          span.style.textDecoration = 'underline';
          span.style.fontWeight = 'bold';


          if (!hasScrolledToActive) {
            hasScrolledToActive = true;
            setTimeout(() => {
              link.scrollIntoView({ behavior: 'smooth', block: 'center' });
            }, 100);
          }
        } else {
          span.style.textDecoration = '';
          span.style.fontWeight = '';
        }
      }
    });
  }

  window.addEventListener('popstate', () => {
    hasScrolledToActive = false;
    updateUnderline();
  });

  window.addEventListener('pushState', () => {
    hasScrolledToActive = false;
    updateUnderline();
  });

  window.addEventListener('replaceState', () => {
    hasScrolledToActive = false;
    updateUnderline();
  });

  updateUnderline();

  const observer = new MutationObserver(updateUnderline);
  observer.observe(document.body, { childList: true, subtree: true });

  const origPushState = history.pushState;
  history.pushState = function () {
    origPushState.apply(this, arguments);
    hasScrolledToActive = false;
    updateUnderline();
  };

  const origReplaceState = history.replaceState;
  history.replaceState = function () {
    origReplaceState.apply(this, arguments);
    hasScrolledToActive = false;
    updateUnderline();
  };
})();