// ==UserScript== // @name AI 提示词大师 Pro 9.0 (稳定填充+分类折叠+预览优化) // @namespace http://tampermonkey.net/ // @version 9.1 // @license AGPL-3.0 // @description 解决填充消失,支持分类折叠、半透明自适应预览、原地编辑、追加模式。 // @author WaterHuo // @match https://gemini.google.com/* // @match https://chatgpt.com/* // @match https://claude.ai/* // @match https://chat.deepseek.com/* // @match https://www.doubao.com/* // @match https://www.kimi.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @downloadURL none // ==/UserScript== (function() { 'use strict'; // ======= 1. 深度样式表 ======= GM_addStyle(` #pm-root { font-family: -apple-system, system-ui, sans-serif; } .pm-panel { position: fixed; top: 80px; right: 20px; width: 220px; background: #fff; border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); z-index: 2147483640; border: 1px solid #eee; display: flex; flex-direction: column; } .pm-header { padding: 12px; background: #fcfcfc; border-bottom: 1px solid #f0f0f0; display: flex; justify-content: space-between; align-items: center; border-radius: 12px 12px 0 0; } .pm-title { font-size: 13px; font-weight: 700; color: #1a73e8; display: flex; align-items: center; gap: 5px; } .pm-body { padding: 8px; max-height: 75vh; overflow-y: auto; scrollbar-width: thin; } /* 分类与折叠 */ .pm-cat-wrap { margin-bottom: 8px; border-radius: 8px; overflow: hidden; } .pm-cat-header { display: flex; align-items: center; padding: 6px 4px; background: #f8f9fa; cursor: pointer; group; position: relative; } .pm-cat-fold-icon { font-size: 10px; margin-right: 6px; transition: transform 0.2s; color: #70757a; } .pm-cat-name { font-size: 11px; color: #5f6368; font-weight: 700; flex: 1; text-transform: uppercase; letter-spacing: 0.5px; } .pm-cat-tools { display: none; gap: 6px; margin-right: 4px; } .pm-cat-header:hover .pm-cat-tools { display: flex; } /* 模板列表 */ .pm-tpl-list { padding: 4px 0; } .pm-tpl-list.folded { display: none; } .pm-item-wrap { position: relative; margin-bottom: 2px; } .pm-btn { width: 100%; border: none; background: transparent; padding: 8px 10px; text-align: left; font-size: 12px; border-radius: 6px; cursor: pointer; color: #3c4043; transition: 0.2s; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .pm-btn:hover { background: #f1f3f4; color: #1a73e8; } /* 预览浮窗 (需求2: 半透明、自适应) */ #pm-preview-float { position: fixed; display: none; width: auto; max-width: 200px; background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(8px); border: 1px solid rgba(0,0,0,0.08); box-shadow: 0 4px 16px rgba(0,0,0,0.1); border-radius: 8px; padding: 10px; font-size: 11px; line-height: 1.4; color: #444; z-index: 2147483647; pointer-events: auto; word-break: break-all; transition: opacity 0.2s; } /* 原地编辑器 (需求3) */ .pm-inline-editor { background: #fff; border: 1px solid #1a73e8; border-radius: 8px; padding: 8px; margin: 4px 0; box-shadow: 0 4px 12px rgba(26,115,232,0.15); } .pm-inline-editor textarea { width: 100%; height: 100px; border: 1px solid #dadce0; border-radius: 4px; padding: 6px; font-size: 12px; box-sizing: border-box; resize: vertical; margin: 5px 0; } .pm-inline-editor input, .pm-inline-editor select { width: 100%; border: 1px solid #dadce0; border-radius: 4px; padding: 4px 6px; font-size: 12px; box-sizing: border-box; margin-bottom: 4px; } .pm-ed-btns { display: flex; justify-content: flex-end; gap: 6px; } .pm-ebtn { padding: 3px 8px; font-size: 11px; border-radius: 4px; cursor: pointer; border: none; } .pm-save { background: #1a73e8; color: #fff; } .pm-cancel { background: #f1f3f4; color: #5f6368; } .pm-toast { position: fixed; bottom: 30px; left: 50%; transform: translateX(-50%); background: #323232; color: #fff; padding: 6px 16px; border-radius: 16px; font-size: 12px; z-index: 2147483647; display: none; } `); // ======= 2. 数据与持久化 ======= const DATA_KEY = 'pm_data_v9'; const FOLD_KEY = 'pm_folded_cats'; let promptData = GM_getValue(DATA_KEY, { "写作类": [{ name: "📝 深度润色", content: "请对以下文本进行优化:先梳理逻辑脉络(若原文条理混乱,可按 “总分 / 因果 / 递进” 等清晰结构重组),再优化语言表达 —— 做到简洁精准、流畅自然,剔除冗余重复内容,完整保留原文核心信息与核心意图,不添加额外修饰,仅提升文本的逻辑性与可读性。" }], "代码类": [{ name: "💻 逻辑审查", content: "请检查这段代码是否存在潜在的逻辑错误..." }] }); let foldedCats = GM_getValue(FOLD_KEY, []); // 存储折叠状态的分类名 let isEditMode = false; let previewLock = false; let appendMode = true; // 默认追加模式 // ======= 3. 稳定填充核心 (解决填充消失问题) ======= async function stableInject(text) { const inputField = document.querySelector('div[role="textbox"], #prompt-textarea, textarea[placeholder*="输入"], #chat-input, [contenteditable="true"], textarea'); if (!inputField) return toast("未找到输入框"); inputField.focus(); const isRich = inputField.isContentEditable; const oldVal = isRich ? inputField.innerText : inputField.value; const newVal = (appendMode && oldVal.trim()) ? (oldVal + "\n" + text) : text; try { if (isRich) { // 针对 Gemini/Claude/DeepSeek 富文本模式 const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(inputField); selection.removeAllRanges(); selection.addRange(range); document.execCommand('delete', false); document.execCommand('insertText', false, newVal); } else { // 针对 ChatGPT/豆包/Kimi 原生模式 const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set; setter.call(inputField, newVal); inputField.dispatchEvent(new Event('input', { bubbles: true })); } toast("填充成功"); // 保持焦点并滚动到底部 inputField.focus(); setTimeout(() => { inputField.scrollTop = inputField.scrollHeight; }, 10); } catch (e) { toast("尝试填充失败"); } } // ======= 4. UI 渲染引擎 ======= function toast(msg) { const t = document.getElementById('pm-toast') || (()=>{ const d = document.createElement('div'); d.id='pm-toast'; d.className='pm-toast'; document.body.appendChild(d); return d; })(); t.innerText = msg; t.style.display = 'block'; setTimeout(() => t.style.display = 'none', 2000); } function renderUI() { let root = document.getElementById('pm-root'); if (!root) { root = document.createElement('div'); root.id = 'pm-root'; document.body.appendChild(root); const pf = document.createElement('div'); pf.id = 'pm-preview-float'; document.body.appendChild(pf); } const previewFloat = document.getElementById('pm-preview-float'); root.innerHTML = `
🪄 提示词大师 ${appendMode?'追加':'替换'}
${appendMode?'➕':'🔄'} ${isEditMode ? '✅' : '⚙️'}
${isEditMode ? `
` : ''}
`; const container = document.getElementById('pm-list-container'); Object.keys(promptData).forEach(cat => { const isFolded = foldedCats.includes(cat); const catWrap = document.createElement('div'); catWrap.className = 'pm-cat-wrap'; // 分类头部 const header = document.createElement('div'); header.className = 'pm-cat-header'; header.innerHTML = ` ${cat} ${isEditMode ? `
✏️ ×
` : ''} `; // 折叠点击事件 header.onclick = (e) => { if (e.target.closest('.pm-cat-tools')) return; if (isFolded) foldedCats = foldedCats.filter(c => c !== cat); else foldedCats.push(cat); GM_setValue(FOLD_KEY, foldedCats); renderUI(); }; if (isEditMode) { header.querySelector('.pm-ed-cat').onclick = () => editCatName(catWrap, cat); header.querySelector('.pm-del-cat').onclick = () => deleteCat(cat); } catWrap.appendChild(header); // 模板列表 const tplList = document.createElement('div'); tplList.className = `pm-tpl-list ${isFolded ? 'folded' : ''}`; promptData[cat].forEach((item, idx) => { const itemWrap = document.createElement('div'); itemWrap.className = 'pm-item-wrap'; const btn = document.createElement('button'); btn.className = 'pm-btn'; btn.innerText = item.name; // 预览触发 (需求2) btn.onmouseenter = (e) => { if (isEditMode || previewLock) return; const rect = btn.getBoundingClientRect(); const coreText = item.content.length > 70 ? item.content.substring(0, 70) + "..." : item.content; previewFloat.innerHTML = `
预览
${coreText.replace(/\n/g, '
')}
(点击填充,右侧支持选中复制)
`; previewFloat.style.display = 'block'; // 自适应位置计算 let topPos = rect.top; if (topPos + 150 > window.innerHeight) topPos = window.innerHeight - 160; previewFloat.style.top = `${topPos}px`; previewFloat.style.right = `${window.innerWidth - rect.left + 10}px`; }; btn.onmouseleave = () => { if(!previewLock) previewFloat.style.display = 'none'; }; btn.onclick = () => { if (isEditMode) { editTpl(itemWrap, cat, idx); } else { stableInject(item.content); previewLock = true; setTimeout(() => { previewLock = false; previewFloat.style.display='none'; }, 1500); } }; itemWrap.appendChild(btn); tplList.appendChild(itemWrap); }); if (isEditMode) { const addTplBtn = document.createElement('button'); addTplBtn.className = 'pm-btn'; addTplBtn.style.border = "1px dashed #ccc"; addTplBtn.style.color="#999"; addTplBtn.innerText = "+ 新模板"; addTplBtn.onclick = () => editTpl(tplList, cat, -1, addTplBtn); tplList.appendChild(addTplBtn); } catWrap.appendChild(tplList); container.appendChild(catWrap); }); document.getElementById('pm-config-btn').onclick = () => { isEditMode = !isEditMode; renderUI(); }; document.getElementById('pm-toggle-mode').onclick = () => { appendMode = !appendMode; renderUI(); }; if (isEditMode) document.getElementById('pm-new-cat').onclick = () => { const n = prompt("输入新分类名称:"); if(n) { promptData[n]=[]; saveData(); } }; } // ======= 5. 交互:原地编辑分类/模板 ======= function editCatName(wrap, oldName) { const header = wrap.querySelector('.pm-cat-header'); header.style.display = 'none'; const editor = document.createElement('div'); editor.className = 'pm-inline-editor'; editor.innerHTML = `
`; wrap.prepend(editor); editor.querySelector('.pm-cancel').onclick = () => renderUI(); editor.querySelector('.pm-save').onclick = () => { const n = editor.querySelector('#new-cat-inp').value.trim(); if(n && n !== oldName) { promptData[n] = promptData[oldName]; delete promptData[oldName]; saveData(); } else renderUI(); }; } function deleteCat(catName) { if(promptData[catName].length > 0) { if(!confirm(`该分类下有模板,删除后将迁移至“通用”分类,确定吗?`)) return; if(!promptData["通用"]) promptData["通用"] = []; promptData["通用"] = promptData["通用"].concat(promptData[catName]); } else if(!confirm(`确定删除空分类 [${catName}]?`)) return; delete promptData[catName]; saveData(); } function editTpl(container, cat, idx, addBtn = null) { const isNew = idx === -1; const item = isNew ? { name: "", content: "" } : promptData[cat][idx]; const editor = document.createElement('div'); editor.className = 'pm-inline-editor'; let cats = Object.keys(promptData).map(c => ``).join(''); editor.innerHTML = `
×
`; if(!isNew) container.querySelector('.pm-btn').style.display = 'none'; if(addBtn) addBtn.style.display = 'none'; container.appendChild(editor); editor.querySelector('#pm-clear-ed').onclick = () => editor.querySelector('#ed-cont').value = ""; editor.querySelector('.pm-cancel').onclick = () => renderUI(); editor.querySelector('.pm-save').onclick = () => { const n = editor.querySelector('#ed-name').value.trim(); const c = editor.querySelector('#ed-cont').value; const tCat = editor.querySelector('#ed-cat').value; if(!n || !c) return toast("请完整填写"); if(!isNew) promptData[cat].splice(idx, 1); promptData[tCat].push({ name: n, content: c }); saveData(); toast("保存成功"); }; } function saveData() { GM_setValue(DATA_KEY, promptData); renderUI(); } // ======= 6. 自动检测与启动 ======= const init = () => { if (!document.getElementById('pm-root')) renderUI(); }; setInterval(init, 2000); // 应对单页应用重绘 setTimeout(init, 1000); })();