// ==UserScript== // @name Prompt Manager // @namespace http://tampermonkey.net/ // @version 1.0 // @description Fixed focus issue with search, import, and export (search below list) // @author yowaimono // @match https://grok.com/chat/* // @match https://askmanyai.cn/chat/* // @match https://chat.deepseek.com/a/chat/* // @match https://yuanbao.tencent.com/* // @match https://kimi.moonshot.cn/chat/* // @match https://www.wenxiaobai.com/chat/* // @match https://chatgpt.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org // @grant none // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/528364/Prompt%20Manager.user.js // @updateURL https://update.greasyfork.icu/scripts/528364/Prompt%20Manager.meta.js // ==/UserScript== (function() { 'use strict'; // 配置数据 const STORAGE_KEY = 'promptManagerData'; let prompts = JSON.parse(localStorage.getItem(STORAGE_KEY)) || []; let filteredPrompts = [...prompts]; // 用于存储搜索结果 let currentEditIndex = null; let isMinimized = false; let lastFocusedElement = null; // 新增:记录最后聚焦的元素 // 创建主容器 const container = document.createElement('div'); container.id = 'prompt-manager'; container.innerHTML = `

提示词管理

${currentEditIndex !== null ? '编辑提示词' : '新建提示词'}

`; document.body.appendChild(container); // 主样式(完全保持原样) const style = document.createElement('style'); style.textContent = ` #prompt-manager { position: fixed; top: 20px; right: 20px; width: 320px; background: #fff; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12); z-index: 9999; font-family: 'Helvetica Neue', Arial, sans-serif; transition: all 0.3s ease; } #prompt-manager.minimized { width: 40px; height: 40px; border-radius: 50%; overflow: hidden; cursor: pointer; } #prompt-manager.minimized .pm-header { border-bottom: none; padding: 0; height: 100%; display: flex; align-items: center; justify-content: center; } #prompt-manager.minimized .pm-header h3 { display: none; } #prompt-manager.minimized .pm-header-buttons { display: none; } #prompt-manager.minimized .pm-list, #prompt-manager.minimized .pm-modal, #prompt-manager.minimized .pm-search-container { display: none !important; } #prompt-manager.minimized .pm-header::before { content: 'AI'; color: #1890ff; font-size: 16px; font-weight: bold; } .pm-header { display: flex; justify-content: space-between; align-items: center; padding: 16px; border-bottom: 1px solid #f0f0f0; } .pm-header h3 { margin: 0; font-size: 16px; color: #1f1f1f; } .pm-header-buttons { display: flex; gap: 8px; align-items: center; /* 垂直居中 */ } .pm-icon-btn { width: 32px; height: 32px; border: none; background: #1890ff; border-radius: 6px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s; color: #fff; } .pm-icon-btn:hover { background: #40a9ff; } .pm-icon-btn#pm-minimize { background: #blue; color: blue; border: 1px solid #1890ff; font-size: 14px; font-weight: bold; } .pm-icon { color: #fff; font-size: 20px; line-height: 1; } .pm-list { max-height: 150px; /* 固定高度为200px */ overflow-y: auto; padding: 8px; } .pm-item { display: flex; align-items: center; padding: 12px; margin: 4px; background: #f8fafb; border-radius: 8px; transition: background 0.2s; cursor: pointer; } .pm-item:hover { background: #e6f4ff; } .pm-item-title { flex: 1; font-size: 14px; color: #434343; overflow: hidden; text-overflow: ellipsis; } .pm-item-actions { display: flex; gap: 8px; opacity: 0; transition: opacity 0.2s; } .pm-item:hover .pm-item-actions { opacity: 1; } .pm-modal { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.4); justify-content: center; align-items: center; overflow: auto; } .pm-modal-content { background: #fff; width: 440px; border-radius: 12px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); max-height: 90vh; overflow: auto; } .pm-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 16px; border-bottom: 1px solid #f0f0f0; } .pm-modal-header h4 { margin: 0; font-size: 16px; color: #1d1d1d; } .pm-modal-body { padding: 16px; } .pm-input, .pm-textarea { width: 90%; padding: 8px 12px; border: 1px solid #e0e0e0; border-radius: 6px; margin: 8px 0; font-size: 14px; transition: border-color 0.2s; } .pm-input:focus, .pm-textarea:focus { border-color: #1890ff; outline: none; } .pm-textarea { height: 100px; resize: vertical; } .pm-modal-footer { padding: 16px; text-align: right; border-top: 1px solid #f0f0f0; } .pm-btn { padding: 8px 16px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.2s; } .pm-primary { background: #1890ff; color: #fff; } .pm-primary:hover { background: #40a9ff; } .pm-btn:not(.pm-primary) { background: #f5f5f5; color: #666; margin-left: 8px; } .pm-btn:not(.pm-primary):hover { background: #e0e0e0; } .pm-search-container { padding: 8px; border-top: 1px solid #f0f0f0; } `; document.head.appendChild(style); // 新增:焦点追踪逻辑 document.addEventListener('focusin', (e) => { if (!container.contains(e.target)) { const target = e.target; if (target.matches('input, textarea, [contenteditable="true"]')) { lastFocusedElement = target; } } }); // 渲染列表 function renderList() { const list = document.getElementById('pm-list'); list.innerHTML = ''; // 清空列表 filteredPrompts.forEach((item, index) => { const listItem = document.createElement('div'); listItem.classList.add('pm-item'); listItem.innerHTML = ` ${item.title}
`; // 修改事件处理 const [editBtn, deleteBtn] = listItem.querySelectorAll('.pm-icon-btn'); // 阻止按钮获取焦点 editBtn.addEventListener('mousedown', e => e.preventDefault()); deleteBtn.addEventListener('mousedown', e => e.preventDefault()); editBtn.addEventListener('click', (e) => { e.stopPropagation(); editPrompt(prompts.indexOf(item)); // 传递原始索引 }); deleteBtn.addEventListener('click', (e) => { e.stopPropagation(); deletePrompt(prompts.indexOf(item)); // 传递原始索引 }); // 阻止列表项获取焦点 listItem.addEventListener('mousedown', e => e.preventDefault()); listItem.addEventListener('click', () => { if (lastFocusedElement) { pasteToFocusedElement(item.content); } else { alert('请先点击需要输入的位置'); } }); list.appendChild(listItem); }); } // 修改粘贴函数 function pasteToFocusedElement(text) { if (!lastFocusedElement) return; try { // 强制恢复焦点 lastFocusedElement.focus(); if (lastFocusedElement.isContentEditable) { const selection = window.getSelection(); const range = selection.getRangeAt(0); range.deleteContents(); const textNode = document.createTextNode(text); range.insertNode(textNode); range.setStartAfter(textNode); selection.collapseToEnd(); } else { const elem = lastFocusedElement; const start = elem.selectionStart; elem.setRangeText(text, start, start, 'end'); elem.selectionStart = elem.selectionEnd = start + text.length; } // 触发输入事件 const event = new Event('input', { bubbles: true }); lastFocusedElement.dispatchEvent(event); } catch (error) { console.error('粘贴失败,使用剪贴板回退'); navigator.clipboard.writeText(text); alert('已复制到剪贴板,请手动粘贴'); } } // 编辑提示词 window.editPrompt = function(index) { currentEditIndex = index; document.getElementById('pm-title').value = prompts[index].title; document.getElementById('pm-content').value = prompts[index].content; document.getElementById('pm-modal').style.display = 'flex'; }; // 删除提示词 window.deletePrompt = function(index) { prompts.splice(index, 1); localStorage.setItem(STORAGE_KEY, JSON.stringify(prompts)); filterPrompts(); // 重新过滤列表 }; // 添加新提示词 document.getElementById('pm-add').addEventListener('click', () => { currentEditIndex = null; document.getElementById('pm-title').value = ''; document.getElementById('pm-content').value = ''; document.getElementById('pm-modal').style.display = 'flex'; }); // 关闭模态框 document.getElementById('pm-close').addEventListener('click', () => { document.getElementById('pm-modal').style.display = 'none'; }); // 取消操作 document.getElementById('pm-cancel').addEventListener('click', () => { document.getElementById('pm-modal').style.display = 'none'; }); // 保存提示词 document.getElementById('pm-save').addEventListener('click', () => { const title = document.getElementById('pm-title').value.trim(); const content = document.getElementById('pm-content').value.trim(); if (!title || !content) { alert('标题和内容不能为空'); return; } if (currentEditIndex !== null) { prompts[currentEditIndex] = { title, content }; } else { prompts.push({ title, content }); } localStorage.setItem(STORAGE_KEY, JSON.stringify(prompts)); filterPrompts(); // 刷新列表 document.getElementById('pm-modal').style.display = 'none'; }); // 最小化功能 document.getElementById('pm-minimize').addEventListener('click', (e) => { e.stopPropagation(); isMinimized = !isMinimized; container.classList.toggle('minimized', isMinimized); }); container.addEventListener('click', () => { if (isMinimized) { isMinimized = false; container.classList.remove('minimized'); } }); // 导出功能 document.getElementById('pm-export').addEventListener('click', () => { const json = JSON.stringify(prompts); const blob = new Blob([json], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'prompts.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }); // 导入功能 document.getElementById('pm-import').addEventListener('click', () => { document.getElementById('pm-import-file').click(); }); document.getElementById('pm-import-file').addEventListener('change', (event) => { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { try { const json = JSON.parse(e.target.result); if (Array.isArray(json)) { prompts = json; localStorage.setItem(STORAGE_KEY, JSON.stringify(prompts)); filterPrompts(); // 重新渲染列表 alert('导入成功'); } else { alert('文件格式不正确,应为JSON数组'); } } catch (error) { alert('文件解析失败:' + error); } }; reader.readAsText(file); } }); // 搜索功能 const searchInput = document.getElementById('pm-search'); searchInput.addEventListener('input', () => { filterPrompts(searchInput.value.trim()); }); // 过滤提示词 function filterPrompts(searchTerm = '') { if (searchTerm) { const lowerSearchTerm = searchTerm.toLowerCase(); filteredPrompts = prompts.filter(item => item.title.toLowerCase().includes(lowerSearchTerm) || item.content.toLowerCase().includes(lowerSearchTerm) ); } else { filteredPrompts = [...prompts]; // 恢复到所有提示词 } renderList(); } // 初始化 filterPrompts(); })();