ChatGPT Tools

Various Tools for ChatGPT

От 26.12.2024. Виж последната версия.

// ==UserScript==
// @name         ChatGPT Tools
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  Various Tools for ChatGPT
// @author       You
// @match        https://chatgpt.com/*
// @grant        GM_addStyle

// ==/UserScript==


(function () {
    'use strict';
// =============================================================== MAIN INJECT ===============================================================

function isMobileDevice() {
    return /Mobi|Android/i.test(navigator.userAgent);
}

if (!isMobileDevice()) {
function disableEnterKey(event) {
    // Check if the Enter key is pressed
    if (event.key === "Enter") {
        // Allow Shift + Enter for a new paragraph
        if (event.shiftKey) {
            console.log("New paragraph created.");
            return; // Exit the function, allowing the default behavior
        }
        // Prevent default Enter key behavior
        event.preventDefault();
        console.log("Enter key functionality disabled.");
        const inputPanelGPT = document.querySelector('div#prompt-textarea.ProseMirror');

// RULES
        const getRulesState = localStorage.getItem('enableRules');
        if (getRulesState === "true") {
        const getSelectedRuleValue = localStorage.getItem('selectedRuleValue');
        const newParagraph = document.createElement('p');
        newParagraph.textContent = getSelectedRuleValue;
        inputPanelGPT.appendChild(newParagraph);
        console.log('Next Rule appended:', getSelectedRuleValue);
        }


// LOREBOOK
      const getLorebookState = localStorage.getItem('enableLorebook');
      if (getLorebookState === "true") {
      const getSelectedLorebookEntries = localStorage.getItem('selectedLorebookValues');
        const newParagraph = document.createElement('p');
        newParagraph.textContent = getSelectedLorebookEntries;
        inputPanelGPT.appendChild(newParagraph);
        console.log('Lorebook Entries appended:', getSelectedLorebookEntries);
      }

        // Update the selection range to the end of the container
        const selection = window.getSelection();
        selection.removeAllRanges();
        const newRange = document.createRange();
        newRange.selectNodeContents(inputPanelGPT);
        newRange.collapse(false);
        selection.addRange(newRange);

        const inputEvent = new Event('input', { bubbles: true, cancelable: true });
        inputPanelGPT.dispatchEvent(inputEvent);

        setTimeout(() => {
          const sendButton = document.querySelector('button[data-testid="send-button"]');
          if (sendButton) {
            sendButton.click();
            console.log('Send button clicked after delay.');
          } else {
            console.error('Send button not found.');
          }
        }, 100); // 10ms delay (adjust as needed)

    }
}

// Attach the event listener to the document
document.addEventListener("keydown", disableEnterKey, true);
}

if (isMobileDevice()) {
let programmaticClick = false; // Flag to differentiate between user and programmatic clicks

document.body.addEventListener('click', function (event) {
    const sendButton1 = document.querySelector('button[aria-label="Send prompt"]');

    // Check if the button exists and if the clicked target is the send button
    if (sendButton1 && sendButton1.contains(event.target)) {
        console.error('AAAAAAA');

        // If this is a programmatic click, bypass the custom logic
        if (programmaticClick) {
            programmaticClick = false; // Reset the flag for subsequent clicks
            console.log("Programmatic click detected, skipping custom logic.");
            return;
        }

        // Prevent default click behavior and propagation temporarily
        event.preventDefault();
        event.stopImmediatePropagation();
        console.log("Send Button functionality temporarily disabled to execute custom logic.");

            const inputPanelGPT = document.querySelector('div#prompt-textarea.ProseMirror');

            // RULES
            const getRulesState = localStorage.getItem('enableRules');
            if (getRulesState === "true") {
                const getSelectedRuleValue = localStorage.getItem('selectedRuleValue');

                // Check if the rule is already appended
                const existingRule = Array.from(inputPanelGPT.children).find(
                    child => child.textContent === getSelectedRuleValue
                );

                if (!existingRule) {
                    const newParagraph = document.createElement('p');
                    newParagraph.textContent = getSelectedRuleValue;
                    inputPanelGPT.appendChild(newParagraph);
                    console.log('Next Rule appended:', getSelectedRuleValue);
                } else {
                    console.log('Rule already exists, not appending again.');
                }
            }

            // Update the selection range to the end of the container
            const selection = window.getSelection();
            selection.removeAllRanges();
            const newRange = document.createRange();
            newRange.selectNodeContents(inputPanelGPT);
            newRange.collapse(false);
            selection.addRange(newRange);

            const inputEvent = new Event('input', { bubbles: true, cancelable: true });
            inputPanelGPT.dispatchEvent(inputEvent);




        // Restore the send functionality after custom logic
        setTimeout(() => {
            console.log("Restoring Send Button functionality.");
            programmaticClick = true; // Set the flag to indicate programmatic click
            sendButton1.click(); // Programmatically trigger the send action
        }, 20); // Use a 0ms delay to allow custom logic to finish
    }
});

}



// ================================================================ GLOBAL STYLES =================================================================

    const CONFIG = {
        panelBackground: '#171717',
// PanelButtons
        BUTTON_HIGHLIGHT: '#424242',
        BUTTON_OUTLINE: '1px solid #4E4E4E',
    };



// Black Background Overlay
const overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.backgroundColor = 'rgba(0,0,0,0.5)';
overlay.style.zIndex = '999';
overlay.style.display = 'none';

function showOverlay() {
    document.body.appendChild(overlay);
    overlay.style.display = 'block';
}
function hideOverlay() {
    overlay.style.display = 'none';
}


// ================================================================= MAIN PANEL ==================================================================
function mainPanelScript() {
    // Create and add the arrow button to open the storage panel
    const arrowButton = document.createElement('div');
    arrowButton.innerHTML = '〈';
    arrowButton.style.position = 'fixed';
    arrowButton.style.bottom = '50%';
    arrowButton.style.right = '0';
    arrowButton.style.padding = '10px';
    arrowButton.style.fontSize = '24px';
    arrowButton.style.zIndex = '998';
    arrowButton.style.cursor = 'pointer';
    arrowButton.style.color = '#B4B4B4';
    arrowButton.style.borderRadius = '5px 0 0 5px';
    arrowButton.style.transition = 'transform 0.3s ease, right 0.3s ease';

    // Making Panel available for the whole script
    window.mainPanel = document.createElement('div');
    mainPanel.style.position = 'fixed';
    mainPanel.style.top = '0';
    mainPanel.style.right = '-250px'; // Initially hidden
    mainPanel.style.height = '100%';
    mainPanel.style.width = '250px';
    mainPanel.style.backgroundColor = CONFIG.panelBackground;
    mainPanel.style.transition = 'right 0.3s ease';
    mainPanel.style.zIndex = '999';

    // Create the header above the button
    const mainPanelHeader = document.createElement('div');
    mainPanelHeader.innerText = 'ChatGPT Tools';
    mainPanelHeader.style.margin = '20px';
    mainPanelHeader.style.padding = '10px';
    mainPanelHeader.style.fontSize = '19px';
    mainPanelHeader.style.fontWeight = '550';
    mainPanelHeader.style.color = '#ECECEC';
    mainPanelHeader.style.textAlign = 'center';

    // Create the background overlay
    window.mainPanelOverlay = document.createElement('div');
    mainPanelOverlay.style.position = 'fixed';
    mainPanelOverlay.style.top = '0';
    mainPanelOverlay.style.left = '0';
    mainPanelOverlay.style.width = '100%';
    mainPanelOverlay.style.height = '100%';
    mainPanelOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.0)';
    mainPanelOverlay.style.zIndex = '997';
    mainPanelOverlay.style.display = 'none'; // Initially hidden

    // Toggle panel visibility
    arrowButton.addEventListener('click', () => {
        if (mainPanel.style.right === '-250px') {
            mainPanel.style.right = '0';
            arrowButton.style.right = '250px';
            arrowButton.style.transform = 'rotate(180deg)';
            mainPanelOverlay.style.display = 'block'; // Show overlay
        } else {
            closePanel();
        }
    });

    // Close panel and remove overlay
    mainPanelOverlay.addEventListener('click', () => {
        closePanel();
    });

    function closePanel() {
        mainPanel.style.right = '-250px';
        arrowButton.style.right = '0';
        arrowButton.style.transform = 'rotate(0deg)';
        mainPanelOverlay.style.display = 'none'; // Hide overlay
    }

    document.body.appendChild(arrowButton);
    document.body.appendChild(mainPanelOverlay);
    document.body.appendChild(mainPanel);
    mainPanel.appendChild(mainPanelHeader);
}



// ================================================================== LOREBOOK ====================================================================

function lorebookScript() {

    // Create a function to detect mobile
    function isMobile() {
        return window.innerWidth <= 768;
    }

    // Manage Lorebook Button
    window.openLorebookButton = document.createElement('div');
    window.openLorebookButton.innerHTML = `
        <button id="toggle-lorebook-panel"
            style="
                display: flex;
                align-items: center;
                gap: 8px;
                position: relative;
                top: 10px;
                right: 0px;
                left: 10px;
                padding: 7px 15px;
                background: transparent;
                color: #b0b0b0;
                border: none;
                border-radius: 8px;
                font-size: 16px;
                text-align: left;
                cursor: pointer;
                width: 90%;
                transition: background-color 0.1s, color 0.1s;
                z-index: 1001;">
            <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" class="mb-[-1px]">
                <path d="M6 3C4.89543 3 4 3.89543 4 5V13C4 14.1046 4.89543 15 6 15L6 3Z" fill="currentColor"></path>
                <path d="M7 3V15H8.18037L8.4899 13.4523C8.54798 13.1619 8.69071 12.8952 8.90012 12.6858L12.2931 9.29289C12.7644 8.82153 13.3822 8.58583 14 8.58578V3.5C14 3.22386 13.7761 3 13.5 3H7Z" fill="currentColor"></path>
                <path d="M11.3512 15.5297L9.73505 15.8529C9.38519 15.9229 9.07673 15.6144 9.14671 15.2646L9.46993 13.6484C9.48929 13.5517 9.53687 13.4628 9.60667 13.393L12.9996 10C13.5519 9.44771 14.4473 9.44771 14.9996 10C15.5519 10.5523 15.5519 11.4477 14.9996 12L11.6067 15.393C11.5369 15.4628 11.448 15.5103 11.3512 15.5297Z" fill="currentColor"></path>
            </svg>
            Manage Lorebook
        </button>
    `;

    const lorebookButtonElement = openLorebookButton.querySelector('button');
    lorebookButtonElement.onmouseover = () => {
        lorebookButtonElement.style.backgroundColor = '#212121';
        lorebookButtonElement.style.color = '#ffffff';
    };
    lorebookButtonElement.onmouseout = () => {
        lorebookButtonElement.style.backgroundColor = 'transparent';
        lorebookButtonElement.style.color = '#b0b0b0';
    };

// Create the main panel container
const lorebookPanel = document.createElement('div');
lorebookPanel.id = 'lorebookManagerPanel';
lorebookPanel.style.position = 'fixed';
lorebookPanel.style.top = '50%';
lorebookPanel.style.left = '50%';
lorebookPanel.style.transform = 'translate(-50%, -50%)';
lorebookPanel.style.zIndex = '1000';
lorebookPanel.style.display = 'none';
lorebookPanel.style.backgroundColor = '#2F2F2F';
lorebookPanel.style.borderRadius = '20px';
lorebookPanel.style.padding = '10px';

document.body.appendChild(lorebookPanel);

// Add close button for the panel
const lorebookCloseButton = document.createElement('button');
lorebookCloseButton.style.position = 'absolute';
lorebookCloseButton.style.borderRadius = '50%';
lorebookCloseButton.style.top = '20px';
lorebookCloseButton.style.right = '20px';
lorebookCloseButton.style.backgroundColor = 'transparent';
lorebookCloseButton.style.cursor = 'pointer';
lorebookCloseButton.style.width = '32px';
lorebookCloseButton.style.height = '32px';
lorebookCloseButton.style.display = 'flex';
lorebookCloseButton.style.alignItems = 'center';
lorebookCloseButton.style.justifyContent = 'center';
lorebookCloseButton.style.zIndex = '1001';

const lorebookCloseSymbol = document.createElement('span');
lorebookCloseSymbol.innerText = '✕';
lorebookCloseSymbol.style.color = '#FBFBFE';
lorebookCloseSymbol.style.fontSize = '14px';
lorebookCloseSymbol.style.fontWeight = '550';
lorebookCloseSymbol.style.transform = 'translateY(-1px) translateX(0.4px)';

lorebookCloseButton.appendChild(lorebookCloseSymbol);

lorebookCloseButton.addEventListener('mouseenter', () => {
  lorebookCloseButton.style.backgroundColor = '#676767';
});
lorebookCloseButton.addEventListener('mouseleave', () => {
  lorebookCloseButton.style.backgroundColor = 'transparent';
});
const closeLorebookPanel = () => {
  lorebookPanel.style.display = 'none';
  hideOverlay();
};
lorebookCloseButton.addEventListener('click', closeLorebookPanel);
lorebookPanel.appendChild(lorebookCloseButton);

// (Mobile) Show/Close Profiles button
const showProfilesButton = document.createElement('button');
showProfilesButton.innerText = 'Show Profiles';
showProfilesButton.style.padding = '8px';
showProfilesButton.style.border = '0.2px solid #4E4E4E';
showProfilesButton.style.backgroundColor = 'transparent';
showProfilesButton.style.color = '#fff';
showProfilesButton.style.borderRadius = '20px';
showProfilesButton.style.width = '90%';
showProfilesButton.style.cursor = 'pointer';
showProfilesButton.style.margin = '10px auto';
showProfilesButton.style.display = 'none'; // Hidden on desktop

showProfilesButton.onmouseover = () => {
  showProfilesButton.style.backgroundColor = '#424242';
};
showProfilesButton.onmouseout = () => {
  showProfilesButton.style.backgroundColor = 'transparent';
};

// (Mobile) Show/Close Profiles button
showProfilesButton.addEventListener('click', () => {
    const currentlyHidden = (lorebookProfilePanel.style.display === 'none');

    // Toggle the panel
    lorebookProfilePanel.style.display = currentlyHidden ? 'block' : 'none';

    // On mobile, replace the big heading's text
    if (isMobile()) {
        lorebookEntriesTitle.innerText = currentlyHidden
            ? 'Profiles' // when the list is visible
            : 'Manage Lorebook Entries';
        // Hide the smaller label altogether on mobile
        profileslabel.style.display = 'none';
    }

    // Toggle button text
    showProfilesButton.innerText = currentlyHidden ? 'Close Profiles' : 'Show Profiles';

    // Toggle the close button for mobile
    if (isMobile()) {
        lorebookCloseButton.style.display =
            lorebookProfilePanel.style.display === 'block'
                ? 'none'
                : 'flex';
    }
});

// Open the Lorebook Panel
openLorebookButton.addEventListener('click', () => {
  lorebookPanel.style.display = lorebookPanel.style.display === 'none' ? 'block' : 'none';
  showOverlay();
  loadProfileEntries();
  updateLayout();
});

// Profiles Title
// -- PROFILES LABEL (the smaller text) --
    const profileslabel = document.createElement('h3');
    profileslabel.innerText = 'Profiles';
    profileslabel.style.color = '#ffffff';
    profileslabel.style.textAlign = 'center';
    profileslabel.style.marginBottom = '5px';
 //   profilesOverlay.appendChild(profilesTitleOverlay);

// Profile Management Panel
const lorebookProfilePanel = document.createElement('div');
lorebookProfilePanel.id = 'lorebookProfilePanel';
lorebookProfilePanel.style.float = 'left';
lorebookProfilePanel.style.width = '20%';
lorebookProfilePanel.style.borderRight = '0.5px solid #444444';
lorebookProfilePanel.style.height = '95%';

// Create the profile list container
const profileList = document.createElement('div');
profileList.id = 'profileList';
profileList.style.height = '95%';
profileList.style.color = 'white';
profileList.style.overflowY = 'auto';

// Add Profiles Button
    const addProfileButton = document.createElement('button');
    addProfileButton.textContent = 'Add Profile';
    addProfileButton.style.margin = '-59px auto';
//    addProfileButton.style.align = 'center';
    addProfileButton.style.marginLeft = '7px';
    addProfileButton.style.display = 'block';
    addProfileButton.style.padding = '10px';
    addProfileButton.style.border = CONFIG.BUTTON_OUTLINE;
    addProfileButton.style.width = '86%';
    addProfileButton.style.backgroundColor = 'transparent';
    addProfileButton.style.borderRadius = '60px';
    addProfileButton.style.cursor = 'pointer';

    addProfileButton.addEventListener('mouseenter', () => {
        addProfileButton.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT;
    });

    addProfileButton.addEventListener('mouseleave', () => {
        addProfileButton.style.backgroundColor = 'transparent';
    });



addProfileButton.addEventListener('click', () => {
  const profileName = prompt('Enter profile name:');
  if (profileName) {
    let lorebookEntries = getAllLorebookEntries();
    if (!lorebookEntries[profileName]) {
      lorebookEntries[profileName] = [];
      setAllLorebookEntries(lorebookEntries);
      loadProfiles();
    } else {
      alert('Profile already exists.');
    }
  }
});

/************************************************************
 * Profile Selection Functionality
 ************************************************************/
function loadProfiles() {
  profileList.innerHTML = '';
  let lorebookEntries = getAllLorebookEntries();

  Object.keys(lorebookEntries).forEach(profile => {
    // Entire item is clickable, text left-aligned
    const profileItem = document.createElement('div');
    profileItem.innerText = profile;
    profileItem.style.marginBottom = '5px';
    profileItem.style.cursor = 'pointer';
    profileItem.style.borderRadius = '5px';
    profileItem.style.width = '95%';
    profileItem.style.display = 'flex';               // ← make it a flex container
    profileItem.style.alignItems = 'center';          // center vertically
    profileItem.style.justifyContent = 'space-between'; // place removeButton on far right
    profileItem.style.textAlign = 'left';             // text at left
    // Highlight if selected
    profileItem.style.backgroundColor =
      profile === getCurrentProfile() ? '#424242' : '#2F2F2F';
    profileItem.style.padding = '5px 10px';

    // Click entire item to set current profile
    profileItem.addEventListener('click', () => {
      setCurrentProfile(profile);
      loadProfiles();
      loadProfileEntries();
    });




// Create the remove button
const removeButton = document.createElement('button');
removeButton.style.cssText = `
    color: #B4B4B4;
    background-color: transparent;
    cursor: pointer;
    border: none;
    font-size: 14px;
    padding: 0;
    outline: none; /* Optional: remove focus outline */
    display: flex; /* Optional: center-align the SVG */
    align-items: center; /* Optional: center-align the SVG */
`;

// Add the SVG icon for the button
removeButton.innerHTML = `
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none"
         xmlns="http://www.w3.org/2000/svg" class="icon-sm">
        <path fill-rule="evenodd" clip-rule="evenodd"
            d="
                M10.5555 4 C10.099 4 9.70052 4.30906 9.58693 4.75114
                L9.29382 5.8919 H14.715 L14.4219 4.75114
                C14.3083 4.30906 13.9098 4 13.4533 4H10.5555
                M16.7799 5.8919 L16.3589 4.25342
                C16.0182 2.92719 14.8226 2 13.4533 2H10.5555
                C9.18616 2 7.99062 2.92719 7.64985 4.25342
                L7.22886 5.8919 H4
                C3.44772 5.8919 3 6.33961 3 6.8919
                C3 7.44418 3.44772 7.8919 4 7.8919H4.10069
                L5.31544 19.3172 C5.47763 20.8427 6.76455 22 8.29863 22H15.7014
                C17.2354 22 18.5224 20.8427 18.6846 19.3172 L19.8993 7.8919 H20
                C20.5523 7.8919 21 7.44418 21 6.8919
                C21 6.33961 20.5523 5.8919 20 5.8919H16.7799
                M17.888 7.8919 H6.11196 L7.30423 19.1057
                C7.3583 19.6142 7.78727 20 8.29863 20H15.7014
                C16.2127 20 16.6417 19.6142 16.6958 19.1057 L17.888 7.8919
                M10 10 C10.5523 10 11 10.4477 11 11V16
                C11 16.5523 10.5523 17 10 17
                C9.44772 17 9 16.5523 9 16V11
                C9 10.4477 9.44772 10 10 10
                M14 10 C14.5523 10 15 10.4477 15 11V16
                C15 16.5523 14.5523 17 14 17
                C13.4477 17 13 16.5523 13 16V11
                C13 10.4477 13.4477 10 14 10
            "
            fill="currentColor"/>
    </svg>
`;

// Add hover color change events
removeButton.addEventListener('mouseover', () => {
    removeButton.style.color = '#E3E3E3';
});

removeButton.addEventListener('mouseout', () => {
    removeButton.style.color = '#B4B4B4';
});

// Add click behavior to stop parent click from firing and trigger actions
removeButton.addEventListener('click', (e) => {
    e.stopPropagation();
    deleteProfile(profile); // Replace with your profile deletion logic
    loadProfiles();
    loadProfileEntries();
});

// Append remove button to the profile item
profileItem.appendChild(removeButton);

    profileList.appendChild(profileItem);
  });
}

/************************************************************
 * Lorebook Entries Title (will switch to "Profiles" on mobile)
 ************************************************************/
const lorebookEntriesTitle = document.createElement('h3');
lorebookEntriesTitle.innerText = 'Manage Lorebook Entries';
lorebookEntriesTitle.style.fontWeight = '550';
lorebookEntriesTitle.style.color = '#ffffff';
lorebookEntriesTitle.style.textAlign = 'center';
lorebookEntriesTitle.style.fontSize = '24px';
lorebookEntriesTitle.style.marginTop = '10px';
lorebookEntriesTitle.style.position = 'relative';
//lorebookEntriesTitle.style.marginLeft = '40%';

lorebookEntriesTitle.style.marginBottom = '15px';

// -- [SEARCH BAR + SORT BUTTON] --
const controlBar = document.createElement('div');
//controlBar.style.display = 'flex';
//controlBar.style.gap = '10px';
//controlBar.style.alignItems = 'center';
controlBar.style.marginLeft = '25%';
controlBar.style.marginBottom = '5px';
controlBar.style.width = '100%';

// Search Input
const searchInput = document.createElement('input');
searchInput.type = 'text';
searchInput.placeholder = 'Search entries...';
searchInput.style.width = '200px';
searchInput.style.padding = '8px';
searchInput.style.border = '1px solid #444444';
searchInput.style.borderRadius = '8px';
searchInput.style.backgroundColor = '#1e1e1e';
searchInput.style.color = '#dddddd';

// Trigger loadProfileEntries() whenever user types
searchInput.addEventListener('input', () => {
  loadProfileEntries();
});

// Sort Button
let sortAlphabetical = false;
const sortButton = document.createElement('button');
sortButton.innerText = 'Sort: Date';
sortButton.style.padding = '8px 15px';
sortButton.style.border = '0.2px solid #4E4E4E';
sortButton.style.backgroundColor = 'transparent';
sortButton.style.color = '#fff';
sortButton.style.borderRadius = '20px';
sortButton.style.cursor = 'pointer';
sortButton.style.marginLeft = '5px';

sortButton.addEventListener('click', () => {
  sortAlphabetical = !sortAlphabetical;
  sortButton.innerText = sortAlphabetical ? 'Sort: A-Z' : 'Sort: Date';
  loadProfileEntries();
});

controlBar.appendChild(searchInput);
controlBar.appendChild(sortButton);

// Profile Entries List
const profileEntriesList = document.createElement('div');
profileEntriesList.id = 'profileEntriesList';
profileEntriesList.style.marginTop = '20px';
profileEntriesList.style.overflowY = 'auto';

// Header for Inputs
const entrieslabel = document.createElement('div');
entrieslabel.textContent = 'Enter keys and description:';
entrieslabel.style.color = '#dddddd';
entrieslabel.style.fontSize = '14px';
entrieslabel.style.marginBottom = '5px';
entrieslabel.style.marginTop = '5px';
entrieslabel.style.marginLeft = '23%';

// Create key-value input fields
const inputContainer = document.createElement('div');
inputContainer.id = 'inputContainer';
inputContainer.style.marginTop = '10px';
inputContainer.style.display = 'flex';
inputContainer.style.flexDirection = 'column';
inputContainer.style.alignItems = 'center';
inputContainer.style.margin = '0 auto';

const lorebookKeyInput = document.createElement('input');
lorebookKeyInput.type = 'text';
lorebookKeyInput.placeholder = 'Entry Keywords (comma-separated)';
lorebookKeyInput.style.width = '90%';
lorebookKeyInput.style.marginBottom = '5px';
lorebookKeyInput.style.padding = '10px';
lorebookKeyInput.style.border = '1px solid #444444';
lorebookKeyInput.style.borderRadius = '8px';
lorebookKeyInput.style.backgroundColor = '#1e1e1e';
lorebookKeyInput.style.color = '#dddddd';

const lorebookValueInput = document.createElement('textarea');
lorebookValueInput.placeholder = ' ';
lorebookValueInput.style.width = '90%';
lorebookValueInput.style.marginBottom = '5px';
lorebookValueInput.style.padding = '10px';
lorebookValueInput.style.border = '1px solid #444444';
lorebookValueInput.style.borderRadius = '8px';
lorebookValueInput.style.backgroundColor = '#1e1e1e';
lorebookValueInput.style.color = '#dddddd';
lorebookValueInput.style.height = '100px';
lorebookValueInput.style.resize = 'vertical';
lorebookValueInput.maxLength = 1000;
lorebookValueInput.style.overflow = 'auto';

const charCounter = document.createElement('div');
charCounter.style.color = '#dddddd';
charCounter.style.fontSize = '12px';
charCounter.style.marginTop = '0px';
charCounter.style.marginBottom = '15px';
charCounter.style.textAlign = 'right';
charCounter.style.marginRight = '-87%';
charCounter.style.color = 'grey';
charCounter.textContent = `0/${lorebookValueInput.maxLength}`;

lorebookValueInput.addEventListener('input', () => {
  charCounter.textContent = `${lorebookValueInput.value.length}/${lorebookValueInput.maxLength}`;
});

// Save Entry button, also important for editing
const lorebookSaveButton = document.createElement('button');
lorebookSaveButton.innerText = 'Add Entry';
lorebookSaveButton.style.padding = '10px 20px';
lorebookSaveButton.style.border = '0.2px solid #4E4E4E';
lorebookSaveButton.style.backgroundColor = '#2F2F2F';
lorebookSaveButton.style.color = '#fff';
lorebookSaveButton.style.borderRadius = '50px';
lorebookSaveButton.style.cursor = 'pointer';
lorebookSaveButton.style.width = '95%';

    lorebookSaveButton.addEventListener('mouseenter', () => {
        lorebookSaveButton.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT;
    });

    lorebookSaveButton.addEventListener('mouseleave', () => {
        lorebookSaveButton.style.backgroundColor = 'transparent';
    });



// DOM structure
lorebookPanel.appendChild(lorebookEntriesTitle);
lorebookPanel.appendChild(showProfilesButton);
lorebookPanel.appendChild(lorebookProfilePanel);
lorebookProfilePanel.appendChild(profileslabel);
lorebookProfilePanel.appendChild(profileList);
lorebookProfilePanel.appendChild(addProfileButton);
lorebookPanel.appendChild(controlBar);
lorebookPanel.appendChild(profileEntriesList);
lorebookPanel.appendChild(entrieslabel);
lorebookPanel.appendChild(inputContainer);
inputContainer.appendChild(lorebookKeyInput);
inputContainer.appendChild(lorebookValueInput);
inputContainer.appendChild(charCounter);
inputContainer.appendChild(lorebookSaveButton);


    let isEditing = false;
    let editingIndex = -1; // We'll track the array index if editing

    lorebookSaveButton.addEventListener('click', () => {
        const rawKey = lorebookKeyInput.value.trim().toLowerCase();
        const value = lorebookValueInput.value;
        const currentProfile = getCurrentProfile();

        if (!currentProfile) {
            alert('Please select a profile.');
            return;
        }

        if (!rawKey) {
            alert('Please enter a key for the entry.');
            return;
        }

        const newKeySet = parseKeyToSet(rawKey);

        let lorebookEntries = getAllLorebookEntries();
        if (!lorebookEntries[currentProfile]) {
            lorebookEntries[currentProfile] = [];
        }

        if (!canAddKey(newKeySet, lorebookEntries[currentProfile], isEditing, editingIndex)) {
            return;
        }

        const newEntry = `<[Lorebook: ${rawKey}] ${value}>`;

        if (isEditing && editingIndex >= 0) {
            lorebookEntries[currentProfile][editingIndex] = newEntry;
            isEditing = false;
            editingIndex = -1;
        } else {
            lorebookEntries[currentProfile].push(newEntry);
        }

        setAllLorebookEntries(lorebookEntries);

        // Reset form
        lorebookKeyInput.value = '';
        lorebookValueInput.value = '';
        charCounter.textContent = `0/${lorebookValueInput.maxLength}`;
        loadProfileEntries();
    });

    // Modified loadProfileEntries to support searching + sorting
    function loadProfileEntries() {
        profileEntriesList.innerHTML = '';
        profileEntriesList.style.display = 'flex';
        profileEntriesList.style.flexDirection = 'column';
        profileEntriesList.style.alignItems = 'center';
        profileEntriesList.style.margin = '0 auto';

        const currentProfile = getCurrentProfile();
        if (!currentProfile) return;

        let lorebookEntries = getAllLorebookEntries();
        let entriesArray = lorebookEntries[currentProfile] || [];

        // Filter by search query
        const query = searchInput.value.trim().toLowerCase();
        if (query) {
            entriesArray = entriesArray.filter(entry =>
                entry.toLowerCase().includes(query)
            );
        }

        // Sort
        if (sortAlphabetical) {
            // We'll sort by the key portion if we can parse it, fallback to the full string
            entriesArray.sort((a, b) => {
                const aMatch = a.match(/^<\[Lorebook:\s*(.*?)\]\s*(.*?)>$/);
                const bMatch = b.match(/^<\[Lorebook:\s*(.*?)\]\s*(.*?)>$/);

                let aKey = aMatch ? aMatch[1] : a;
                let bKey = bMatch ? bMatch[1] : b;
                return aKey.localeCompare(bKey);
            });
        }
        // Else default is the chronological order in localStorage

        entriesArray.forEach((entry) => {
            const entryItem = document.createElement('div');
            entryItem.style.padding = '10px';
            entryItem.style.marginBottom = '12px';
            entryItem.style.borderRadius = '8px';
            entryItem.style.backgroundColor = '#424242';
            entryItem.style.position = 'relative';
            entryItem.style.color = 'white';
            entryItem.style.flexDirection = 'column';
            entryItem.style.width = '90%';

            let matched = entry.match(/^<\[Lorebook:\s*(.*?)\]\s*(.*?)>$/);
            let keyPart = '';
            let textPart = '';
            if (matched) {
                keyPart = matched[1];
                textPart = matched[2];
            }

            const keyElement = document.createElement('div');
            keyElement.innerText = keyPart;
            keyElement.style.fontWeight = 'bold';
            keyElement.style.marginBottom = '10px';
            entryItem.appendChild(keyElement);

            const valueElement = document.createElement('div');
            valueElement.innerText = textPart;
            entryItem.appendChild(valueElement);

            entryItem.addEventListener('click', () => {
                lorebookKeyInput.value = keyPart;
                lorebookValueInput.value = textPart;
                charCounter.textContent = `${textPart.length}/${lorebookValueInput.maxLength}`;
                isEditing = true;
                editingIndex = findFullIndexInStorage(entry);
            });

// Create button
const removeButton = document.createElement('button');
removeButton.style.cssText = `
    color: #B4B4B4;
    background-color: transparent;
    cursor: pointer;
    position: absolute;
    top: 10px;
    right: 10px;
    border: none;       /* optional: remove default button border */
    outline: none;      /* optional: remove focus outline */
    padding: 0;         /* optional: remove default button padding */
`;

// Insert the same SVG icon you used in deleteButton
removeButton.innerHTML = `
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none"
         xmlns="http://www.w3.org/2000/svg" class="icon-sm">
        <path fill-rule="evenodd" clip-rule="evenodd"
            d="
                M10.5555 4 C10.099 4 9.70052 4.30906 9.58693 4.75114
                L9.29382 5.8919 H14.715 L14.4219 4.75114
                C14.3083 4.30906 13.9098 4 13.4533 4H10.5555
                M16.7799 5.8919 L16.3589 4.25342
                C16.0182 2.92719 14.8226 2 13.4533 2H10.5555
                C9.18616 2 7.99062 2.92719 7.64985 4.25342
                L7.22886 5.8919 H4
                C3.44772 5.8919 3 6.33961 3 6.8919
                C3 7.44418 3.44772 7.8919 4 7.8919H4.10069
                L5.31544 19.3172 C5.47763 20.8427 6.76455 22 8.29863 22H15.7014
                C17.2354 22 18.5224 20.8427 18.6846 19.3172 L19.8993 7.8919 H20
                C20.5523 7.8919 21 7.44418 21 6.8919
                C21 6.33961 20.5523 5.8919 20 5.8919H16.7799
                M17.888 7.8919 H6.11196 L7.30423 19.1057
                C7.3583 19.6142 7.78727 20 8.29863 20H15.7014
                C16.2127 20 16.6417 19.6142 16.6958 19.1057 L17.888 7.8919
                M10 10 C10.5523 10 11 10.4477 11 11V16
                C11 16.5523 10.5523 17 10 17
                C9.44772 17 9 16.5523 9 16V11
                C9 10.4477 9.44772 10 10 10
                M14 10 C14.5523 10 15 10.4477 15 11V16
                C15 16.5523 14.5523 17 14 17
                C13.4477 17 13 16.5523 13 16V11
                C13 10.4477 13.4477 10 14 10
            "
            fill="currentColor"/>
    </svg>
`;

// Add hover color change events
removeButton.addEventListener('mouseover', () => {
  removeButton.style.color = '#E3E3E3';
});

removeButton.addEventListener('mouseout', () => {
  removeButton.style.color = '#B4B4B4';
});

// Add click behavior
removeButton.addEventListener('click', (event) => {
  event.stopPropagation();
  removeEntry(currentProfile, entry);
});

// Append to your entry item
entryItem.appendChild(removeButton);

            entryItem.appendChild(removeButton);
            profileEntriesList.appendChild(entryItem);
        });
    }

    // Because we filter/sort entries before display, find the real index in localStorage
    function findFullIndexInStorage(entryString) {
        const currentProfile = getCurrentProfile();
        let lorebookEntries = getAllLorebookEntries();
        let entriesArray = lorebookEntries[currentProfile] || [];
        return entriesArray.findIndex(e => e === entryString);
    }

    function removeEntry(profileName, entryString) {
        let lorebookEntries = getAllLorebookEntries();
        if (!lorebookEntries[profileName]) return;
        let arr = lorebookEntries[profileName];
        const realIndex = arr.findIndex(e => e === entryString);
        if (realIndex >= 0) {
            arr.splice(realIndex, 1);
            lorebookEntries[profileName] = arr;
            setAllLorebookEntries(lorebookEntries);
            loadProfileEntries();
        }
    }

    function getAllLorebookEntries() {
        let data = localStorage.getItem('lorebookEntries');
        if (!data) {
            return {};
        }
        try {
            return JSON.parse(data);
        } catch (e) {
            console.error('Error parsing lorebookEntries:', e);
            return {};
        }
    }

    function setAllLorebookEntries(lorebookEntries) {
        localStorage.setItem('lorebookEntries', JSON.stringify(lorebookEntries));
    }

    function deleteProfile(profileName) {
        let lorebookEntries = getAllLorebookEntries();
        if (lorebookEntries.hasOwnProperty(profileName)) {
            delete lorebookEntries[profileName];
            setAllLorebookEntries(lorebookEntries);
            if (getCurrentProfile() === profileName) {
                localStorage.removeItem('selectedProfile.lorebook');
            }
        }
    }

    function getCurrentProfile() {
        const selectedProfile = localStorage.getItem('selectedProfile.lorebook');
        return selectedProfile ? selectedProfile : null;
    }

    function setCurrentProfile(profileName) {
        localStorage.setItem('selectedProfile.lorebook', profileName);
    }

    function parseKeyToSet(keyString) {
        return new Set(
            keyString
                .split(',')
                .map(item => item.trim())
                .filter(Boolean)
        );
    }

    function canAddKey(newKeySet, allEntries, isEditing, editingIndex) {
        for (let i = 0; i < allEntries.length; i++) {
            if (isEditing && i === editingIndex) continue;
            const match = allEntries[i].match(/^<\[Lorebook:\s*(.*?)\]\s*(.*?)>$/);
            if (!match) continue;

            const existingKeyString = match[1];
            const existingKeySet = parseKeyToSet(existingKeyString);

            // Check for exact match
            if (setsAreEqual(newKeySet, existingKeySet)) {
                alert(`Key "${existingKeyString}" already exists for this profile.`);
                return false;
            }
            // Check for subset or superset conflict
            if (isSubset(newKeySet, existingKeySet) || isSubset(existingKeySet, newKeySet)) {
                alert(`Key "${existingKeyString}" is in conflict (subset/superset) with the new key.`);
                return false;
            }
        }
        return true;
    }

    function setsAreEqual(a, b) {
        if (a.size !== b.size) return false;
        for (let val of a) {
            if (!b.has(val)) return false;
        }
        return true;
    }

    function isSubset(smallerSet, biggerSet) {
        for (let val of smallerSet) {
            if (!biggerSet.has(val)) return false;
        }
        return true;
    }

    // This function adjusts layout on resize or after toggling



// updateLayout() - handle mobile vs desktop
function updateLayout() {
    if (isMobile()) {
        // MOBILE LAYOUT
        lorebookPanel.style.width = '90%';
        lorebookPanel.style.height = '90%';

        lorebookProfilePanel.style.display = 'none'; // hidden by default
        lorebookProfilePanel.style.width = '100%';
        lorebookProfilePanel.style.borderRight = 'none';
        lorebookProfilePanel.style.flexDirection = 'column';
        lorebookProfilePanel.style.alignItems = 'center';
        lorebookProfilePanel.style.justifyContent = 'start';
        lorebookProfilePanel.style.textAlign = 'center';
        lorebookProfilePanel.style.marginTop = '0px';
        lorebookProfilePanel.style.marginLeft = '2.5%';

        entrieslabel.style.marginLeft = '5%';
        controlBar.style.marginLeft = '5%';
        addProfileButton.style.marginLeft = '0px';
        profileList.style.height = '90%';
        addProfileButton.style.width = '95%';
        charCounter.style.marginRight = '-80%';

        // Always hide the smaller label on mobile
        profileslabel.style.display = 'none';

        // This sets the big title back to "Manage Lorebook Entries"
        // until the user opens profiles
        lorebookEntriesTitle.innerText = 'Manage Lorebook Entries';

        showProfilesButton.style.display = 'block';
        showProfilesButton.style.margin = '10px auto';


        if (lorebookProfilePanel.style.display === 'none') {
            lorebookCloseButton.style.display = 'flex';
        }

        // --- BLUNT “5% STEPS” LOGIC ---
        // Grab the current panel height
        //   (the actual offsetHeight of the container
        //    or you could compare window.innerHeight, etc.)
    const panelHeight = lorebookPanel.offsetHeight;
    let entriesPercent = 10;

    if (panelHeight >= 500 && panelHeight < 600) {
        entriesPercent = 15;
    } else if (panelHeight >= 600 && panelHeight < 650) {
        entriesPercent = 20;
    } else if (panelHeight >= 650 && panelHeight < 700) {
        entriesPercent = 30;
    } else if (panelHeight >= 700 && panelHeight < 750) {
        entriesPercent = 35;
    } else if (panelHeight >= 750 && panelHeight < 800) {
        entriesPercent = 40; // Could be higher than initial 30
    } else if (panelHeight >= 800 && panelHeight < 850) {
        entriesPercent = 44;
    } else if (panelHeight >= 850 && panelHeight < 900) {
        entriesPercent = 48;
    } else if (panelHeight >= 900) {
        entriesPercent = 52;
    }

    profileEntriesList.style.height = entriesPercent + '%';

    } else {
        // DESKTOP LAYOUT
        lorebookPanel.style.width = '1000px';
        lorebookPanel.style.height = '700px';

        lorebookProfilePanel.style.display = 'block';
        lorebookProfilePanel.style.width = '20%';
        lorebookProfilePanel.style.borderRight = '0.5px solid #444444';
        lorebookProfilePanel.style.marginTop = '-40px';
        lorebookProfilePanel.style.marginLeft = '0px';

        // Show the smaller label on desktop only
        profileslabel.style.display = 'block';

        lorebookEntriesTitle.innerText = 'Manage Lorebook Entries';
        profileList.style.height = '95%';
        addProfileButton.style.width = '86%';
        addProfileButton.style.marginLeft = '7px';

        showProfilesButton.style.display = 'none';
        lorebookCloseButton.style.display = 'flex';

        entrieslabel.style.marginLeft = '24%';
        controlBar.style.marginLeft = '24%';
        profileEntriesList.style.height = '285px';
        charCounter.style.marginRight = '-87%';
    }
}

    // Listen for window resize
    window.addEventListener('resize', updateLayout);

    // Initial load
    loadProfiles();
}


// ==================================================================== RULES ====================================================================

function rulesScript() {
    // Profiles object structure: { profileName: [arrayOfRules], ... }
    let profiles = {};
    let currentProfile = null;
    let customRules = [];
    let currentIndex = 0;

    // Load profiles from localStorage
    const storedRulesProfiles = localStorage.getItem('rulesProfiles');
    if (storedRulesProfiles) {
        profiles = JSON.parse(storedRulesProfiles);
    }

    // Check if there's a previously selected profile stored
   const selectedProfileRules = localStorage.getItem('selectedProfile.Rules');

    if (Object.keys(profiles).length === 0) {
        // If no profiles exist, create a default one
        profiles['Default'] = [];
        saveProfiles();
        currentProfile = 'Default';
    } else {
        // If we have a stored selected profile, use that; otherwise use first available
        if (selectedProfileRules && profiles[selectedProfileRules]) {
            currentProfile = selectedProfileRules;
        } else {
            currentProfile = Object.keys(profiles)[0];
        }
    }

    // Sync customRules with currently selected profile
    loadProfileRules(currentProfile);

    function loadProfileRules(profileName) {
        currentProfile = profileName;
        customRules = profiles[currentProfile] || [];
        // Save the selected profile so it's sticky across sessions
        localStorage.setItem('selectedProfile.Rules', currentProfile);
    }

    function saveProfiles() {
        localStorage.setItem('rulesProfiles', JSON.stringify(profiles));
    }


    // Create Button and Panel UI for Local Storage Key Management
    window.manageRulesButton = document.createElement('div');
    window.manageRulesButton.innerHTML = `
        <button id="toggle-rules-panel"
            style="
                position: relative;
                top: 10px;
                right: 0px;
                left: 10px;
                padding: 7px 15px;
                background: transparent;
                color: #b0b0b0;
                border: none;
                border-radius: 8px;
                font-size: 16px;
                text-align: left;
                cursor: pointer;
                width: 90%;
                display: flex;
                align-items: center;
                gap: 10px;
                transition: background-color 0.1s, color 0.1s;
                z-index: 1001;">
            <svg fill="#B0B0B0" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg"
                 xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px"
                 viewBox="0 0 492.508 492.508" xml:space="preserve"
                 style="padding-right: 0px; margin-left: 1px;">
                <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
                <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
                <g id="SVGRepo_iconCarrier">
                    <g>
                        <g>
                            <path d="M199.493,402.145c0-10.141-8.221-18.361-18.36-18.361H42.475c-10.139,0-18.36,8.221-18.36,18.361
                                c0,3.195,0.818,6.199,2.255,8.816H0v38.067h223.607v-38.067h-26.369C198.674,408.343,199.493,405.34,199.493,402.145z">
                            </path>
                            <path d="M175.898,88.224l117.157,74.396c9.111,4.643,20.43,1.678,26.021-7.129l5.622-8.85
                                c5.938-9.354,3.171-21.75-6.182-27.69L204.592,46.608c-9.352-5.939-21.748-3.172-27.688,6.182l-5.622,8.851
                                C165.692,70.447,167.82,81.952,175.898,88.224z">
                            </path>
                            <path d="M492.456,372.433l-0.082-1.771l-0.146-1.672c-0.075-1.143-0.235-2.159-0.375-3.204c-0.562-4.177-1.521-7.731-2.693-10.946
                                c-2.377-6.386-5.738-11.222-9.866-14.845c-1.027-0.913-2.126-1.714-3.218-2.528l-3.271-2.443
                                c-2.172-1.643-4.387-3.218-6.587-4.815c-2.196-1.606-4.419-3.169-6.644-4.729c-2.218-1.571-4.445-3.125-6.691-4.651
                                c-4.468-3.089-8.983-6.101-13.51-9.103l-6.812-4.464l-6.85-4.405c-4.58-2.911-9.167-5.813-13.785-8.667
                                c-4.611-2.865-9.24-5.703-13.896-8.496l-13.979-8.363l-14.072-8.22l-14.149-8.096l-14.219-7.987l-14.287-7.882l-14.354-7.773
                                c-4.802-2.566-9.599-5.137-14.433-7.653c-4.822-2.529-9.641-5.071-14.498-7.548l-4.398,6.928l-22.17-10.449l24.781-39.026
                                l-117.156-74.395l-60.944,95.974l117.157,74.395l24.781-39.026l18.887,15.622l-4.399,6.929c4.309,3.343,8.657,6.619,12.998,9.91
                                c4.331,3.305,8.698,6.553,13.062,9.808l13.14,9.686l13.211,9.577l13.275,9.474l13.346,9.361l13.422,9.242l13.514,9.095
                                c4.51,3.026,9.045,6.009,13.602,8.964c4.547,2.967,9.123,5.882,13.707,8.792l6.898,4.324l6.936,4.266
                                c4.643,2.818,9.289,5.625,13.985,8.357c2.337,1.383,4.689,2.739,7.055,4.078c2.358,1.349,4.719,2.697,7.106,4
                                c2.383,1.312,4.75,2.646,7.159,3.912l3.603,1.922c1.201,0.64,2.394,1.296,3.657,1.837c5.036,2.194,10.841,3.18,17.63,2.614
                                c3.409-0.305,7.034-0.949,11.054-2.216c1.006-0.317,1.992-0.606,3.061-1.023l1.574-0.58l1.639-0.68
                                c2.185-0.91,4.523-2.063,7.059-3.522C492.513,377.405,492.561,374.799,492.456,372.433z">
                            </path>
                            <path d="M67.897,261.877l113.922,72.341c9.354,5.938,21.75,3.172,27.689-6.181l5.621-8.852
                                c5.592-8.808,3.462-20.311-4.615-26.583L93.358,218.207c-9.111-4.642-20.43-1.678-26.022,7.13l-5.62,8.85
                                C55.775,243.541,58.543,255.938,67.897,261.877z">
                            </path>
                        </g>
                    </g>
                </g>
            </svg>
            Manage Rules
        </button>
    `;
    const rulesButtonElement = manageRulesButton.querySelector('button');
    rulesButtonElement.onmouseover = () => {
        rulesButtonElement.style.backgroundColor = '#212121';
        rulesButtonElement.style.color = '#ffffff';
    };
    rulesButtonElement.onmouseout = () => {
        rulesButtonElement.style.backgroundColor = 'transparent';
        rulesButtonElement.style.color = '#b0b0b0';
    };

    const rulesPanel = document.createElement('div');
    rulesPanel.style.position = 'fixed';
    rulesPanel.style.top = '50%';
    rulesPanel.style.left = '50%';
    rulesPanel.style.transform = 'translate(-50%, -50%)';
    rulesPanel.style.zIndex = 1000;
    rulesPanel.style.backgroundColor = '#2f2f2f';
    rulesPanel.style.padding = '20px';
    rulesPanel.style.borderRadius = '20px';
    rulesPanel.style.display = 'none';
    document.body.appendChild(rulesPanel);

    const isMobile = () => window.innerWidth <= 768;

    const rulesTitle = document.createElement('h2');
    rulesTitle.innerText = 'Manage Rules';
    rulesTitle.style.textAlign = 'center';
    rulesTitle.style.color = '#ffffff';
    rulesTitle.style.fontSize = '24px';
    rulesTitle.style.fontWeight = '550';
    rulesTitle.style.marginBottom = '20px';
    rulesPanel.appendChild(rulesTitle);

    const rulesCloseButton = document.createElement('button');
    rulesCloseButton.style.position = 'absolute';
    rulesCloseButton.style.borderRadius = '50%';
    rulesCloseButton.style.top = '20px';
    rulesCloseButton.style.right = '20px';
    rulesCloseButton.style.backgroundColor = 'transparent';
    rulesCloseButton.style.cursor = 'pointer';
    rulesCloseButton.style.width = '32px';
    rulesCloseButton.style.height = '32px';
    rulesCloseButton.style.display = 'flex';
    rulesCloseButton.style.alignItems = 'center';
    rulesCloseButton.style.justifyContent = 'center';

    const rulesCloseSymbol = document.createElement('span');
    rulesCloseSymbol.innerText = '✕';
    rulesCloseSymbol.style.color = '#FBFBFE';
    rulesCloseSymbol.style.fontSize = '14px';
    rulesCloseSymbol.style.fontWeight = '550';
    rulesCloseSymbol.style.transform = 'translateY(-1px) translateX(0.4px)';

    rulesCloseButton.appendChild(rulesCloseSymbol);

    rulesCloseButton.addEventListener('mouseenter', () => {
        rulesCloseButton.style.backgroundColor = '#676767';
    });

    rulesCloseButton.addEventListener('mouseleave', () => {
        rulesCloseButton.style.backgroundColor = 'transparent';
    });

    const closeRulesPanel = () => {
        rulesPanel.style.display = 'none';
        hideOverlay();
    };

    rulesCloseButton.addEventListener('click', closeRulesPanel);
    rulesPanel.appendChild(rulesCloseButton);

    const container = document.createElement('div');
    container.style.display = 'flex';
    container.style.height = 'calc(100% - 60px)';
    container.style.gap = '20px';
    rulesPanel.appendChild(container);

    // Mobile: show/hide profile panel functionality
    const profilesOverlay = document.createElement('div');
    profilesOverlay.style.position = 'absolute';
    profilesOverlay.style.top = '0';
    profilesOverlay.style.left = '0';
    profilesOverlay.style.width = '100%';
    profilesOverlay.style.height = '100%';
    profilesOverlay.style.backgroundColor = '#2f2f2f';
//    profilesOverlay.style.padding = '20px';
    profilesOverlay.style.display = 'none';
    profilesOverlay.style.zIndex = 1100;
    profilesOverlay.style.borderRadius = '20px';
    profilesOverlay.style.flexDirection = 'column';
    profilesOverlay.style.overflowY = 'auto';
    rulesPanel.appendChild(profilesOverlay);

    const profilesTitleOverlay = document.createElement('h3');
    profilesTitleOverlay.innerText = 'Profiles';
    profilesTitleOverlay.style.color = '#ffffff';
    profilesTitleOverlay.style.textAlign = 'center';
    profilesOverlay.appendChild(profilesTitleOverlay);

    const profilesCloseOverlay = document.createElement('button');
    profilesCloseOverlay.innerText = 'Close';
    profilesCloseOverlay.style.margin = '10px auto';
    profilesCloseOverlay.style.display = 'block';
    profilesCloseOverlay.style.padding = '10px';
    profilesCloseOverlay.style.width = '90%';
    profilesCloseOverlay.style.backgroundColor = 'transparent';
    profilesCloseOverlay.style.color = '#ffffff';
    profilesCloseOverlay.style.border = '1px solid #444';
    profilesCloseOverlay.style.borderRadius = '50px';
    profilesCloseOverlay.style.cursor = 'pointer';
    profilesCloseOverlay.addEventListener('mouseenter', () => {
        profilesCloseOverlay.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT;
    });

    profilesCloseOverlay.addEventListener('mouseleave', () => {
        profilesCloseOverlay.style.backgroundColor = 'transparent';
    });


    profilesCloseOverlay.addEventListener('click', () => {
        profilesOverlay.style.display = 'none';
    });
    profilesOverlay.appendChild(profilesCloseOverlay);

    const profilesListOverlay = document.createElement('div');
    profilesListOverlay.style.flex = '1';
    profilesListOverlay.style.overflowY = 'auto';
    profilesOverlay.appendChild(profilesListOverlay);

    const addProfileButtonOverlay = document.createElement('button');
    addProfileButtonOverlay.textContent = 'Add Profile';
    addProfileButtonOverlay.style.margin = '10px auto';
    addProfileButtonOverlay.style.display = 'block';
    addProfileButtonOverlay.style.padding = '10px';
    addProfileButtonOverlay.style.border = CONFIG.BUTTON_OUTLINE;
    addProfileButtonOverlay.style.width = '90%';
    addProfileButtonOverlay.style.backgroundColor = 'transparent';
    addProfileButtonOverlay.style.borderRadius = '50px';
    addProfileButtonOverlay.style.cursor = 'pointer';

    addProfileButtonOverlay.addEventListener('mouseenter', () => {
        addProfileButtonOverlay.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT;
    });

    addProfileButtonOverlay.addEventListener('mouseleave', () => {
        addProfileButtonOverlay.style.backgroundColor = 'transparent';
    });

    addProfileButtonOverlay.addEventListener('click', () => {
        const newProfileName = prompt('Enter Profile Name:');
        if (newProfileName && !profiles[newProfileName]) {
            profiles[newProfileName] = [];
            saveProfiles();
            renderProfilesList();
        }
    });
    profilesOverlay.appendChild(addProfileButtonOverlay);

    // Left side (profiles)
    const profilesContainer = document.createElement('div');
    profilesContainer.style.width = '21.5%';
    // profilesContainer.style.backgroundColor = '#1E1E1E';
    profilesContainer.style.borderRight = '1px solid #444444'; // Added border width, style, and color
    profilesContainer.style.marginLeft = '-20px';
    profilesContainer.style.display = 'flex';
    profilesContainer.style.flexDirection = 'column';
    profilesContainer.style.marginTop = '-4.7%';
    profilesContainer.style.padding = '10px';
    profilesContainer.style.overflowY = 'auto';


    const profilesTitle = document.createElement('h3');
    profilesTitle.innerText = 'Profiles';
    profilesTitle.style.color = '#ffffff';
    profilesTitle.style.textAlign = 'center';
    profilesContainer.appendChild(profilesTitle);

    const profilesList = document.createElement('div');
    profilesList.style.flex = '1';
    profilesList.style.overflowY = 'auto';
    profilesContainer.appendChild(profilesList);

    const addProfileButton = document.createElement('button');
    addProfileButton.textContent = 'Add Profile';
    addProfileButton.style.margin = '10px auto';
    addProfileButton.style.display = 'block';
    addProfileButton.style.padding = '10px';
    addProfileButton.style.border = CONFIG.BUTTON_OUTLINE;
    addProfileButton.style.width = '90%';
    addProfileButton.style.backgroundColor = 'transparent';
    addProfileButton.style.borderRadius = '50px';
    addProfileButton.style.cursor = 'pointer';

    addProfileButton.addEventListener('mouseenter', () => {
        addProfileButton.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT;
    });

    addProfileButton.addEventListener('mouseleave', () => {
        addProfileButton.style.backgroundColor = 'transparent';
    });

    addProfileButton.addEventListener('click', () => {
        const newProfileName = prompt('Enter Profile Name:');
        if (newProfileName && !profiles[newProfileName]) {
            profiles[newProfileName] = [];
            saveProfiles();
            renderProfilesList();
        }
    });
    profilesContainer.appendChild(addProfileButton);

    // A button to toggle profiles overlay in mobile view
    const toggleProfilesButton = document.createElement('button');
    toggleProfilesButton.innerText = 'Show Profiles';
    toggleProfilesButton.style.display = 'none';
    toggleProfilesButton.style.margin = '10px auto';
    toggleProfilesButton.style.padding = '10px';
    toggleProfilesButton.style.border = 'none';
    toggleProfilesButton.style.width = '90%';
    toggleProfilesButton.style.border = CONFIG.BUTTON_OUTLINE;
    toggleProfilesButton.style.backgroundColor = 'transparent';
    toggleProfilesButton.style.borderRadius = '50px';
    toggleProfilesButton.style.cursor = 'pointer';
    toggleProfilesButton.addEventListener('mouseenter', () => {
        toggleProfilesButton.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT;
    });

    toggleProfilesButton.addEventListener('mouseleave', () => {
        toggleProfilesButton.style.backgroundColor = 'transparent';
    });

    toggleProfilesButton.addEventListener('click', () => {
        profilesOverlay.style.display = 'flex';
        renderProfilesList(); // Update list in overlay
    });

    rulesPanel.insertBefore(toggleProfilesButton, container);

    function renderProfilesList() {
        // Decide whether to render in overlay or side panel
        const targetList = isMobile() ? profilesListOverlay : profilesList;
        targetList.innerHTML = '';

        Object.keys(profiles).forEach(profileName => {
            const profileItem = document.createElement('div');
            profileItem.style.display = 'flex';
            profileItem.style.justifyContent = 'space-between';
            profileItem.style.alignItems = 'center';
            profileItem.style.backgroundColor = profileName === currentProfile ? '#424242' : 'transparent';
            profileItem.style.color = '#ffffff';
            profileItem.style.padding = '5px 10px';
            profileItem.style.borderRadius = '5px';
            profileItem.style.marginBottom = '5px';
            profileItem.style.cursor = 'pointer';

            const nameSpan = document.createElement('span');
            nameSpan.innerText = profileName;
            nameSpan.style.flex = '1';
            profileItem.appendChild(nameSpan);

            profileItem.addEventListener('click', () => {
                loadProfileRules(profileName);
                if (isMobile()) {
                    profilesOverlay.style.display = 'none';
                }
                renderProfilesList();
                renderPanel();
            });

            // Delete button for the profile
            if (profileName !== 'Default') {
                const deleteButton = document.createElement('button');

deleteButton.style.cssText = 'color: #B4B4B4; background-color: transparent; cursor: pointer;';
deleteButton.innerHTML = `
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="icon-sm">
        <path fill-rule="evenodd" clip-rule="evenodd"
            d="
                M10.5555 4 C10.099 4 9.70052 4.30906 9.58693 4.75114 L9.29382 5.8919 H14.715 L14.4219 4.75114 C14.3083 4.30906 13.9098 4 13.4533 4H10.5555
                M16.7799 5.8919 L16.3589 4.25342 C16.0182 2.92719 14.8226 2 13.4533 2H10.5555 C9.18616 2 7.99062 2.92719 7.64985 4.25342 L7.22886 5.8919 H4
                C3.44772 5.8919 3 6.33961 3 6.8919 C3 7.44418 3.44772 7.8919 4 7.8919H4.10069 L5.31544 19.3172 C5.47763 20.8427 6.76455 22 8.29863 22H15.7014
                C17.2354 22 18.5224 20.8427 18.6846 19.3172 L19.8993 7.8919 H20 C20.5523 7.8919 21 7.44418 21 6.8919 C21 6.33961 20.5523 5.8919 20 5.8919H16.7799
                M17.888 7.8919 H6.11196 L7.30423 19.1057 C7.3583 19.6142 7.78727 20 8.29863 20H15.7014 C16.2127 20 16.6417 19.6142 16.6958 19.1057 L17.888 7.8919
                M10 10 C10.5523 10 11 10.4477 11 11V16 C11 16.5523 10.5523 17 10 17 C9.44772 17 9 16.5523 9 16V11 C9 10.4477 9.44772 10 10 10 M14 10
                C14.5523 10 15 10.4477 15 11V16 C15 16.5523 14.5523 17 14 17 C13.4477 17 13 16.5523 13 16V11 C13 10.4477 13.4477 10 14 10
            "
            fill="currentColor"/>
    </svg>
`;


deleteButton.addEventListener('mouseover', () => {
    deleteButton.style.color = '#E3E3E3';
});

deleteButton.addEventListener('mouseout', () => {
    deleteButton.style.color = '#B4B4B4';
});



                deleteButton.addEventListener('click', (event) => {
                    event.stopPropagation();
                    if (confirm(`Delete profile "${profileName}"?`)) {
                        delete profiles[profileName];
                        if (currentProfile === profileName) {
                            currentProfile = Object.keys(profiles)[0];
                            loadProfileRules(currentProfile);
                        }
                        saveProfiles();
                        renderProfilesList();
                        renderPanel();
                    }
                });
                profileItem.appendChild(deleteButton);
            }

            targetList.appendChild(profileItem);
        });
    }

    // Right side rules management
    const rightSideContainer = document.createElement('div');
    rightSideContainer.style.flex = '1';
    rightSideContainer.style.display = 'flex';
    rightSideContainer.style.flexDirection = 'column';
    container.appendChild(rightSideContainer);

    const rulesListContainer = document.createElement('div');
    rulesListContainer.style.overflowY = 'auto';
    rulesListContainer.style.height = 'calc(100% - 81px)';
    rightSideContainer.appendChild(rulesListContainer);

    const addButton = document.createElement('button');
    addButton.textContent = 'Add Rule';
    addButton.style.margin = '15px auto';
    addButton.style.display = 'block';
    addButton.style.padding = '10px';
    addButton.style.width = '90%';
    addButton.style.backgroundColor = 'transparent';
    addButton.style.border = CONFIG.BUTTON_OUTLINE;
    addButton.style.borderRadius = '50px';
    addButton.style.cursor = 'pointer';

    addButton.addEventListener('mouseenter', () => {
        addButton.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT;
    });

    addButton.addEventListener('mouseleave', () => {
        addButton.style.backgroundColor = 'transparent';
    });

    addButton.addEventListener('click', () => {
        const newRule = `<Rule${customRules.length + 1}: Define your rule here>`;
        customRules.push(newRule);
        saveCurrentProfileRules();
        renderPanel();
    });
    rightSideContainer.appendChild(addButton);

    function saveCurrentProfileRules() {
        profiles[currentProfile] = customRules;
        saveProfiles();
    }

    function renderPanel() {
        rulesListContainer.innerHTML = '';

        customRules.forEach((rule, index) => {
            const ruleContainer = document.createElement('div');
            ruleContainer.style.marginBottom = '15px';
            ruleContainer.style.display = 'flex';
            ruleContainer.style.alignItems = 'center';
            ruleContainer.style.width = '95%';
            ruleContainer.style.gap = '5px';
            ruleContainer.style.flexWrap = 'wrap';

            const ruleLabel = document.createElement('label');
            ruleLabel.textContent = `Rule ${index + 1}:`;
            ruleLabel.style.color = 'white';
            ruleLabel.style.flex = '0.3';
            ruleContainer.appendChild(ruleLabel);

            const ruleInput = document.createElement('textarea');
            ruleInput.value = rule.replace(/<Rule\d+: (.*?)>/, '$1');
            ruleInput.style.flex = '2';
            ruleInput.style.padding = '5px';
            ruleInput.style.borderRadius = '5px';
            ruleInput.style.border = '0.5px solid #444444';
            ruleInput.style.backgroundColor = '#1E1E1E';
            ruleInput.style.color = 'gray';
            ruleInput.style.overflowY = 'hidden';
            ruleInput.style.maxWidth = '100%';
            ruleInput.style.boxSizing = 'border-box';
            ruleInput.style.resize = 'none';

            function adjustHeight(element) {
                element.style.height = 'auto';
                element.style.height = `${element.scrollHeight}px`;
            }

            adjustHeight(ruleInput);

            ruleInput.addEventListener('input', () => {
                adjustHeight(ruleInput);
                ruleInput.style.color = '#D16262';
            });

            ruleContainer.appendChild(ruleInput);

            const updateButton = document.createElement('button');
            updateButton.style.padding = '10px';
            updateButton.style.border = 'none';
            updateButton.style.color = '#B4B4B4';
            updateButton.style.borderRadius = '5px';
            updateButton.style.cursor = 'pointer';

            // Adding the SVG as the innerHTML of the button
            updateButton.innerHTML = `
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path fill-rule="evenodd" clip-rule="evenodd"
                      d="
                         M18.1716 1C18.702 1 19.2107 1.21071 19.5858 1.58579L22.4142 4.41421C22.7893 4.78929 23 5.29799 23 5.82843V20C23 21.6569 21.6569
                         23 20 23H4C2.34315 23 1 21.6569 1 20V4C1 2.34315 2.34315 1 4 1H18.1716ZM4 3C3.44772 3 3 3.44772 3 4V20C3 20.5523 3.44772 21 4 21L5
                         21L5 15C5 13.3431 6.34315 12 8 12L16 12C17.6569 12 19 13.3431 19 15V21H20C20.5523 21 21 20.5523 21 20V6.82843C21 6.29799 20.7893
                         5.78929 20.4142 5.41421L18.5858 3.58579C18.2107 3.21071 17.702 3 17.1716 3H17V5C17 6.65685 15.6569 8 14 8H10C8.34315 8 7 6.65685
                         7 5V3H4ZM17 21V15C17 14.4477 16.5523 14 16 14L8 14C7.44772 14 7 14.4477 7 15L7 21L17 21ZM9 3H15V5C15 5.55228 14.5523 6 14 6H10C9.44772
                         6 9 5.55228 9 5V3Z
                        "
                      fill="currentColor"/>
              </svg>
            `;

            updateButton.addEventListener('mouseover', () => {
                updateButton.style.color = '#E3E3E3';
            });

            updateButton.addEventListener('mouseout', () => {
                updateButton.style.color = '#B4B4B4';
            });



            updateButton.addEventListener('click', () => {
                customRules[index] = `<Rule${index + 1}: ${ruleInput.value}>`;
                saveCurrentProfileRules();
                ruleInput.style.color = 'black';
            });

            ruleContainer.appendChild(updateButton);

            const rulesDeleteButton = document.createElement('button');
            rulesDeleteButton.style.cssText = 'padding: 5px 10px; margin-right: -20px; color: #B4B4B4; background-color: transparent;';
            rulesDeleteButton.innerHTML = `
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="icon-sm">
                    <path fill-rule="evenodd" clip-rule="evenodd"
                        d="
                           M10.5555 4C10.099 4 9.70052 4.30906 9.58693 4.75114L9.29382 5.8919H14.715L14.4219 4.75114C14.3083 4.30906 13.9098 4 13.4533
                           4H10.5555ZM16.7799 5.8919L16.3589 4.25342C16.0182 2.92719 14.8226 2 13.4533 2H10.5555C9.18616 2 7.99062 2.92719 7.64985
                           4.25342L7.22886 5.8919H4C3.44772 5.8919 3 6.33961 3 6.8919C3 7.44418 3.44772 7.8919 4 7.8919H4.10069L5.31544 19.3172C5.47763
                           20.8427 6.76455 22 8.29863 22H15.7014C17.2354 22 18.5224 20.8427 18.6846 19.3172L19.8993 7.8919H20C20.5523 7.8919 21 7.44418
                           21 6.8919C21 6.33961 20.5523 5.8919 20 5.8919H16.7799ZM17.888 7.8919H6.11196L7.30423 19.1057C7.3583 19.6142 7.78727 20 8.29863
                           20H15.7014C16.2127 20 16.6417 19.6142 16.6958 19.1057L17.888 7.8919ZM10 10C10.5523 10 11 10.4477 11 11V16C11 16.5523 10.5523
                           17 10 17C9.44772 17 9 16.5523 9 16V11C9 10.4477 9.44772 10 10 10ZM14 10C14.5523 10 15 10.4477 15 11V16C15 16.5523 14.5523 17
                           14 17C13.4477 17 13 16.5523 13 16V11C13 10.4477 13.4477 10 14 10Z
                          "
                        fill="currentColor"/>
                </svg>
            `;

            rulesDeleteButton.addEventListener('mouseover', () => {
                rulesDeleteButton.style.color = '#E3E3E3';
            });

            rulesDeleteButton.addEventListener('mouseout', () => {
                rulesDeleteButton.style.color = '#B4B4B4';
            });

            rulesDeleteButton.addEventListener('click', () => {
                customRules.splice(index, 1);
                saveCurrentProfileRules();
                renderPanel();
            });


            const moveContainer = document.createElement('div');
            moveContainer.style.display = 'flex';
            moveContainer.style.flexDirection = 'column';
            moveContainer.style.gap = '3px';

            if (index > 0) {
                const upButton = document.createElement('button');
                upButton.textContent = '▲';
                upButton.style.padding = '3px';
                upButton.style.border = 'none';
                upButton.style.backgroundColor = 'transparent';
                upButton.style.color = '#B4B4B4';
                upButton.style.borderRadius = '5px';
                upButton.style.cursor = 'pointer';
                upButton.addEventListener('click', () => {
                    [customRules[index - 1], customRules[index]] = [customRules[index], customRules[index - 1]];
                    saveCurrentProfileRules();
                    renderPanel();
                });
                moveContainer.appendChild(upButton);
            }

            if (index < customRules.length - 1) {
                const downButton = document.createElement('button');
                downButton.textContent = '▼';
                downButton.style.padding = '3px';
                downButton.style.border = 'none';
                downButton.style.backgroundColor = 'transparent';
                downButton.style.color = '#B4B4B4';
                downButton.style.borderRadius = '5px';
                downButton.style.cursor = 'pointer';
                downButton.addEventListener('click', () => {
                    [customRules[index], customRules[index + 1]] = [customRules[index + 1], customRules[index]];
                    saveCurrentProfileRules();
                    renderPanel();
                });
                moveContainer.appendChild(downButton);
            }

            ruleContainer.appendChild(moveContainer);
            ruleContainer.appendChild(rulesDeleteButton);
            rulesListContainer.appendChild(ruleContainer);
        });

        adjustAllHeights();
    }

    function adjustAllHeights() {
        const textareas = rulesListContainer.querySelectorAll('textarea');
        textareas.forEach((textarea) => {
            textarea.style.height = 'auto';
            textarea.style.height = `${textarea.scrollHeight}px`;
        });
    }

function updateLayout() {
    if (isMobile()) {
        container.style.flexDirection = 'column';
        rulesPanel.style.width = '90%';
        rulesPanel.style.height = '90%';
        rulesListContainer.style.height = 'calc(90% - 60px)';
        rulesListContainer.style.overflowY = 'auto';
        rulesListContainer.style.maxHeight = `${rulesPanel.clientHeight - 150}px`; // Adjust dynamically
        profilesContainer.style.display = 'none';
        toggleProfilesButton.style.display = 'block';
    } else {
        container.style.flexDirection = 'row';
        rulesPanel.style.width = '1000px';
        rulesPanel.style.height = '700px';
        rulesListContainer.style.height = 'calc(100% - 81px)';
        rulesListContainer.style.overflowY = 'auto';
        profilesContainer.style.display = 'flex';
        toggleProfilesButton.style.display = 'none';

        if (profilesOverlay.style.display === 'flex') {
            profilesOverlay.style.display = 'none';
        }

        if (!container.contains(profilesContainer)) {
            container.insertBefore(profilesContainer, container.firstChild);
        }
    }
}


    window.addEventListener('resize', updateLayout);

    function openPanel() {
        rulesPanel.style.display = 'block';
        showOverlay();
        renderProfilesList();
        renderPanel();
        updateLayout();
    }

    manageRulesButton.addEventListener('click', () => {
        if (rulesPanel.style.display === 'none') {
            openPanel();
        } else {
            closeRulesPanel();
        }
    });

    // Initial render
    renderProfilesList();

    updateLayout();

}

// ================================================================ INJECT TEXT ==================================================================
function injectLogicGPT() {

// Variable in which the next rule is stored
//     const getSelectedRuleValue = localStorage.getItem('selectedRuleValue');


// DETECTING INPUT PANEL
    function detectInputPanelGPT(callback) {
    const maxRetries = 10;
    const retryInterval = 500;
    let retryCount = 0;
    window.inputPanelGPT = document.querySelector('div#prompt-textarea.ProseMirror');

        if (!inputPanelGPT) {
            console.error('Textarea panel not found.');
            if (retryCount < maxRetries) {
                retryCount++;
                console.log(`Retrying... Attempt ${retryCount}`);
                setTimeout(() => detectInputPanelGPT(callback), retryInterval);
            } else {
                console.error('Max retries reached. Cannot find the textarea.');
                callback(false, null); // Pass null for inputPanelGPT on failure
            }
            return;
        }

        console.log('Textarea found.');
        callback(true, inputPanelGPT);
    }



detectInputPanelGPT(function(success, inputPanelGPT) {
  if (success) {
    console.log('Textarea is ready to listen for events.');
  } else {
    console.error('Cannot proceed as textarea was not found.');
  }
});

function getCurrentInput() {
    // Add an event listener to the document to listen for keypresses
    document.addEventListener('keydown', function(event) {
        // Retrieve the input panel
        const inputPanel = document.querySelector('div#prompt-textarea.ProseMirror');

        // If the input panel exists
        if (inputPanel) {
            // Retrieve the current text from the input panel
            const currentText = inputPanel.innerText || inputPanel.textContent || '';

            // Store the text in localStorage with the key 'currentInputText'
            localStorage.setItem('currentInputText', currentText);

            console.log('Text saved to localStorage:', currentText);
        } else {
            console.error('Input panel not found. Cannot save text.');
        }
    });
}

getCurrentInput();



// Utility function to debounce rapid function calls
function debounce(func, wait) {
    let timeout;
    return function(...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this, args), wait);
    };
}

