您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Lets you change the text colors as you wish and highlight chosen words
当前为
- // ==UserScript==
- // @name c.ai X Text Color
- // @namespace c.ai X Text Color
- // @match https://*.character.ai/*
- // @grant none
- // @license MIT
- // @version 2.5.2
- // @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 = '#A2A2AC';
- // 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_918210','Noto Sans', sans-serif !important; } p, textarea, button, div.text-sm { font-family: '__Inter_918210','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': '#A2A2AC',
- '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-\\[325px\\]';
- const secondaryTargetSelector = 'div.justify-between: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...');