您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
修改Caveduck網站的樣式。
当前为
// ==UserScript== // @name Caveduck Modifier // @namespace https://muyi.tw/labs/caveduck_modifier/ // @version 0.23 // @description 修改Caveduck網站的樣式。 // @license AGPL-3.0-or-later // @author 慕儀 // @match *://caveduck.io/talk/* // @match *://caveduck.io/created-characters/edit/* // @match *://caveduck.io/*-editor/* // @match *://caveduck.io/prompt-build-script/* // @grant GM_addStyle // @icon data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDEyODAgMTI4MCI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogI2ZmZjsKICAgICAgfQoKICAgICAgLmNscy0yIHsKICAgICAgICBmaWxsOiAjZjJiNDEyOwogICAgICB9CiAgICA8L3N0eWxlPgogIDwvZGVmcz4KICA8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMjguNy4xLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogMS4yLjAgQnVpbGQgMTQyKSAgLS0+CiAgPGc+CiAgICA8ZyBpZD0iQ2F2ZWR1Y2siPgogICAgICA8ZyBpZD0iQ2F2ZWR1Y2stMiIgZGF0YS1uYW1lPSJDYXZlZHVjayI+CiAgICAgICAgPHBhdGggZD0iTTEwOTYuMSw0NTMuNWMzMDUuMiw0OTcuMywxNTIuNiw3NDYtNDU3LjgsNzQ2Uy0xMjQuNiw5NTAuOCwxODAuNiw0NTMuNWMzMDUuMi00OTcuMyw2MTAuMy00OTcuMyw5MTUuNSwwWiIvPgogICAgICAgIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTExNDcuNiw0NTMuNWMyMDguOCwzNjEuNywxMDQuNCw1NDIuNS0zMTMuMiw1NDIuNXMtNTIyLTE4MC44LTMxMy4yLTU0Mi41YzIwOC44LTM2MS43LDQxNy42LTM2MS43LDYyNi41LDBaIi8+CiAgICAgICAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNNjg0LDcyMS4yYzEwMC4yLDE3My42LDUwLjEsMjYwLjQtMTUwLjMsMjYwLjRzLTI1MC42LTg2LjgtMTUwLjMtMjYwLjRjMTAwLjItMTczLjYsMjAwLjUtMTczLjYsMzAwLjcsMFoiLz4KICAgICAgICA8cGF0aCBkPSJNODcxLjksNjEyLjdjMjUuMSw0My40LDEyLjUsNjUuMS0zNy42LDY1LjFzLTYyLjYtMjEuNy0zNy42LTY1LjFjMjUuMS00My40LDUwLjEtNDMuNCw3NS4yLDBaIi8+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPg== // ==/UserScript== (function () { 'use strict'; let inLanguage, sw_fontOverride, sw_replaceText, sw_autoHeight; const tarAutoHeight = `prompt-input`; const tarAutoScrollHeight = `lorebook-data-input textarea`; const textReplaceSelector = `#chatMessages b:not([data-text-replaced]), #chatMessages p:not([data-text-replaced])`; const $ = (selector) => document.querySelectorAll(selector); const muyiStyles = 'https://muyi.tw/labs/caveduck_modifier/style.css?v=1131127'; const fontStyles = ` user-input-form div[ng-repeat] textarea, #chatMessages b, #chatMessages p, form[ng-if~="!!chat.editMode"] textarea { font: normal clamp(16px, .8vw, 32px) / 1.75em var(--m_ff1); } #chatMessages b { font-family: var(--m_ff2); } form[ng-if~="!!chat.editMode"] textarea { font-size: var(--m_font-size); } user-input-form div[ng-repeat] textarea { font-size: var(--m_font-size); } `; const charMap = { '\\.{2,}': '⋯⋯', '⋯': '⋯⋯', '⋯{3,}': '⋯⋯', '!': '!', '\\?': '?', '~': '~', ';': ';', ':': ':', ',': ',', '\\.': '。', '\\(': '(', '\\)': ')' }; // 主要動作 function mainAction() { if (sw_autoHeight) initializeAutoHeight(); if (['zh-hant', 'zh-hans', 'ja', 'ko'].includes(inLanguage) && (sw_replaceText)) replaceTextContent(); } // 添加自訂樣式 function addCustomStyles() { GM_addStyle(fontStyles); console.log("Custom styles added."); } // 自動調整高度的核心函式 function autoHeight(el) { el.style.height = 'auto'; el.style.overflow = 'auto'; } function autoScrollHeight(el) { autoHeight(el); el.style.height = `${el.scrollHeight}px`; } // 初始化符合條件的元素 function initializeAutoHeight() { const debouncedAutoHeight = debounce(() => { $(tarAutoHeight).forEach(autoHeight); $(tarAutoScrollHeight).forEach(autoScrollHeight); }, 200, 2); debouncedAutoHeight(); window.addEventListener('keydown', debouncedAutoHeight); window.addEventListener('mousedown', debouncedAutoHeight); } // 替換指定選擇符的內容 function replaceTextContent() { const processedAttribute = "data-text-replaced"; // 標記屬性名稱 const el = $(`${textReplaceSelector}:not([${processedAttribute}])`); el.forEach((el) => { let originalText = el.textContent; for (const [pattern, replacement] of Object.entries(charMap)) { originalText = originalText.replace(new RegExp(pattern, 'g'), replacement); } el.textContent = originalText; el.setAttribute(processedAttribute, ""); // 添加標記屬性 }); } // 延遲觸發的去抖函式 function debounce(func, delay, repeat) { let timer = null; let count = 1; return () => { func(); if (timer) clearInterval(timer); timer = setInterval(() => { func(); count += 1; if (count >= repeat) { clearInterval(timer); } }, delay); }; } // 啟動 MutationObserver function initializeObserver() { const observer = new MutationObserver(() => { mainAction(); }); observer.observe(document.body, { childList: true, subtree: true }); console.log("MutationObserver initialized."); } // 檢查 inLanguage 並啟動必要功能 function checkInLanguage() { const script = document.querySelector('script[type="application/ld+json"]'); if (script) { try { const jsonData = JSON.parse(script.textContent); inLanguage = jsonData[0]?.inLanguage || ''; } catch (error) { console.error("Failed to parse JSON:", error); } } } // 創建設定按鈕和視窗 function createSettingsUI() { let toggleButtonText, reloadButtonText, fontCheckboxTitle, fontCheckboxDesc, replaceCheckboxTitle, replaceCheckboxDesc, autoHeightCheckboxTitle, autoHeightCheckboxDesc const isZH = ['zh-hant', 'zh-hans'].includes(inLanguage); toggleButtonText = isZH ? '慕儀\n神器' : 'MuYi\'s\nToolbox'; reloadButtonText = isZH ? '套用並重載' : 'Apply and reload'; fontCheckboxTitle = isZH ? '覆蓋字型' : 'Override Font'; fontCheckboxDesc = isZH ? '作用頁:Talk<br>用慕儀喜歡的自訂字型取代預設字型,僅限聊天頁。' : 'Effective page:Talk<br>Replace default font with MuYi\'s preferred custom font.'; replaceCheckboxTitle = isZH ? '取代符號' : 'Replace Symbols'; replaceCheckboxDesc = isZH ? '作作用頁:Talk<br>Claude 3 Haiku會使用錯誤的中文標點符號,這個功能可以修正它,僅限聊天頁。' : 'Effective page:Talk<br>Claude 3 Haiku uses incorrect Chinese punctuation. This feature fixes it.'; autoHeightCheckboxTitle = isZH ? '編輯頁無卷軸' : 'No Scrollbar for Edit Page'; autoHeightCheckboxDesc = isZH ? '作用頁:Edit Character、Lorabook、Custom prompt<br>慕儀認為每個項目使用卷軸十分愚蠢,勾選此項可以將其設為自動高度。' : 'Effective page:Edit Character、Lorabook、Custom prompt<br>MuYi thinks using scrollbars for each item is stupid. Enable this to auto-height.'; // 建立按鈕 const toggleButton = document.createElement('button'); toggleButton.className = 'button--red mt_fixed mt_toggleButton' toggleButton.textContent = toggleButtonText; // 建立設定視窗 const settingsPanel = document.createElement('div'); settingsPanel.className = 'mt_fixed mt_settingsPanel'; settingsPanel.style.display = 'none'; // 核取方塊:覆蓋字型 const fontCheckbox = createCheckbox(fontCheckboxTitle, 'enableFontOverride', true, fontCheckboxDesc); settingsPanel.appendChild(fontCheckbox); // 核取方塊:取代符號 const replaceCheckbox = createCheckbox(replaceCheckboxTitle, 'enableReplaceText', true, replaceCheckboxDesc); settingsPanel.appendChild(replaceCheckbox); // 核取方塊:設定框無卷軸 const autoHeightCheckbox = createCheckbox(autoHeightCheckboxTitle, 'enableautoHeight', true, autoHeightCheckboxDesc); settingsPanel.appendChild(autoHeightCheckbox); // 重整按鈕 const reloadButton = document.createElement('button'); reloadButton.textContent = reloadButtonText; reloadButton.style.marginTop = '10px'; reloadButton.style.padding = '5px 10px'; reloadButton.style.cursor = 'pointer'; reloadButton.className = 'button--red'; reloadButton.addEventListener('click', () => location.reload()); settingsPanel.appendChild(reloadButton); // 切換視窗顯示 toggleButton.addEventListener('click', () => { settingsPanel.style.display = settingsPanel.style.display === 'none' ? 'block' : 'none'; }); // 加入到頁面 document.body.appendChild(toggleButton); document.body.appendChild(settingsPanel); } // 建立核取方塊元件 function createCheckbox(labelText, storageKey, defaultValue, tooltipText = '') { const wrapper = document.createElement('div'); const label = document.createElement('label'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = JSON.parse(localStorage.getItem(storageKey) || defaultValue); checkbox.addEventListener('change', () => { localStorage.setItem(storageKey, checkbox.checked); }); label.appendChild(checkbox); label.appendChild(document.createTextNode(labelText)); if (tooltipText) { const tooltip = document.createElement('div'); tooltip.innerHTML = `${tooltipText}`; label.appendChild(tooltip); } wrapper.appendChild(label); return wrapper; } function checkSettings() { checkInLanguage(); sw_fontOverride = JSON.parse(localStorage.getItem('enableFontOverride') || 'false'); sw_replaceText = JSON.parse(localStorage.getItem('enableReplaceText') || 'false'); sw_autoHeight = JSON.parse(localStorage.getItem('enableautoHeight') || 'false'); if (sw_fontOverride) addCustomStyles(); mainAction(); } function setStylesheet() { const link = document.createElement("link"); link.rel = 'stylesheet'; link.href = muyiStyles; document.head.appendChild(link); } window.addEventListener('load', () => { setStylesheet(); checkSettings(); createSettingsUI(); setTimeout(initializeObserver, 100); }); })();