// Function to retrieve and store messages
function retrieveAndStoreMessages(type) {
    const selector = type === 'user'
        ? '.whitespace-pre-wrap'
        : 'div.markdown.prose.w-full.break-words.dark\\:prose-invert';
    const storageKey = type === 'user' ? 'lastUserMessage' : 'lastGPTMessage';
    const storageKeyTen = type === 'user' ? 'lastTenMessages' : 'lastTenGPTMessages';

    const messageElementArray = Array.from(document.querySelectorAll(selector));
    if (messageElementArray.length > 0) {
        const lastMessage = messageElementArray.slice(-1)[0].textContent.trim();
        console.log(`Last ${type === 'user' ? 'User' : 'GPT'} Message:`, lastMessage);
        localStorage.setItem(storageKey, lastMessage);

        const lastTenMessages = messageElementArray.slice(-10).map(element => element.textContent.trim());
        console.log(`Last 10 ${type === 'user' ? 'User' : 'GPT'} Messages:`, lastTenMessages);
        localStorage.setItem(storageKeyTen, JSON.stringify(lastTenMessages));
    }
}

// Main function to set up observers for user and GPT messages
function setupMessageObservers() {
    const userSelector = '.whitespace-pre-wrap';
    const gptSelector = 'div.markdown.prose.w-full.break-words.dark\\:prose-invert';

    const observerConfig = { childList: true, subtree: true };

    const debouncedUserHandler = debounce(() => retrieveAndStoreMessages('user'), 500);
    const debouncedGPTHandler = debounce(() => retrieveAndStoreMessages('gpt'), 500);

    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            if (mutation.type === 'childList') {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        if (node.matches(userSelector) || node.querySelector(userSelector)) {
                            debouncedUserHandler();
                        }
                        if (node.matches(gptSelector) || node.querySelector(gptSelector)) {
                            debouncedGPTHandler();
                        }
                    }
                });
            }
        }
    });

    observer.observe(document.body, observerConfig);
    console.log("MutationObserver set up for user and GPT messages.");
}

