c.ai X Text Color

Lets you change the text colors as you wish and highlight chosen words

当前为 2024-01-24 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        c.ai X Text Color
// @namespace   c.ai X Text Color
// @match       https://*.character.ai/*
// @grant       none
// @license     MIT
// @version     2.4
// @author      Vishanka via chatGPT
// @description Lets you change the text colors as you wish and highlight chosen words
// @icon        https://i.imgur.com/ynjBqKW.png
// ==/UserScript==


(function () {
 var plaintextColor = localStorage.getItem('plaintext_color');

  // Default color if 'plaintext_color' is not set
  var defaultColor = '#958C7F';

  // Use the retrieved color or default color
  var color = plaintextColor || defaultColor;

  // Create the CSS style
//  var css =
//"p[node='[object Object]'] { color: " + color + " !important; }";
//"p, div, textarea { font-family: 'Noto Sans', sans-serif !important; }";
var css = "p[node='[object Object]'] { color: " + color + " !important; font-family: '__Inter_cc86f0','Noto Sans', sans-serif !important; } p, textarea, button, div.text-sm { font-family: '__Inter_cc86f0','Noto Sans', sans-serif !important; }";
//var css = "p[node='[object Object]'] { color: " + color + " !important; }";

  var head = document.getElementsByTagName("head")[0];
  var style = document.createElement("style");
  style.setAttribute("type", "text/css");
  style.innerHTML = css;
  head.appendChild(style);



})();

