c.ai X Text Color

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

当前为 2024-08-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name c.ai X Text Color
  3. // @namespace c.ai X Text Color
  4. // @match https://character.ai/*
  5. // @grant none
  6. // @license MIT
  7. // @version 3.4
  8. // @author Vishanka via chatGPT
  9. // @description Lets you change the text colors as you wish and highlight chosen words
  10. // @icon https://i.imgur.com/ynjBqKW.png
  11. // ==/UserScript==
  12.  
  13.  
  14. (function () {
  15.  
  16. const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
  17. var plaintextColor = localStorage.getItem('plaintext_color');
  18. var italicColor = localStorage.getItem('italic_color');
  19. var charbubbleColor = localStorage.getItem('charbubble_color') || '#26272B';
  20. var userbubbleColor = localStorage.getItem('userbubble_color') || '#303136';
  21. var defaultColor = '#A2A2AC'; // Default color if 'plaintext_color' is not set
  22. var GuideColor = localStorage.getItem('guide_color') || '#131316';
  23. var BodyColor = localStorage.getItem('body_color') || '#18181B';
  24. var InputColor = localStorage.getItem('input_color') || '#202024';
  25. var AccentColor = localStorage.getItem('accent_color') || '#26272b';
  26.  
  27. // Use the retrieved color or default color
  28. var color = plaintextColor || defaultColor;
  29.  
  30. // Retrieve the selected font and font size from local storage, or use defaults
  31. var selectedFont = localStorage.getItem('selected_font') || '__Inter_918210';
  32. var fontSize = localStorage.getItem('font_size') || '16px'; // Default font size
  33.  
  34. // Create the CSS style using the selected font, stored colors, and font size
  35. var css = `
  36. p[node='[object Object]'] {
  37. color: ${color} !important;
  38. font-family: '${selectedFont}', 'Noto Sans', sans-serif !important;
  39. font-size: ${fontSize} !important;
  40. }
  41. p, textarea, button, div.text-sm {
  42. font-family: '${selectedFont}', 'Noto Sans', sans-serif !important;
  43. }
  44. em {
  45. color: ${italicColor} !important;
  46. }
  47. `;
  48.  
  49. css += `.mt-1.bg-surface-elevation-2 { background-color: ${charbubbleColor}; } .mt-1.bg-surface-elevation-3 { background-color: ${userbubbleColor}; }`;
  50.  
  51.  
  52.  
  53. var head = document.getElementsByTagName("head")[0];
  54. var style = document.createElement("style");
  55. style.setAttribute("type", "text/css");
  56. style.innerHTML = css;
  57. head.appendChild(style);
  58.  
  59.  
  60. // Function to update CSS variables
  61. function updateCSSVariable(variableName, value) {
  62. document.documentElement.style.setProperty(variableName, value);
  63. }
  64.  
  65. if (currentTheme === 'dark') {
  66. // Update the specific CSS variables
  67. updateCSSVariable('--G800', AccentColor);
  68. updateCSSVariable('--G850', InputColor);
  69. updateCSSVariable('--G900', BodyColor);
  70. updateCSSVariable('--G950', GuideColor);
  71.  
  72.  
  73. updateCSSVariable('--G50', '#fafafa');
  74. updateCSSVariable('--G100', '#f4f4f5');
  75. updateCSSVariable('--G150', '#ececee');
  76. }
  77. else {
  78. // Update CSS variables for light theme (or any other theme)
  79. updateCSSVariable('--G850', '#202024');
  80. updateCSSVariable('--G900', '#18181B');
  81. updateCSSVariable('--G950', '#131316');
  82. updateCSSVariable('--G50', InputColor);
  83. updateCSSVariable('--G100', BodyColor);
  84. updateCSSVariable('--G150', GuideColor);
  85. }
  86. })();
  87.  
  88.  
  89.  
  90.  
  91. function changeColors() {
  92. const pTags = document.getElementsByTagName("p");
  93. const quotationMarksColor = localStorage.getItem('quotationmarks_color') || '#FFFFFF';
  94. const customColor = localStorage.getItem('custom_color') || '#FFFFFF';
  95. const wordlistCc = JSON.parse(localStorage.getItem('wordlist_cc')) || [];
  96.  
  97. const wordRegex = wordlistCc.length > 0 ? new RegExp('\\b(' + wordlistCc.map(word => word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|') + ')\\b', 'gi') : null;
  98.  
  99. Array.from(pTags).forEach((pTag) => {
  100. if (
  101. pTag.dataset.colorChanged === "true" ||
  102. pTag.querySelector("code") ||
  103. pTag.querySelector("img") ||
  104. pTag.querySelector("textarea") ||
  105. pTag.querySelector("button") ||
  106. pTag.querySelector("div")
  107. ) {
  108. return; // Skip iteration
  109. }
  110.  
  111. let text = pTag.innerHTML;
  112.  
  113. // Save .katex elements' original HTML and replace with placeholders
  114. const katexElems = Array.from(pTag.querySelectorAll(".katex"));
  115. const katexReplacements = katexElems.map((elem, index) => {
  116. const placeholder = `KATEX_PLACEHOLDER_${index}`;
  117. text = text.replace(elem.outerHTML, placeholder);
  118. return { html: elem.outerHTML, placeholder };
  119. });
  120.  
  121. // Handle <a> tags by removing them temporarily and saving their HTML for later restoration
  122. const aTags = Array.from(pTag.getElementsByTagName("a"));
  123. const aTagsReplacements = aTags.map((aTag, j) => {
  124. const placeholder = `REPLACE_ME_${j}`;
  125. text = text.replace(aTag.outerHTML, placeholder);
  126. return { tag: aTag, placeholder };
  127. });
  128.  
  129. // Change text within quotation marks and for specific words based on the regex
  130. text = text.replace(/(["“”«»].*?["“”«»])/g, `<span style="color: ${quotationMarksColor}">$1</span>`);
  131. // text = text.replace(/(["“”«»][^"]*?,["“”«»])/g, `<span style="color: #E0DF7F">$1</span>`);
  132.  
  133. if (wordRegex) {
  134. text = text.replace(wordRegex, `<span style="color: ${customColor}">$1</span>`);
  135. }
  136.  
  137. // Restore .katex elements and <a> tags
  138. [...katexReplacements, ...aTagsReplacements].forEach(({ html, placeholder, tag }) => {
  139. text = text.replace(placeholder, html || tag.outerHTML);
  140. });
  141.  
  142. // Update the innerHTML and mark the <p> tag to avoid re-processing
  143. pTag.innerHTML = text;
  144. pTag.dataset.colorChanged = "true";
  145. });
  146.  
  147. console.log("Changed colors");
  148. }
  149.  
  150. const divElements = document.querySelectorAll('div');
  151.  
  152. divElements.forEach(div => {
  153. const observer = new MutationObserver(changeColors);
  154. observer.observe(div, { subtree: true, childList: true });
  155. });
  156.  
  157.  
  158.  
  159. function createButton(symbol, onClick) {
  160. const colorpalettebutton = document.createElement('button');
  161. colorpalettebutton.innerHTML = symbol;
  162. colorpalettebutton.style.position = 'relative';
  163. colorpalettebutton.style.background = 'none';
  164. colorpalettebutton.style.border = 'none';
  165. colorpalettebutton.style.fontSize = '18px';
  166. colorpalettebutton.style.top = '-5px';
  167. colorpalettebutton.style.cursor = 'pointer';
  168. colorpalettebutton.addEventListener('click', onClick);
  169. return colorpalettebutton;
  170. }
  171.  
  172. // Function to create the color selector panel
  173. function createColorPanel() {
  174. const panel = document.createElement('div');
  175. panel.id = 'colorPanel';
  176. panel.style.position = 'fixed';
  177. panel.style.top = '50%';
  178. panel.style.left = '50%';
  179. panel.style.transform = 'translate(-50%, -50%)';
  180. const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
  181. if (currentTheme === 'dark') {
  182. panel.style.backgroundColor = 'rgba(19, 19, 22, 0.95)';
  183. } else {
  184. panel.style.backgroundColor = 'rgba(214, 214, 221, 0.95)';
  185. }
  186. panel.style.border = 'none';
  187. panel.style.borderRadius = '5px';
  188. panel.style.padding = '20px';
  189. // panel.style.border = '2px solid #000';
  190. panel.style.zIndex = '9999';
  191.  
  192. const categories = ['italic', 'quotationmarks', 'plaintext', 'custom', 'charbubble', 'userbubble', 'guide', 'body', 'input', 'accent'];
  193.  
  194. const colorPickers = {};
  195.  
  196. // Set a fixed width for the labels
  197. const labelWidth = '150px';
  198.  
  199.  
  200.  
  201.  
  202. categories.forEach(category => {
  203. const colorPicker = document.createElement('input');
  204. colorPicker.type = 'color';
  205.  
  206. // Retrieve stored color from local storage
  207. const storedColor = localStorage.getItem(`${category}_color`);
  208. if (storedColor) {
  209. colorPicker.value = storedColor;
  210. }
  211.  
  212. colorPickers[category] = colorPicker;
  213.  
  214. // Create a div to hold color picker
  215. const colorDiv = document.createElement('div');
  216. colorDiv.style.position = 'relative';
  217. colorDiv.style.width = '20px';
  218. colorDiv.style.height = '20px';
  219. colorDiv.style.marginLeft = '10px';
  220. colorDiv.style.top = '0px';
  221. colorDiv.style.backgroundColor = colorPicker.value;
  222. colorDiv.style.display = 'inline-block';
  223. colorDiv.style.marginRight = '10px';
  224. colorDiv.style.cursor = 'pointer';
  225. colorDiv.style.border = '1px solid black';
  226.  
  227. // Event listener to open color picker when the color square is clicked
  228. colorDiv.addEventListener('click', function () {
  229. colorPicker.click();
  230. });
  231.  
  232. // Event listener to update the color div when the color changes
  233. colorPicker.addEventListener('input', function () {
  234. colorDiv.style.backgroundColor = colorPicker.value;
  235. });
  236.  
  237. const label = document.createElement('label');
  238. label.style.width = labelWidth; // Set fixed width for the label
  239. label.style.margin = '0'; // Reduce label margin
  240. label.style.padding = '0'; // Reduce label padding
  241. label.appendChild(document.createTextNode(`${category}: `));
  242.  
  243. // Reset button for each color picker
  244. const resetButton = createButton('↺', function () {
  245. colorPicker.value = getDefaultColor(category);
  246. colorDiv.style.backgroundColor = colorPicker.value;
  247. });
  248. resetButton.style.position = 'relative';
  249. resetButton.style.top = '-2px';
  250. resetButton.style.margin = '0'; // Reduce button margin
  251. resetButton.style.padding = '0'; // Reduce button padding
  252.  
  253. // Create a div to hold label, color picker, and reset button
  254. const containerDiv = document.createElement('div');
  255. containerDiv.style.margin = '2px 0'; // Reduce vertical margin between rows
  256. containerDiv.style.padding = '0'; // Reduce padding within each row
  257. containerDiv.style.display = 'flex'; // Flex display for better control over spacing
  258. containerDiv.style.alignItems = 'center'; // Center align items vertically
  259.  
  260. containerDiv.appendChild(label);
  261. containerDiv.appendChild(colorDiv);
  262. containerDiv.appendChild(resetButton);
  263.  
  264. panel.appendChild(containerDiv);
  265. });
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272. // Create a new button for custom font selection
  273. const fontSelectorButton = document.createElement('button');
  274. fontSelectorButton.style.marginBottom = '20px';
  275. fontSelectorButton.style.borderRadius = '3px';
  276. fontSelectorButton.style.width = '120px';
  277. fontSelectorButton.style.marginLeft = '0px';
  278. fontSelectorButton.style.height = '30px';
  279. fontSelectorButton.style.border = 'none';
  280. fontSelectorButton.style.textAlign = 'left';
  281. fontSelectorButton.style.paddingLeft = '-10px';
  282. fontSelectorButton.innerText = 'Select Font';
  283.  
  284. // Create a dropdown for font selection
  285. const fontDropdown = document.createElement('select');
  286. fontDropdown.style.marginLeft = '5px';
  287. fontDropdown.style.marginBottom = '20px';
  288. fontDropdown.style.borderRadius = '3px';
  289. fontDropdown.style.paddingLeft = '-20px';
  290. fontDropdown.style.height = '30px';
  291.  
  292. // List of font options
  293. const fonts = [
  294. { name: 'Onest', value: '__Onest_b2ce1d' },
  295. { name: 'Inter', value: '__Inter_918210' },
  296. { name: 'Noto Sans', value: 'Noto Sans' },
  297. { name: 'Arial', value: 'Arial' },
  298. { name: 'Times New Roman', value: 'Times New Roman' },
  299. { name: 'Verdana', value: 'Verdana' },
  300. { name: 'Roboto', value: 'Roboto' }
  301. ];
  302.  
  303. // Add fonts to the dropdown
  304. fonts.forEach(font => {
  305. const option = document.createElement('option');
  306. option.value = font.value;
  307. option.text = font.name;
  308. fontDropdown.appendChild(option);
  309. });
  310.  
  311. // Load saved font from local storage
  312. const savedFont = localStorage.getItem('selected_font');
  313. if (savedFont) {
  314. fontDropdown.value = savedFont;
  315. }
  316.  
  317. // Create a dropdown for font size selection
  318. const fontSizeDropdown = document.createElement('select');
  319. fontSizeDropdown.style.marginLeft = '5px';
  320. fontSizeDropdown.style.marginBottom = '20px';
  321. fontSizeDropdown.style.borderRadius = '3px';
  322. fontSizeDropdown.style.height = '30px';
  323.  
  324. // List of font size options
  325. const fontSizes = [
  326. { name: '12px', value: '12px' },
  327. { name: '14px', value: '14px' },
  328. { name: '15px', value: '15px' },
  329. { name: '16px', value: '16px' }, // Default font size
  330. { name: '17px', value: '17px' },
  331. { name: '18px', value: '18px' },
  332. { name: '20px', value: '20px' },
  333. { name: '24px', value: '24px' },
  334. { name: '28px', value: '28px' }
  335. ];
  336.  
  337. // Add font sizes to the dropdown
  338. fontSizes.forEach(size => {
  339. const option = document.createElement('option');
  340. option.value = size.value;
  341. option.text = size.name;
  342. fontSizeDropdown.appendChild(option);
  343. });
  344.  
  345. // Load saved font size from local storage
  346. const savedFontSize = localStorage.getItem('font_size') || '16px';
  347. fontSizeDropdown.value = savedFontSize;
  348.  
  349. // Add event listener to save the selected font size to local storage and apply it
  350. fontSizeDropdown.addEventListener('change', function () {
  351. const selectedFontSize = fontSizeDropdown.value;
  352. localStorage.setItem('font_size', selectedFontSize);
  353.  
  354. // Apply the selected font size to the document
  355. document.documentElement.style.setProperty('--font-size', selectedFontSize);
  356.  
  357. // Update CSS dynamically
  358. const css = `
  359. p[node='[object Object]'] {
  360. font-size: ${selectedFontSize} !important;
  361. }
  362.  
  363. p, textarea, button, div.text-sm {
  364. /* Other styles here, without font-size modification */
  365. }
  366. `;
  367.  
  368. // Apply the new style
  369. const styleSheet = document.createElement('style');
  370. styleSheet.type = 'text/css';
  371. styleSheet.innerText = css;
  372. document.head.appendChild(styleSheet);
  373.  
  374. alert('Font size changed to ' + selectedFontSize);
  375. });
  376.  
  377. // Add event listener to save the selected font to local storage and apply it
  378. fontDropdown.addEventListener('change', function () {
  379. const selectedFont = fontDropdown.value;
  380. localStorage.setItem('selected_font', selectedFont);
  381.  
  382. // Apply the selected font to the document
  383. document.documentElement.style.setProperty('--font-family', selectedFont);
  384.  
  385. // Update CSS dynamically
  386. const css = `
  387. p[node='[object Object]'], p, textarea, button, div.text-sm {
  388. font-family: '${selectedFont}', sans-serif !important;
  389. }
  390. `;
  391.  
  392. // Apply the new style
  393. const styleSheet = document.createElement('style');
  394. styleSheet.type = 'text/css';
  395. styleSheet.innerText = css;
  396. document.head.appendChild(styleSheet);
  397.  
  398. alert('Font changed to ' + fontDropdown.options[fontDropdown.selectedIndex].text);
  399. });
  400.  
  401. // Append the button and dropdowns to the panel
  402. panel.appendChild(fontSelectorButton);
  403. panel.appendChild(fontDropdown);
  404. panel.appendChild(fontSizeDropdown);
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413. // Custom word list input
  414. const wordListInput = document.createElement('input');
  415. wordListInput.type = 'text';
  416. wordListInput.placeholder = 'Separate words with commas';
  417. wordListInput.style.width = '250px';
  418. wordListInput.style.height = '35px';
  419. wordListInput.style.borderRadius = '3px';
  420. wordListInput.style.marginBottom = '10px';
  421. panel.appendChild(wordListInput);
  422. panel.appendChild(document.createElement('br'));
  423.  
  424. const wordListContainer = document.createElement('div');
  425. wordListContainer.style.display = 'flex';
  426. wordListContainer.style.flexWrap = 'wrap';
  427. wordListContainer.style.maxWidth = '300px'; // Set a fixed maximum width for the container
  428.  
  429. // Display custom word list buttons
  430. const wordListArray = JSON.parse(localStorage.getItem('wordlist_cc')) || [];
  431. const wordListButtons = [];
  432.  
  433. function createWordButton(word) {
  434. const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
  435.  
  436. const removeSymbol = isMobile ? '×' : '🞮';
  437.  
  438. const wordButton = createButton(`${word} ${removeSymbol}`, function() {
  439. // Remove the word from the list and update the panel
  440. const index = wordListArray.indexOf(word);
  441. if (index !== -1) {
  442. wordListArray.splice(index, 1);
  443. updateWordListButtons();
  444. }
  445. });
  446.  
  447. // Word Buttons
  448. wordButton.style.borderRadius = '3px';
  449. wordButton.style.border = 'none';
  450. if (currentTheme === 'dark') {
  451. wordButton.style.backgroundColor = '#26272B';
  452. } else {
  453. wordButton.style.backgroundColor = '#E4E4E7';
  454. }
  455. wordButton.style.marginBottom = '5px';
  456. wordButton.style.marginRight = '5px';
  457. wordButton.style.fontSize = '16px';
  458. wordButton.classList.add('word-button');
  459. return wordButton;
  460. }
  461.  
  462. function updateWordListButtons() {
  463. wordListContainer.innerHTML = ''; // Clear the container
  464. wordListArray.forEach(word => {
  465. const wordButton = createWordButton(word);
  466. wordListContainer.appendChild(wordButton);
  467. });
  468. }
  469.  
  470.  
  471.  
  472.  
  473.  
  474. updateWordListButtons();
  475.  
  476. // Add Words button
  477. const addWordsButton = document.createElement('button');
  478. addWordsButton.textContent = 'Add';
  479. addWordsButton.style.marginTop = '-8px';
  480. addWordsButton.style.marginLeft = '5px';
  481. addWordsButton.style.borderRadius = '3px';
  482. addWordsButton.style.border = 'none';
  483. if (currentTheme === 'dark') {
  484. addWordsButton.style.backgroundColor = '#26272B';
  485. } else {
  486. addWordsButton.style.backgroundColor = '#E4E4E7';
  487. }
  488. addWordsButton.addEventListener('click', function() {
  489. // Get the input value, split into words, and add to wordListArray
  490. const wordListValue = wordListInput.value;
  491. const newWords = wordListValue.split(',').map(word => word.trim().toLowerCase()).filter(word => word !== ''); // Convert to lowercase and remove empty entries
  492. wordListArray.push(...newWords);
  493.  
  494. // Update the word list buttons in the panel
  495. updateWordListButtons();
  496. });
  497.  
  498. // Create a div to group the input and button on the same line
  499. const inputButtonContainer = document.createElement('div');
  500. inputButtonContainer.style.display = 'flex';
  501. inputButtonContainer.style.alignItems = 'center';
  502.  
  503. inputButtonContainer.appendChild(wordListInput);
  504. inputButtonContainer.appendChild(addWordsButton);
  505.  
  506. // Append the container to the panel
  507. panel.appendChild(inputButtonContainer);
  508. panel.appendChild(wordListContainer);
  509. // Create initial word list buttons
  510. updateWordListButtons();
  511.  
  512.  
  513. // OK button
  514. const okButton = document.createElement('button');
  515. okButton.textContent = 'Confirm';
  516. okButton.style.marginTop = '-20px';
  517. okButton.style.width = '75px';
  518. okButton.style.height = '35px';
  519. okButton.style.marginRight = '5px';
  520. okButton.style.borderRadius = '3px';
  521. okButton.style.border = 'none';
  522. if (currentTheme === 'dark') {
  523. okButton.style.backgroundColor = '#26272B';
  524. } else {
  525. okButton.style.backgroundColor = '#D9D9DF';
  526. }
  527.  
  528. okButton.style.position = 'relative';
  529. okButton.style.left = '24%';
  530. //okButton.style.transform = 'translateX(-50%)';
  531. okButton.addEventListener('click', function() {
  532. // Save selected colors to local storage
  533. categories.forEach(category => {
  534. const oldValue = localStorage.getItem(`${category}_color`);
  535. const newValue = colorPickers[category].value;
  536.  
  537. if (oldValue !== newValue) {
  538. localStorage.setItem(`${category}_color`, newValue);
  539.  
  540. // If 'plaintext' color is changed, auto-reload the page
  541. if (category === 'plaintext' || category === 'guide' || category === 'body' || category === 'input') {
  542. window.location.reload();
  543. }
  544. }
  545. });
  546.  
  547.  
  548. // Save custom word list to local storage
  549. const wordListValue = wordListInput.value;
  550. const newWords = wordListValue.split(',').map(word => word.trim().toLowerCase()).filter(word => word !== ''); // Convert to lowercase and remove empty entries
  551. const uniqueNewWords = Array.from(new Set(newWords)); // Remove duplicates
  552.  
  553. // Check for existing words and add only new ones
  554. uniqueNewWords.forEach(newWord => {
  555. if (!wordListArray.includes(newWord)) {
  556. wordListArray.push(newWord);
  557. }
  558. });
  559.  
  560. localStorage.setItem('wordlist_cc', JSON.stringify(wordListArray));
  561.  
  562. updateWordListButtons();
  563.  
  564. // Close the panel
  565. panel.remove();
  566. });
  567.  
  568. // Cancel button
  569. const cancelButton = document.createElement('button');
  570. cancelButton.textContent = 'Cancel';
  571. cancelButton.style.marginTop = '-20px';
  572. cancelButton.style.borderRadius = '3px';
  573. cancelButton.style.width = '75px';
  574. cancelButton.style.marginLeft = '5px';
  575. cancelButton.style.height = '35px';
  576. cancelButton.style.border = 'none';
  577. if (currentTheme === 'dark') {
  578. cancelButton.style.backgroundColor = '#5E5E5E';
  579. } else {
  580. cancelButton.style.backgroundColor = '#CBD2D4';
  581. }
  582. cancelButton.style.position = 'relative';
  583. cancelButton.style.left = '25%';
  584. cancelButton.addEventListener('click', function() {
  585. // Close the panel without saving
  586. panel.remove();
  587. });
  588.  
  589. // ==== PRESETS ========
  590. // Create button
  591. const preset1 = document.createElement('button');
  592. preset1.style.marginBottom = '20px';
  593. preset1.style.borderRadius = '3px';
  594. preset1.style.width = '30px';
  595. preset1.style.marginLeft = '5px';
  596. preset1.style.height = '30px';
  597. preset1.style.border = 'none';
  598.  
  599. // Set image as button background
  600. preset1.style.backgroundImage = "url('https://i.imgur.com/91Z4AwP.png')";
  601. preset1.style.backgroundSize = 'contain';
  602. preset1.style.backgroundRepeat = 'no-repeat';
  603. preset1.style.backgroundPosition = 'center';
  604.  
  605.  
  606.  
  607.  
  608. // Event listener for button click
  609. preset1.addEventListener('click', function () {
  610.  
  611. // Show confirmation dialog
  612. const userConfirmed = confirm('All colors will be replaced with Discord pallet. Proceed?');
  613.  
  614.  
  615.  
  616. if (userConfirmed) {
  617.  
  618. function updateCSSVariable(variableName, value) {
  619. document.documentElement.style.setProperty(variableName, value);
  620. }
  621. updateCSSVariable('--G850', '#383A40'); //input
  622. updateCSSVariable('--G900', '#313338'); //body
  623. updateCSSVariable('--G950', '#232428'); //guide
  624. // Hardcode the selected colors to local storage
  625. const hardcodedColors = {
  626. 'guide': '#232428',
  627. 'input': '#383A40',
  628. 'body': '#313338',
  629. 'charbubble': '#383A40',
  630. 'userbubble': '#41434A',
  631. 'accent': '#3E4047'
  632. };
  633.  
  634. // Save hardcoded values to local storage
  635. Object.keys(hardcodedColors).forEach(category => {
  636. const newValue = hardcodedColors[category];
  637. localStorage.setItem(`${category}_color`, newValue);
  638. });
  639. window.location.reload();
  640. }
  641. });
  642.  
  643. const preset2 = document.createElement('button');
  644. preset2.style.marginBottom = '20px';
  645. preset2.style.borderRadius = '3px';
  646. preset2.style.width = '30px';
  647. preset2.style.marginLeft = '5px';
  648. preset2.style.height = '30px';
  649. preset2.style.border = 'none';
  650.  
  651. // Set image as button background
  652. preset2.style.backgroundImage = "url('https://i.imgur.com/PSkZ4Yq.png')";
  653. preset2.style.backgroundSize = 'contain';
  654. preset2.style.backgroundRepeat = 'no-repeat';
  655. preset2.style.backgroundPosition = 'center';
  656.  
  657.  
  658.  
  659.  
  660. // Event listener for button click
  661. preset2.addEventListener('click', function () {
  662.  
  663. // Show confirmation dialog
  664. const userConfirmed = confirm('All colors will be replaced with ChatGPT pallet. Proceed?');
  665.  
  666.  
  667.  
  668. if (userConfirmed) {
  669.  
  670. function updateCSSVariable(variableName, value) {
  671. document.documentElement.style.setProperty(variableName, value);
  672. }
  673. updateCSSVariable('--G850', '#2F2F2F'); //input
  674. updateCSSVariable('--G900', '#212121'); //body
  675. updateCSSVariable('--G950', '#171717'); //guide
  676. // Hardcode the selected colors to local storage
  677. const hardcodedColors = {
  678. 'guide': '#171717',
  679. 'input': '#2F2F2F',
  680. 'body': '#212121',
  681. 'charbubble': '#212121',
  682. 'userbubble': '#2F2F2F',
  683. 'accent': '#323232'
  684. };
  685.  
  686. // Save hardcoded values to local storage
  687. Object.keys(hardcodedColors).forEach(category => {
  688. const newValue = hardcodedColors[category];
  689. localStorage.setItem(`${category}_color`, newValue);
  690. });
  691. window.location.reload();
  692. }
  693. });
  694.  
  695. const preset3 = document.createElement('button');
  696. preset3.style.marginBottom = '20px';
  697. preset3.style.borderRadius = '3px';
  698. preset3.style.width = '30px';
  699. preset3.style.marginLeft = '5px';
  700. preset3.style.height = '30px';
  701. preset3.style.border = 'none';
  702.  
  703. // Set image as button background
  704. preset3.style.backgroundImage = "url('https://i.imgur.com/wWpHDIj.png')";
  705. preset3.style.backgroundSize = 'contain';
  706. preset3.style.backgroundRepeat = 'no-repeat';
  707. preset3.style.backgroundPosition = 'center';
  708.  
  709.  
  710.  
  711.  
  712. // Event listener for button click
  713. preset3.addEventListener('click', function () {
  714.  
  715. // Show confirmation dialog
  716. const userConfirmed = confirm('All colors will be replaced with old.character.ai pallet. Proceed?');
  717.  
  718.  
  719.  
  720. if (userConfirmed) {
  721.  
  722. function updateCSSVariable(variableName, value) {
  723. document.documentElement.style.setProperty(variableName, value);
  724. }
  725. updateCSSVariable('--G850', '#242525'); //input
  726. updateCSSVariable('--G900', '#242525'); //body
  727. updateCSSVariable('--G950', '#2B2C2D'); //guide
  728. // Hardcode the selected colors to local storage
  729. const hardcodedColors = {
  730. 'guide': '#2B2C2D',
  731. 'input': '#242525',
  732. 'body': '#242525',
  733. 'charbubble': '#242525',
  734. 'userbubble': '#2B2C2D',
  735. 'accent': '#363838'
  736. };
  737.  
  738. // Save hardcoded values to local storage
  739. Object.keys(hardcodedColors).forEach(category => {
  740. const newValue = hardcodedColors[category];
  741. localStorage.setItem(`${category}_color`, newValue);
  742. });
  743. window.location.reload();
  744. }
  745. });
  746.  
  747.  
  748.  
  749.  
  750.  
  751. panel.appendChild(document.createElement('br'));
  752.  
  753.  
  754. panel.appendChild(preset1);
  755. panel.appendChild(preset2);
  756. panel.appendChild(preset3);
  757. panel.appendChild(document.createElement('br'));
  758. panel.appendChild(okButton);
  759. panel.appendChild(cancelButton);
  760.  
  761. document.body.appendChild(panel);
  762. }
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769. // Function to get the default color for a category
  770. function getDefaultColor(category) {
  771. const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
  772. if (currentTheme === 'dark') {
  773. const defaultColors = {
  774. 'italic': '#E0DF7F',
  775. 'quotationmarks': '#FFFFFF',
  776. 'plaintext': '#A2A2AC',
  777. 'custom': '#E0DF7F',
  778. 'charbubble': '#26272B',
  779. 'userbubble': '#303136',
  780. 'guide': '#131316',
  781. 'input': '#202024',
  782. 'body': '#18181B',
  783. 'accent': '#26272B'
  784. };
  785. return defaultColors[category];
  786. }
  787. else {
  788. const defaultColors = {
  789. 'italic': '#4F7AA6',
  790. 'quotationmarks': '#000000',
  791. 'plaintext': '#374151',
  792. 'custom': '#4F7AA6',
  793. 'charbubble': '#E4E4E7',
  794. 'userbubble': '#D9D9DF',
  795. 'guide': '#FAFAFA',
  796. 'input': '#F4F4F5',
  797. 'body': '#ECECEE',
  798. 'accent': '#26272B'
  799. };
  800. return defaultColors[category];
  801. }
  802. }
  803.  
  804.  
  805.  
  806. const mainButton = createButton('', function() {
  807. const colorPanelExists = document.getElementById('colorPanel');
  808. if (!colorPanelExists) {
  809. createColorPanel();
  810. }
  811. });
  812.  
  813. // Set the background image of the button to the provided image
  814. mainButton.style.backgroundImage = "url('https://i.imgur.com/yBgJ3za.png')";
  815. mainButton.style.backgroundSize = "cover";
  816. mainButton.style.position = "fixed"; // Use "fixed" for a position relative to the viewport
  817. mainButton.style.top = "10px"; // Adjust the top position as needed
  818. mainButton.style.right = "10px"; // Adjust the right position as needed
  819. mainButton.style.width = "22px"; // Adjust the width and height as needed
  820. mainButton.style.height = "22px"; // Adjust the width and height as needed
  821.  
  822. // Function to insert the mainButton into the body of the document
  823. function insertMainButton() {
  824. document.body.appendChild(mainButton);
  825. }
  826.  
  827. // Call the function to insert the mainButton into the body
  828. insertMainButton();
  829.  
  830. console.info('c.ai Text Color Button appended to the top right corner.');