// Function to retrieve the last message of a given type
async function getLastMessages(type) {
    const selector = type === 'user'
        ? '.whitespace-pre-wrap'
        : 'div.markdown.prose.w-full.break-words.dark\\:prose-invert';
    const messageElementArray = Array.from(document.querySelectorAll(selector));

    if (messageElementArray.length > 0) {
        const lastMessage = messageElementArray.slice(-1)[0].textContent.trim();
        return lastMessage;
    } else {
        // Instead of rejecting, return null to indicate absence
        return null;
    }
}

// Initialize observers
setupMessageObservers();

// Function to handle message retrieval and related logic
async function handleMessages() {
    const lastUserMessage = await getLastMessages('user');
    if (lastUserMessage) {
        console.log("Retrieved last user message:", lastUserMessage);
    } else {
        console.info("No user messages found at this time.");
        // Optionally, you can reset rules here if necessary
        const getRulesState = localStorage.getItem('enableRules');
        if (getRulesState === "true") {
            const selectedProfileRules = localStorage.getItem('selectedProfile.Rules');
            const rulesProfiles = JSON.parse(localStorage.getItem('rulesProfiles'));
            const selectedRules = rulesProfiles[selectedProfileRules];
            console.log(`Stored selectedRules: ${selectedRules}`);
            const initNextRule = 'Rule1';
            localStorage.setItem('nextRule', initNextRule);
            localStorage.setItem('previousRule', '0');
            const initNextRuleValue = selectedRules.find(rule => rule.startsWith(`<${initNextRule}:`));
            localStorage.setItem('selectedRuleValue', initNextRuleValue);
            console.log(`Initial stored selectedRuleValue: ${initNextRuleValue}`);
        }
    }

    const lastGPTMessage = await getLastMessages('gpt');
    if (lastGPTMessage) {
        console.log("Retrieved last GPT message:", lastGPTMessage);
    } else {
        console.info("No GPT messages found at this time.");
    }
}