function changeColors() {
  const pTags = document.getElementsByTagName("p");
  for (let i = 0; i < pTags.length; i++) {
    const pTag = pTags[i];
    if (
      pTag.dataset.colorChanged === "true" ||
      pTag.querySelector("code") ||
      pTag.querySelector("img") ||
      pTag.querySelector("textarea") ||
      pTag.querySelector("button") ||
      pTag.querySelector("div")
    ) {
      continue;
    }
    let text = pTag.innerHTML;

    const aTags = pTag.getElementsByTagName("a"); // Get all <a> tags within the <p> tag

    // Remove the <a> tags temporarily
    for (let j = 0; j < aTags.length; j++) {
      const aTag = aTags[j];
      text = text.replace(aTag.outerHTML, "REPLACE_ME_" + j); // Use a placeholder to be able to restore the links later
    }

//Changes Text within Quotation Marks to white
  text = text.replace(/(["“”«»].*?["“”«»])/g, `<span style="color: ${localStorage.getItem('quotationmarks_color') || '#FFFFFF'}">$1</span>`);
//Changes Text within Quotation Marks and a comma at the end to yellow
  text = text.replace(/(["“”«»][^"]*?,["“”«»])/g, '<span style="color: #E0DF7F">$1</span>');
// Changes Italic Text Color
  text = text.replace(/<em>(.*?)<\/em>/g,`<span style="color: ${localStorage.getItem('italic_color') || '#E0DF7F'}; font-style: italic;">$1</span>`);
// Changes Textcolor within Percentages to blue
//  text = text.replace(/([%][^"]*?[%])/g, '<span style="color: #0000FF">$1</span>');

var wordlist_cc = JSON.parse(localStorage.getItem('wordlist_cc')) || [];

// Check if the wordlist is not empty before creating the regex
if (wordlist_cc.length > 0) {
    // Escape special characters in each word and join them with the "|" operator
    var wordRegex = new RegExp('\\b(' + wordlist_cc.map(word => word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|') + ')\\b', 'gi');

    // Replace matching words in the text
    text = text.replace(wordRegex, `<span style="color: ${localStorage.getItem('custom_color') || '#FFFFFF'}">$1</span>`);
}



    // Restore the <a> tags
    for (let j = 0; j < aTags.length; j++) {
      const aTag = aTags[j];
      text = text.replace("REPLACE_ME_" + j, aTag.outerHTML);
    }

    pTag.innerHTML = text;
    pTag.dataset.colorChanged = "true";
  }

  console.log("Changed colors");
}

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



function createButton(symbol, onClick) {
    const colorpalettebutton = document.createElement('button');
    colorpalettebutton.innerHTML = symbol;
    colorpalettebutton.style.position = 'relative';
    colorpalettebutton.style.background = 'none';
    colorpalettebutton.style.border = 'none';
    colorpalettebutton.style.fontSize = '18px';
    colorpalettebutton.style.top = '-5px';
    colorpalettebutton.style.cursor = 'pointer';
    colorpalettebutton.addEventListener('click', onClick);
    return colorpalettebutton;
}

// Function to create the color selector panel
function createColorPanel() {
    const panel = document.createElement('div');
    panel.id = 'colorPanel';
    panel.style.position = 'fixed';
    panel.style.top = '50%';
    panel.style.left = '50%';
    panel.style.transform = 'translate(-50%, -50%)';
    panel.style.backgroundColor = 'rgba(19, 19, 22, 0.95)';
    panel.style.border = 'none';
    panel.style.borderRadius = '5px';
    panel.style.padding = '20px';
//    panel.style.border = '2px solid #000';
    panel.style.zIndex = '9999';

    const categories = ['italic', 'quotationmarks', 'plaintext', 'custom'];

    const colorPickers = {};

    // Set a fixed width for the labels
    const labelWidth = '150px';

    categories.forEach(category => {
        const colorPicker = document.createElement('input');
        colorPicker.type = 'color';

        // Retrieve stored color from local storage
        const storedColor = localStorage.getItem(`${category}_color`);
        if (storedColor) {
            colorPicker.value = storedColor;
        }

        colorPickers[category] = colorPicker;

        // Create a div to hold color picker
        const colorDiv = document.createElement('div');
        colorDiv.style.position = 'relative';
        colorDiv.style.width = '20px';
        colorDiv.style.height = '20px';
        colorDiv.style.marginLeft = '10px';
        colorDiv.style.top = '5px';
        colorDiv.style.backgroundColor = colorPicker.value;
        colorDiv.style.display = 'inline-block';
        colorDiv.style.marginRight = '10px';
        colorDiv.style.cursor = 'pointer';
colorDiv.style.border = '1px solid black';


        // Event listener to open color picker when the color square is clicked
        colorDiv.addEventListener('click', function () {
            colorPicker.click();
        });

        // Event listener to update the color div when the color changes
        colorPicker.addEventListener('input', function () {
            colorDiv.style.backgroundColor = colorPicker.value;
        });

        const label = document.createElement('label');
        label.style.width = labelWidth; // Set fixed width for the label
        label.appendChild(document.createTextNode(`${category}: `));

        // Reset button for each color picker
        const resetButton = createButton('↺', function () {
            colorPicker.value = getDefaultColor(category);
            colorDiv.style.backgroundColor = colorPicker.value;
        });
        resetButton.style.position = 'relative';
        resetButton.style.top = '1px';
        // Create a div to hold label, color picker, and reset button
        const containerDiv = document.createElement('div');
        containerDiv.appendChild(label);
        containerDiv.appendChild(colorDiv);
        containerDiv.appendChild(resetButton);

        panel.appendChild(containerDiv);
        panel.appendChild(document.createElement('br'));
    });

    // Custom word list input
    const wordListInput = document.createElement('input');
    wordListInput.type = 'text';
    wordListInput.placeholder = 'Separate words with commas';
    wordListInput.style.width = '250px';
    wordListInput.style.height = '35px';
    wordListInput.style.borderRadius = '3px';
    wordListInput.style.marginBottom = '10px';
    panel.appendChild(wordListInput);
    panel.appendChild(document.createElement('br'));

    const wordListContainer = document.createElement('div');
    wordListContainer.style.display = 'flex';
    wordListContainer.style.flexWrap = 'wrap';
    wordListContainer.style.maxWidth = '300px'; // Set a fixed maximum width for the container

    // Display custom word list buttons
    const wordListArray = JSON.parse(localStorage.getItem('wordlist_cc')) || [];
    const wordListButtons = [];

function createWordButton(word) {
    const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);

    const removeSymbol = isMobile ? '×' : '🞮';

    const wordButton = createButton(`${word} ${removeSymbol}`, function() {
        // Remove the word from the list and update the panel
        const index = wordListArray.indexOf(word);
        if (index !== -1) {
            wordListArray.splice(index, 1);
            updateWordListButtons();
        }
    });

// Word Buttons
    wordButton.style.borderRadius = '3px';
    wordButton.style.border = 'none';
    wordButton.style.backgroundColor = '#26272B';
    wordButton.style.marginBottom = '5px';
    wordButton.style.marginRight = '5px';
    wordButton.style.fontSize = '16px';
    wordButton.classList.add('word-button');
    return wordButton;
}

    function updateWordListButtons() {
        wordListContainer.innerHTML = ''; // Clear the container
        wordListArray.forEach(word => {
            const wordButton = createWordButton(word);
            wordListContainer.appendChild(wordButton);
        });
    }

    // Append wordListContainer to the panel



updateWordListButtons();

// Add Words button
const addWordsButton = document.createElement('button');
addWordsButton.textContent = 'Add';
addWordsButton.style.marginTop = '-8px';
addWordsButton.style.marginLeft = '5px';
addWordsButton.style.borderRadius = '3px';
addWordsButton.style.border = 'none';
addWordsButton.style.backgroundColor = '#26272B';
addWordsButton.addEventListener('click', function() {
    // Get the input value, split into words, and add to wordListArray
    const wordListValue = wordListInput.value;
const newWords = wordListValue.split(',').map(word => word.trim().toLowerCase()).filter(word => word !== ''); // Convert to lowercase and remove empty entries
    wordListArray.push(...newWords);

    // Update the word list buttons in the panel
    updateWordListButtons();
});

// Create a div to group the input and button on the same line
const inputButtonContainer = document.createElement('div');
inputButtonContainer.style.display = 'flex';
inputButtonContainer.style.alignItems = 'center';

inputButtonContainer.appendChild(wordListInput);
inputButtonContainer.appendChild(addWordsButton);

// Append the container to the panel
panel.appendChild(inputButtonContainer);
    panel.appendChild(wordListContainer);
// Create initial word list buttons
updateWordListButtons();


    // OK button
    const okButton = document.createElement('button');
    okButton.textContent = 'Confirm';
    okButton.style.marginTop = '-20px';
    okButton.style.width = '75px';
    okButton.style.height = '35px';
    okButton.style.marginRight = '5px';
    okButton.style.borderRadius = '3px';
    okButton.style.border = 'none';
    okButton.style.backgroundColor = '#26272B';
okButton.style.position = 'relative';
okButton.style.left = '24%';
//okButton.style.transform = 'translateX(-50%)';
    okButton.addEventListener('click', function() {
        // Save selected colors to local storage
        categories.forEach(category => {
            const oldValue = localStorage.getItem(`${category}_color`);
            const newValue = colorPickers[category].value;

            if (oldValue !== newValue) {
                localStorage.setItem(`${category}_color`, newValue);

                // If 'plaintext' color is changed, auto-reload the page
                if (category === 'plaintext') {
                    window.location.reload();
                }
            }
        });

// Save custom word list to local storage
const wordListValue = wordListInput.value;
const newWords = wordListValue.split(',').map(word => word.trim().toLowerCase()).filter(word => word !== ''); // Convert to lowercase and remove empty entries
const uniqueNewWords = Array.from(new Set(newWords)); // Remove duplicates

// Check for existing words and add only new ones
uniqueNewWords.forEach(newWord => {
  if (!wordListArray.includes(newWord)) {
    wordListArray.push(newWord);
  }
});

localStorage.setItem('wordlist_cc', JSON.stringify(wordListArray));

updateWordListButtons();

        // Close the panel
        panel.remove();
    });

    // Cancel button
    const cancelButton = document.createElement('button');
    cancelButton.textContent = 'Cancel';
    cancelButton.style.marginTop = '-20px';
    cancelButton.style.borderRadius = '3px';
    cancelButton.style.width = '75px';
    cancelButton.style.marginLeft = '5px';
    cancelButton.style.height = '35px';
    cancelButton.style.border = 'none';
    cancelButton.style.backgroundColor = '#5E5E5E';
    cancelButton.style.position = 'relative';
    cancelButton.style.left = '25%';
    cancelButton.addEventListener('click', function() {
        // Close the panel without saving
        panel.remove();
    });

    panel.appendChild(document.createElement('br'));
    panel.appendChild(okButton);
    panel.appendChild(cancelButton);

    document.body.appendChild(panel);
}



// Function to get the default color for a category
function getDefaultColor(category) {
    const defaultColors = {
        'italic': '#E0DF7F',
        'quotationmarks': '#FFFFFF',
        'plaintext': '#878788',
        'custom': '#E0DF7F'
    };
    return defaultColors[category];
}

const mainButton = createButton('', function() {
    const colorPanelExists = document.getElementById('colorPanel');
    if (!colorPanelExists) {
        createColorPanel();
    }
});

// Set the background image of the button to the provided image
mainButton.style.backgroundImage = "url('https://i.imgur.com/yBgJ3za.png')";
mainButton.style.backgroundSize = "cover";
mainButton.style.position = "fixed"; // Use "fixed" for a position relative to the viewport
mainButton.style.top = "10px"; // Adjust the top position as needed
mainButton.style.right = "10px"; // Adjust the right position as needed
mainButton.style.width = "22px";  // Adjust the width and height as needed
mainButton.style.height = "22px"; // Adjust the width and height as needed

const targetSelector = '.w-\\[786px\\]';
const secondaryTargetSelector = '.w-dvw > div:nth-child(1)';

// Function to insert the mainButton into the target panel
function insertMainButton(targetPanel) {
  targetPanel.appendChild(mainButton);
}

// MutationObserver for the web version
const webObserver = new MutationObserver(() => {
    const updatedTargetPanel = document.querySelector(targetSelector);
    if (updatedTargetPanel) {
        insertMainButton(updatedTargetPanel);
        webObserver.disconnect();
    }
});

// MutationObserver for phones
const phoneObserver = new MutationObserver(() => {
    const updatedTargetPanel2 = document.querySelector(secondaryTargetSelector);
    if (updatedTargetPanel2) {
        insertMainButton(updatedTargetPanel2);
        phoneObserver.disconnect();
    }
});

// Determine whether to use webObserver or phoneObserver based on the screen width
if (window.innerWidth >= 1000) {
    webObserver.observe(document.body, { subtree: true, childList: true });
} else {
    phoneObserver.observe(document.body, { subtree: true, childList: true });
}

console.error('Target panel not found. Waiting for changes...');