// Optional: Remove the initial handleMessages call to prevent errors on load
// If you prefer to handle existing messages on load, you can keep it with adjusted error handling
// handleMessages();

// Rely on MutationObserver to handle messages as they arrive

// ================================================================ RULES LOGIC ==================================================================

function rulesLogic() {
    // CHECKING IF THE MODULES ARE ENABLED

    const selectedProfileRules = localStorage.getItem('selectedProfile.Rules');
    const rulesProfiles = JSON.parse(localStorage.getItem('rulesProfiles'));
    const selectedRules = rulesProfiles[selectedProfileRules];
                console.log(`Stored selectedRules: ${selectedRules}`);
    const initNextRule = 'Rule1';
    localStorage.setItem('nextRule', initNextRule);
    const initPreviousRule = localStorage.setItem('previousRule', '0');
    const initNextRuleValue = selectedRules.find(rule => rule.startsWith(`<${initNextRule}:`));
    localStorage.setItem('selectedRuleValue', initNextRuleValue);
    console.log(`Initial stored selectedRuleValue: ${initNextRuleValue}`);
    const getRulesState = localStorage.getItem('enableRules');
    if (getRulesState === "true") {
        // RETRIEVING THE LAST USER MESSAGE
        const lastUserMessage = localStorage.getItem('lastUserMessage');

        if (lastUserMessage) {
            // MATCHING RULES IN THE MESSAGE
            const ruleMatches = lastUserMessage.match(/<Rule\d+/g);
                console.log('TRYING TO MATCH RULES');
            if (ruleMatches) {
                console.log('Found rules:', ruleMatches);

                // STORING THE LAST MATCHED RULE AS "previousRule"
                const previousRule = ruleMatches[ruleMatches.length - 1].replace('<', '');
                localStorage.setItem('previousRule', previousRule);

                // CALCULATING AND STORING THE NEXT RULE
                const ruleNumber = parseInt(previousRule.replace('Rule', ''), 10);
                const nextRuleNumber = (ruleNumber % selectedRules.length) + 1; // Wrap around using modulus
                const nextRule = `Rule${nextRuleNumber}`;
                localStorage.setItem('nextRule', nextRule);

                console.log(`Stored previousRule: ${previousRule}`);
                console.log(`Stored nextRule: ${nextRule}`);

                const nextRuleValue = selectedRules.find(rule => rule.startsWith(`<${nextRule}:`));
                localStorage.setItem('selectedRuleValue', nextRuleValue);
                console.log(`Stored selectedRuleValue: ${nextRuleValue}`);
            } else {

                console.log('No rules found in the last user message.');
            }
        } else {
            console.log('No last user message found in localStorage.');
        }
    } else {
        console.log('Rules module is disabled.');
    }
}

function observeLocalStorageKeyChange(key, callback) {
    let previousValue = localStorage.getItem(key);

    setInterval(() => {
        const currentValue = localStorage.getItem(key);
        if (currentValue !== previousValue) {
            previousValue = currentValue;
            callback(currentValue);
        }
    }, 100); // Adjust the interval as needed
}

// Set up the observer for 'lastUserMessage'
observeLocalStorageKeyChange('lastUserMessage', (newValue) => {
    console.log(`Detected change in 'lastUserMessage': ${newValue}`);
    rulesLogic();
});


    rulesLogic();


// ============================================================== LOREBOOK LOGIC =================================================================

// Existing lorebookLogic function
function lorebookLogic() {
const textareaContent = localStorage.getItem('currentInputText');
const lastGPTMessage = localStorage.getItem('lastGPTMessage');

}

// Initialize the lorebook logic
lorebookLogic();


}

// ================================================================ TEXT COLORS ==================================================================
function colorsScript() {

    const defaultColors = {
        textColor: '#A2A2AC',
        emColor: '#E0DF7F',
        bracketHighlight: '#737373',
        whiteHighlight: '#FFFFFF'
    };

    // Load colors from localStorage or use default colors
    function loadColors() {
        return {
            textColor: localStorage.getItem('textColor') || defaultColors.textColor,
            emColor: localStorage.getItem('emColor') || defaultColors.emColor,
            bracketHighlight: localStorage.getItem('bracketHighlight') || defaultColors.bracketHighlight,
            whiteHighlight: localStorage.getItem('whiteHighlight') || defaultColors.whiteHighlight
        };
    }

    // Inject styles based on the loaded colors
    function injectStyles(colors) {
        const styleId = 'colorizer-styles';
        let styleElement = document.getElementById(styleId);

        if (!styleElement) {
            styleElement = document.createElement('style');
            styleElement.id = styleId;
            document.head.appendChild(styleElement);
        }

        styleElement.textContent = `
            p, div.whitespace-pre-wrap {
                color: ${colors.textColor};
            }
            em {
                color: ${colors.emColor} !important;
                font-weight: normal !important;
            }
            .highlight-blue { color: ${colors.bracketHighlight} !important; }
            .highlight-white { color: ${colors.whiteHighlight} !important; }

            .highlight-blue * { color: inherit !important; }
            .highlight-white * { color: inherit !important; }
        `;
    }

    // Create the color picker panel UI
    function createColorPickerPanel() {
        const colors = loadColors();

        const colorPanel = document.createElement('div');
        colorPanel.id = 'color-picker-panel';
        colorPanel.style.position = 'fixed';
        // Center the panel
        colorPanel.style.top = '50%';
        colorPanel.style.left = '50%';
        colorPanel.style.transform = 'translate(-50%, -50%)'; // Precise centering
        colorPanel.style.padding = '30px'; // Increased padding
        colorPanel.style.background = '#2F2F2F'; // Darker, cooler background
        colorPanel.style.color = '#f8f8f8'; // Light, readable text color
        colorPanel.style.borderRadius = '20px'; // More rounded corners
        colorPanel.style.zIndex = '10000';
        colorPanel.style.display = 'none';
        colorPanel.style.width = '280px';
 //       colorPanel.style.fontFamily = 'sans-serif'; // Modern font
//        colorPanel.style.border = '1px solid #44475a'; // Subtle border

colorPanel.innerHTML = `
    <h3 style="margin-top: 0px; margin-bottom: 20px; text-align: center; color: #f8f8f8;">Text Colors</h3>
    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; width: 90%; margin-left: 10px;">
        <label style="margin-right: 10px;">Standard Color:</label>
        <input type="color" id="textColor" value="${colors.textColor}" style="width: 50px; height: 30px; border: none; cursor: pointer;">
    </div>
    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; width: 90%; margin-left: 10px;">
        <label style="margin-right: 10px;">Italic:</label>
        <input type="color" id="emColor" value="${colors.emColor}" style="width: 50px; height: 30px; border: none; cursor: pointer;">
    </div>
    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; width: 90%; margin-left: 10px;">
        <label style="margin-right: 10px;">Parentheses:</label>
        <input type="color" id="bracketHighlight" value="${colors.bracketHighlight}" style="width: 50px; height: 30px; border: none; cursor: pointer;">
    </div>
    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; width: 90%; margin-left: 10px;">
        <label style="margin-right: 10px;">Quotes:</label>
        <input type="color" id="whiteHighlight" value="${colors.whiteHighlight}" style="width: 50px; height: 30px; border: none; cursor: pointer;">
    </div>
    <div style="text-align: center; margin-top: 25px;">
        <button id="saveColors" style="padding: 8px 15px; background-color: transparent; width: 100%; color: #f8f8f8; border: 1px solid #4E4E4E; border-radius: 50px; cursor: pointer;">Save</button>
    </div>
`;

document.body.appendChild(colorPanel); // Append the color panel to the document

// Now that the color panel is added to the DOM, select the button
const saveColorsHighlight = document.getElementById('saveColors');

// Add event listeners for hover effect
saveColorsHighlight.addEventListener('mouseenter', () => {
    saveColorsHighlight.style.backgroundColor = CONFIG.BUTTON_HIGHLIGHT; // Change background color on hover
});

saveColorsHighlight.addEventListener('mouseleave', () => {
    saveColorsHighlight.style.backgroundColor = 'transparent'; // Reset background color when hover ends
});


    const colorsCloseButton = document.createElement('button');
    colorsCloseButton.style.position = 'absolute';
    colorsCloseButton.style.borderRadius = '50%';
    colorsCloseButton.style.top = '20px';
    colorsCloseButton.style.right = '20px';
    colorsCloseButton.style.backgroundColor = 'transparent';
    colorsCloseButton.style.cursor = 'pointer';
    colorsCloseButton.style.width = '32px';
    colorsCloseButton.style.height = '32px';
    colorsCloseButton.style.display = 'flex';
    colorsCloseButton.style.alignItems = 'center';
    colorsCloseButton.style.justifyContent = 'center';

    const colorsCloseSymbol = document.createElement('span');
    colorsCloseSymbol.innerText = '✕';
    colorsCloseSymbol.style.color = '#FBFBFE';
    colorsCloseSymbol.style.fontSize = '14px';
    colorsCloseSymbol.style.fontWeight = '550';
    colorsCloseSymbol.style.transform = 'translateY(-1px) translateX(0.4px)';

    colorsCloseButton.appendChild(colorsCloseSymbol);

    colorsCloseButton.addEventListener('mouseenter', () => {
    colorsCloseButton.style.backgroundColor = '#676767';
    });

    colorsCloseButton.addEventListener('mouseleave', () => {
        colorsCloseButton.style.backgroundColor = 'transparent';
    });

    const closeColorsPanel = () => {
        colorPanel.style.display = 'none';
        hideOverlay();
    };

    colorsCloseButton.addEventListener('click', closeColorsPanel);
    colorPanel.appendChild(colorsCloseButton);

    }



    // Create the manage colors button
    window.colorButton = document.createElement('div');
    window.colorButton.innerHTML = `
        <button id="toggle-color-panel"
            style="
                position: relative;
                top: 10px;
                right: 0px;
                left: 10px;
                padding: 7px 15px;
                background: transparent;
                color: #b0b0b0;
                border: none;
                border-radius: 8px;
                font-size: 16px;
                text-align: left;
                cursor: pointer;
                width: 90%;
                display: flex;
                align-items: center;
                gap: 10px;
                transition: background-color 0.1s, color 0.1s;
                z-index: 1001;">
            <svg fill="#B0B0B0" viewBox="0 0 32 32" width="16px" height="16px" xmlns="http://www.w3.org/2000/svg">
                <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
                <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
                <g id="SVGRepo_iconCarrier">
                    <title>brush</title>
                    <path d="M27.555 8.42c-1.355 1.647-5.070 6.195-8.021 9.81l-3.747-3.804c3.389-3.016 7.584-6.744 9.1-8.079 2.697-2.377 5.062-3.791
                             5.576-3.213 0.322 0.32-0.533 2.396-2.908 5.286zM18.879 19.030c-1.143 1.399-2.127 2.604-2.729 3.343l-4.436-4.323c0.719-0.64
                             1.916-1.705 3.304-2.939l3.861 3.919zM15.489 23.183v-0.012c-2.575 9.88-14.018 4.2-14.018 4.2s4.801 0.605 4.801-3.873c0-4.341
                             4.412-4.733 4.683-4.753l4.543 4.427c0 0.001-0.009 0.011-0.009 0.011z"></path>
                </g>
            </svg>
            Manage Colors
        </button>
    `;

    const colorButtonElement = window.colorButton.querySelector('button');
    colorButtonElement.onmouseover = () => {
        colorButtonElement.style.backgroundColor = '#212121';
        colorButtonElement.style.color = '#ffffff';
    };
    colorButtonElement.onmouseout = () => {
        colorButtonElement.style.backgroundColor = 'transparent';
        colorButtonElement.style.color = '#b0b0b0';
    };



    // Toggle the color picker panel visibility
    window.colorButton.addEventListener('click', () => {
        const colorPanel = document.getElementById('color-picker-panel');
        if (colorPanel) {
            showOverlay()
            colorPanel.style.display = colorPanel.style.display === 'none' ? 'block' : 'none';
        }
    });

    // Save the selected colors to localStorage and update styles
    function saveColors() {
        const textColor = document.getElementById('textColor').value;
        const emColor = document.getElementById('emColor').value;
        const bracketHighlight = document.getElementById('bracketHighlight').value;
        const whiteHighlight = document.getElementById('whiteHighlight').value;

        localStorage.setItem('textColor', textColor);
        localStorage.setItem('emColor', emColor);
        localStorage.setItem('bracketHighlight', bracketHighlight);
        localStorage.setItem('whiteHighlight', whiteHighlight);

        injectStyles(loadColors());

        // Re-highlight existing messages to apply new colors
        processExistingMessages();

        // Optional: Provide a non-intrusive notification instead of alert
        showTemporaryNotification('Colors saved successfully!', 2000);
    }

    // Function to show a temporary notification
    function showTemporaryNotification(message, duration) {
        const notification = document.createElement('div');
        notification.textContent = message;
        notification.style.position = 'fixed';
        notification.style.bottom = '20px';
        notification.style.right = '20px';
        notification.style.padding = '10px 20px';
        notification.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
        notification.style.color = '#fff';
        notification.style.borderRadius = '5px';
        notification.style.zIndex = '10001';
        notification.style.opacity = '0';
        notification.style.transition = 'opacity 0.5s';

        document.body.appendChild(notification);

        // Trigger reflow to apply transition
        void notification.offsetWidth;
        notification.style.opacity = '1';

        setTimeout(() => {
            notification.style.opacity = '0';
            setTimeout(() => {
                document.body.removeChild(notification);
            }, 500);
        }, duration);
    }

let debounceTimer = null;
let finalDivRecheckTimer = null;
let finalDivRecheckAttempts = 0; // Track how many times we’ve rechecked

function highlightMessageContent(messageElement, forceRecheck = false) {
    if (!messageElement) return;

    // If not forced, and the element is already processed, skip it
    // (unless this is the final streaming div we want to recheck)
    if (!forceRecheck && messageElement.dataset.processed) return;

    console.log("highlightMessageContent called on", messageElement);

    // Exclude elements inside the #prompt-textarea
    if (messageElement.closest('#prompt-textarea')) return;

    // Process parentheses and quotes
    safelyColorText(messageElement, /\(([^)]+)\)/g, 'highlight-blue');  // Parentheses
    safelyColorText(messageElement, /["“](.*?)["”]/g, 'highlight-white'); // Quotes

    // Mark as processed unless it's the final streaming div
    if (!isPotentialStreamingElement(messageElement)) {
        messageElement.dataset.processed = 'true';
    }
}

function safelyColorText(container, regex, highlightClass) {
    const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, null, false);
    const nodesToProcess = [];
    let node;

    while ((node = walker.nextNode())) {
        // Skip processing if inside excluded elements
        if (
            node.parentElement.closest('#prompt-textarea') ||
            node.parentElement.closest('.prosemirror-editor-container') ||
            node.parentElement.closest('#composer-background') ||
            node.parentElement.closest('[contenteditable="true"]')
        ) continue;

        nodesToProcess.push(node);
    }

    nodesToProcess.forEach(node => {
        const parent = node.parentNode;
        const text = node.textContent;
        let newHTML = '';
        let lastIndex = 0;

        regex.lastIndex = 0; // Reset regex state
        let match;

        // Replace curly quotes before processing regex
        replaceQuotes(node);

        // Process text for regex matching and highlighting
        while ((match = regex.exec(text)) !== null) {
            newHTML += escapeHTML(text.substring(lastIndex, match.index));
            newHTML += `<span class="${highlightClass}">${escapeHTML(match[0])}</span>`;
            lastIndex = regex.lastIndex;
        }
        newHTML += escapeHTML(text.substring(lastIndex));

        if (newHTML !== escapeHTML(text)) {
            const tempSpan = document.createElement('span');
            tempSpan.innerHTML = newHTML;
            parent.replaceChild(tempSpan, node);
        }
    });
}

function escapeHTML(str) {
    return str
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
}

function replaceQuotes(node) {
    if (node.nodeType === Node.TEXT_NODE) {
        node.nodeValue = node.nodeValue
            // Replace various single curly quotes with straight single quote
            .replace(/[\u2018\u2019\u201A\u201B]/g, "'")
            // Replace various double curly quotes with straight double quote
            .replace(/[\u201C\u201D\u201E\u201F]/g, '"');
    } else if (node.nodeType === Node.ELEMENT_NODE) {
        // Process child nodes recursively
        for (let child of node.childNodes) {
            replaceQuotes(child);
        }
    }
}

// Identify if the element looks like our final streaming div
function isPotentialStreamingElement(element) {
    return element.matches('div.markdown.prose.w-full.break-words.dark\\:prose-invert.dark');
}

function processExistingMessages() {
    const messages = document.querySelectorAll('p, div.whitespace-pre-wrap, div.markdown.prose.w-full.break-words.dark\\:prose-invert.dark');
    messages.forEach(message => {
        highlightMessageContent(message);
    });
}

function handleMutations(mutationsList) {
    for (const mutation of mutationsList) {
        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
            // Debounce to batch multiple rapid mutations
            if (debounceTimer) {
                clearTimeout(debounceTimer);
            }
            debounceTimer = setTimeout(() => {
                console.log("DOM mutations detected. Processing new messages...");
                processExistingMessages();
                recheckFinalDiv(); // Trigger an additional check on the final streaming div
            }, 500); // Adjust debounce delay as needed
            break;
        }
    }
}

function initializeMutationObserver() {
    const targetNode = document.body; // Or a more specific container if you prefer
    const config = { childList: true, subtree: true };
    const observer = new MutationObserver(handleMutations);
    observer.observe(targetNode, config);
    console.log("MutationObserver initialized.");
}

function initialize() {
    console.log('initialize');
    const colors = loadColors();
    injectStyles(colors);  // Inject your CSS variables or color classes
    createColorPickerPanel();
    processExistingMessages();
    initializeMutationObserver();
}

// *** NEW: Recheck logic for the final streaming div ***
function recheckFinalDiv() {
    // Clear previous timer if any
    if (finalDivRecheckTimer) {
        clearTimeout(finalDivRecheckTimer);
    }

    // Find the final streaming div
    const finalDiv = document.querySelector('div.markdown.prose.w-full.break-words.dark\\:prose-invert.dark:not([data-processed])');
    if (!finalDiv) return;

    // Force a highlight pass on it
    highlightMessageContent(finalDiv, /* forceRecheck = */ true);

    // If we haven’t tried many times, schedule another recheck
    if (finalDivRecheckAttempts < 6) { // e.g., do up to 6 checks
        finalDivRecheckAttempts++;
        finalDivRecheckTimer = setTimeout(() => {
            recheckFinalDiv();
        }, 5000); // e.g., every 5 seconds
    } else {
        // Mark it as processed after final attempt
        finalDiv.dataset.processed = 'true';
        finalDivRecheckAttempts = 0;
    }
}

// Hook into your “done streaming” event if you have one
// Suppose you know the streaming is complete on a particular XHR/Fetch:
function onStreamingComplete() {
    // Force a final highlight pass on the last div
    const finalDiv = document.querySelector('div.markdown.prose.w-full.break-words.dark\\:prose-invert.dark:not([data-processed])');
    if (finalDiv) {
        highlightMessageContent(finalDiv, true);
        finalDiv.dataset.processed = 'true';  // now we can mark it processed
    }
    // Clear any recheck timers if needed
    if (finalDivRecheckTimer) {
        clearTimeout(finalDivRecheckTimer);
        finalDivRecheckAttempts = 0;
    }
}

// Conditionally run the initialization
function startInitialization() {
    const getColorsState = localStorage.getItem('enableColors');
    if (getColorsState === "true") {
        initialize();
    } else {
        console.log("Color customization is disabled.");
    }
}

// Ensure the script initializes correctly on page load
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', startInitialization);
} else {
    startInitialization();
}
}

// =================================================================== < > Hider ===================================================================

function hideInjectionsScript() {
    // Mutation observer reference
    let observer = null;

    // Function to hide text within angle brackets
    function hideBracketText(node) {
        // Multi-line regex to capture text within < and >
        const regex = /<[^>]*?>/gs;

        // Ensure the node is a text node
        if (node.nodeType === Node.TEXT_NODE) {
            const parent = node.parentNode;

            // Exclude nodes outside of .whitespace-pre-wrap
            if (!parent.closest('.whitespace-pre-wrap')) {
                return;
            }

            // Find all matches
            const matches = node.nodeValue.match(regex);
            if (matches) {
                // Split the text node around matched portions
                const parts = node.nodeValue.split(regex);

                // Insert each segment and its matched hidden text
                parts.forEach((part, index) => {
                    // Only insert visible text if non-empty
                    if (part.trim() !== "") {
                        const textNode = document.createTextNode(part);
                        parent.insertBefore(textNode, node);
                    }
                    // Create a hidden <span> if a match still exists at this index
                    if (index < matches.length) {
                        const hiddenSpan = document.createElement('span');
                        hiddenSpan.style.display = 'none';
                        hiddenSpan.textContent = matches[index];
                        parent.insertBefore(hiddenSpan, node);
                    }
                });

                // Remove the original text node
                parent.removeChild(node);
            }
        }
    }

    // Process only visible and editable elements
    function processVisibleTextNodes() {
        document.querySelectorAll('*:not(script):not(style)').forEach(node => {
            // Check for childNodes & whether element is visible
            if (node.childNodes && node.offsetParent !== null) {
                node.childNodes.forEach(child => {
                    // Only hide bracket text within .whitespace-pre-wrap
                    if (child.parentNode.closest('.whitespace-pre-wrap')) {
                        hideBracketText(child);
                    }
                });
            }
        });
    }

    // Start observing the DOM
    function startObserving() {
        if (observer) return; // Avoid multiple observers

        observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                mutation.addedNodes.forEach(addedNode => {
                    if (addedNode.nodeType === Node.ELEMENT_NODE) {
                        if (addedNode.closest('.whitespace-pre-wrap')) {
                            processVisibleTextNodes();
                        }
                    } else if (addedNode.nodeType === Node.TEXT_NODE) {
                        if (addedNode.parentNode.closest('.whitespace-pre-wrap')) {
                            hideBracketText(addedNode);
                        }
                    }
                });
            });
        });

        observer.observe(document.body, { childList: true, subtree: true });
        processVisibleTextNodes(); // Process existing nodes initially
    }

    // Stop observing the DOM
    function stopObserving() {
        if (observer) {
            observer.disconnect();
            observer = null;
        }
    }

    // Show hidden text
    function showBracketText() {
        // Reveal any spans that were previously hidden
        document.querySelectorAll('span[style*="display: none"]').forEach(hiddenSpan => {
            const parent = hiddenSpan.parentNode;
            const textNode = document.createTextNode(hiddenSpan.textContent);
            parent.insertBefore(textNode, hiddenSpan);
            parent.removeChild(hiddenSpan);
        });
    }

    // Monitor toggle state
    function monitorHiderState() {
        const state = localStorage.getItem('enableHider');
        if (state === 'true') {
            console.log("Hider is enabled.");
            showBracketText(); // Reset to avoid duplicates
            startObserving();
        } else {
            console.log("Hider is disabled.");
            stopObserving();
            showBracketText(); // Reveal hidden text
        }
    }

    // Monitor network for specific POST requests
    function monitorNetworkForPOST() {
        const performanceObserver = new PerformanceObserver((list) => {
            const entries = list.getEntries();
            for (const entry of entries) {
                if (
                    entry.initiatorType === 'fetch' &&
                    (entry.name.includes('https://chatgpt.com/backend-api/conversation') ||
                     entry.name.includes('https://chatgpt.com/ces/v1/p'))
                ) {
                    console.log("Detected POST request. Activating hiding script.");
                    monitorHiderState(); // Adjust state based on toggle
                }
            }
        });

        performanceObserver.observe({ type: 'resource', buffered: true });
    }

    // Listen for storage changes
    window.addEventListener('storage', monitorHiderState);

    // Initial setup
    monitorHiderState();
    monitorNetworkForPOST();
}

// ============================================================= CONTENT WARNINGS =================================================================
function hideContentWarnings() {
    function updateVisibility() {
        const state = localStorage.getItem('enableHideWarning');
        if (state === 'true') {
            GM_addStyle(`
                .border-orange-400\\/15,
                div.text-sm.text-orange-600.border-token-border-light.bg-orange-400.bg-opacity-0.w-full.pr-5.text-right {
                    display: none !important;
                }
            `);
        } else {
            GM_addStyle(`
                .border-orange-400\\/15,
                div.text-sm.text-orange-600.border-token-border-light.bg-orange-400.bg-opacity-0.w-full.pr-5.text-right {
                    display: block !important;
                }
            `);
        }
    }

    // Initial update
    updateVisibility();

    // Watch for changes in localStorage
    window.addEventListener('storage', (event) => {
        if (event.key === 'enableHideWarning') {
            updateVisibility();
        }
    });

    // Optional: Add a periodic check as a fallback
    setInterval(updateVisibility, 1000);
}

// Call the function to initialize
hideContentWarnings();

// =================================================================== BUTTONS ===================================================================


function createDivider() {
const divider = document.createElement('div');
divider.style.height = '1px';
divider.style.backgroundColor = '#212121';
divider.style.margin = '20px 20px 0px 20px';
    return divider;
}
function createFooterText() {
    const footerText = document.createElement('div');
    footerText.textContent = '© Vishanka 2024';
    footerText.style.position = 'absolute';
    footerText.style.bottom = '10px';
    footerText.style.left = '50%';
    footerText.style.transform = 'translateX(-50%)';
    footerText.style.fontSize = '12px';
    footerText.style.fontWeight = '550';
    footerText.style.color = '#272727';
    return footerText;
}

function createCheckbox(label, key) {
    const checkboxContainer = document.createElement('div');
    checkboxContainer.style.marginTop = '5px';
    checkboxContainer.style.marginLeft = '25px';

    const checkboxLabel = document.createElement('label');
    checkboxLabel.style.color = '#B0B0B0';

    const checkbox = document.createElement('input');
    checkbox.style.marginRight = '10px';
    checkbox.type = 'checkbox';
    checkbox.id = key;
    checkboxLabel.textContent = label;
    checkboxLabel.setAttribute('for', key);

    // Retrieve saved state from localStorage
    const savedState = localStorage.getItem(key);
    if (savedState !== null) {
        checkbox.checked = savedState === 'true';
    }

    // Listen for changes and save state to localStorage
    checkbox.addEventListener('change', function() {
        localStorage.setItem(key, checkbox.checked);
    });

    checkboxContainer.appendChild(checkbox);
    checkboxContainer.appendChild(checkboxLabel);


    return checkboxContainer;
}

function initializeCheckboxes() {
function checkboxDivider() {
const checkboxDivider = document.createElement('div');
checkboxDivider.style.height = '1px';
checkboxDivider.style.backgroundColor = '#212121';
checkboxDivider.style.margin = '20px 20px 20px 20px';
    return checkboxDivider;
}
    // Create a container for the checkboxes
    const checkboxGroup = document.createElement('div');
    checkboxGroup.style.marginTop = '15px';  // Add margin at the top of the group

    // Create and append each checkbox to the group
    checkboxGroup.appendChild(createCheckbox('Enable Rules', 'enableRules'));
    checkboxGroup.appendChild(createCheckbox('Enable Lorebook', 'enableLorebook'));
    checkboxGroup.appendChild(createCheckbox('Enable Events', 'enableEvents'));
checkboxGroup.appendChild(checkboxDivider());
    checkboxGroup.appendChild(createCheckbox('Enable Colors', 'enableColors'));
    checkboxGroup.appendChild(createCheckbox('Hide Injections', 'enableHider'));
    checkboxGroup.appendChild(createCheckbox('Hide Content Warning', 'enableHideWarning'));

    // Append the group to the main panel
    mainPanel.appendChild(checkboxGroup);
}


function initializeButton() {
mainPanel.appendChild(createDivider());
mainPanel.appendChild(openLorebookButton);
mainPanel.appendChild(manageRulesButton);
mainPanel.appendChild(createDivider());
initializeCheckboxes();
mainPanel.appendChild(createDivider());
mainPanel.appendChild(colorButton);
mainPanel.appendChild(createFooterText());
}
// ============================================================ SCRIPT LOADING ORDER ============================================================
colorsScript();
hideInjectionsScript();
hideContentWarnings();
        mainPanelScript();
        rulesScript();
lorebookScript();

        initializeButton();
        injectLogicGPT();
//lorebookLogic();
    // Function to execute your scripts
/*    function executeScripts() {
        mainPanelScript();
        rulesScript();
        initializeButton();
        injectLogicGPT();
    }

    // Initial execution
    executeScripts();

    // Monitor for URL changes
    let currentUrl = location.href;
    const observer = new MutationObserver(() => {
        if (currentUrl !== location.href) {
            currentUrl = location.href;
            console.log('URL changed, re-executing scripts...');
            executeScripts();
        }
    });

    // Observe changes in the <body> tag
    observer.observe(document.body, { childList: true, subtree: true });
*/
})();
长期地址
遇到问题?请前往 GitHub 提 Issues。