// ==UserScript==
// @name Prompt Manager (Fixed Vertical Drag with Copy & Close)
// @namespace http://tampermonkey.net/
// @version 2.7.6
// @description 在AI网站上保存并快速使用 Prompts,同时支持拖动按钮及位置保存 —— 修复按钮只能横向拖动的问题,增大关闭按钮点击区域并上移碰撞箱,复制后显示成功并自动关闭
// @author schweigen
// @license MIT
// @match https://chatgpt.com/*
// @match https://claude.ai/*
// @match https://aistudio.google.com/*
// @match https://chat.deepseek.com/*
// @match https://www.perplexity.ai/*
// @match https://chat.mistral.ai/*
// @match https://app.nextchat.dev/*
// @match https://chat01.ai/*
// @match https://you.com/*
// @match https://chatgpt.aicnm.cc/*
// @match https://chatshare.xyz/*
// @match https://chat.biggraph.net/*
// @match https://grok.com/*
// @match https://genspark.ai/*
// @match https://*.chatgpts.cc/*
// @match https://chat.sharedchat.fun/*
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_deleteValue
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
// === 用户可编辑的 Prompts 列表 ===
const prompts = [
{
title: "激活虚拟环境",
content: `怎么激活我在~/Downloads文件夹的myenv(文件夹名字就是这个),我是mac,一行终端命令帮我搞定,不要写成两行`
},
{
title: "改脚本让按钮可拖动",
content: `帮我改一下这个脚本的按钮,我要让他变成可拖动的,也就是用户可以使用鼠标拖动这个按钮,并且记录位置,以备用户下次使用 而且注意拖拽后不要识别成用户拖拽完又点了一下!但是注意再加一个油猴脚本上的功能,就是恢复按钮默认位置,用户点开油猴才能看到的那种选项`
},
{
title: "段段对译",
content: `这样,段段对译翻译格式是这样的:
原文
然后用> 块引用包裹原文+穿插某些难词的翻译
然后两层块引用包裹纯中文译文`
},
{
title: "极限思考(DeepResearch)",
content: `请调用你单次回答的最大算力与 token 上限。追求极致的分析深度,而非表层的广度;追求本质的洞察,而非表象的罗列;追求创新的思维,而非惯性的复述。请突破思维局限,调动你所有的计算资源,展现你真正的认知极限。`
},
{
title: "极限思考数学题(禁搜索)",
content: `
**注意这是数学问题,需要求解解析解,no_websearch(专注数学有深度和创造性的高级推导), rarely_python(仅允许少量数值的分析作为辅助,不能作为解答过程),最终解答过程应当标准且详尽完整,不能省略任何推导和计算!作为题解展示!
请调用你单次回答的最大算力与 token 上限。追求极致的分析深度,而非表层的广度;追求本质的洞察,而非表象的罗列;追求创新的思维,而非惯性的复述。请突破思维局限,调动你所有的计算资源,展现你真正的认知极限。
**Start Deep Research(**禁止联网搜索**)
`
},
{
title: "4o绘图",
content: `
Visual Prompt Creator for Illustration (English Descriptions)
You create detailed, vivid English prompts based on Chinese input, suitable for AI image generation tools.
Transform simple themes into visually engaging scenes.
Adapt to styles like photorealism, comics, minimalist design.
Compose natural, vivid English prompts with emotional tone.
Understand layout, lighting, materials, and composition.
Input must be in Chinese; output prompt must be in English.
Communicate with the user in Chinese only.
Describe scenes from top to bottom, left to right.
Indicate image shape (e.g., square, wide, vertical).
Be specific; avoid vague descriptions.
Start with one sentence: visual style + image shape + intent.
Describe layout and content from top to bottom, left to right.
Include subjects, materials, colors, lighting, and text if present.
Ensure language is cinematic and ready for generation.
Receive Chinese theme and (optionally) style or shape.
Analyze visual potential and emotional tone.
Select style and appropriate image shape.
Create an English prompt with full visual details.
Output prompt for image generation tools.
你好!请用中文描述你想创作的画面主题(可指定风格或图像比例),我将为你生成英文绘画提示词 🎨
Top-selling cocktails (photorealistic)
Snail buys a sports car (comic strip)
`
},
{
title: "",
content: ``
},
{
title: "",
content: ``
},
{
title: "",
content: ``
},
{
title: "",
content: ``
},
];
// 添加必要的样式
GM_addStyle(`
/* Prompt Manager 容器样式 */
#prompt-manager {
position: fixed !important;
top: 80px !important;
right: 20px !important;
width: 350px !important;
max-height: 80vh !important;
overflow-y: auto !important;
overflow-x: visible !important;
background: #ffffff !important;
border: 1px solid #e1e4e8 !important;
border-radius: 12px !important;
box-shadow: 0 4px 16px rgba(0,0,0,0.1) !important;
z-index: 2147483647 !important;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
display: block !important;
color: #24292e !important;
opacity: 1 !important;
visibility: visible !important;
}
#prompt-manager.hidden {
display: none !important;
}
/* 标题样式 */
#prompt-manager h2 {
margin: 0 !important;
padding: 16px !important;
background: #2c3e50 !important;
color: #ffffff !important;
border-radius: 12px 12px 0 0 !important;
text-align: center !important;
font-size: 18px !important;
font-weight: 600 !important;
position: relative !important;
}
/* 关闭按钮样式(碰撞箱上移) */
#close-prompt-btn {
position: absolute !important;
top: -10px !important; /* 向上移动显示区域 */
right: 0 !important;
padding: 10px 16px !important;
cursor: pointer !important;
font-size: 20px !important;
color: #ffffff !important;
user-select: none !important;
}
/* Prompt 项样式 */
.prompt-item {
border-bottom: 1px solid #e1e4e8 !important;
padding: 12px 16px !important;
position: relative !important;
transition: all 0.2s ease !important;
background: #ffffff !important;
}
.prompt-item:hover {
background: #f6f8fa !important;
}
.prompt-title {
font-weight: 500 !important;
cursor: pointer !important;
position: relative !important;
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
color: #2c3e50 !important;
}
.prompt-content {
display: none !important;
margin-top: 8px !important;
white-space: pre-wrap !important;
background: #f8f9fa !important;
padding: 12px !important;
border-radius: 6px !important;
cursor: pointer !important;
transition: background 0.2s ease !important;
color: #2c3e50 !important;
border: 1px solid #e1e4e8 !important;
}
.prompt-content:hover {
background: #edf2f7 !important;
}
/* 复制按钮样式 */
.copy-button {
background: #3498db !important;
color: #ffffff !important;
border: none !important;
padding: 6px 12px !important;
border-radius: 4px !important;
cursor: pointer !important;
font-size: 12px !important;
margin-left: 10px !important;
transition: all 0.2s ease !important;
}
.copy-button:hover {
background: #2980b9 !important;
transform: translateY(-1px) !important;
}
/* Toggle 按钮样式 */
#toggle-prompt-btn {
position: fixed !important;
top: 60px !important;
right: 20px !important;
width: 40px !important;
height: 40px !important;
background: #3498db !important;
color: #ffffff !important;
border: none !important;
border-radius: 50% !important;
cursor: pointer !important;
font-size: 20px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
z-index: 2147483647 !important;
transition: all 0.2s ease !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important;
opacity: 1 !important;
visibility: visible !important;
}
#toggle-prompt-btn:hover {
background: #2980b9 !important;
transform: translateY(-1px) !important;
}
/* 复制成功提示样式 */
#copy-success {
position: fixed !important;
top: 100px !important;
right: 20px !important;
background: #2ecc71 !important;
color: #ffffff !important;
padding: 8px 16px !important;
border-radius: 6px !important;
opacity: 0 !important;
transition: opacity 0.3s ease !important;
z-index: 2147483647 !important;
font-size: 14px !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important;
}
/* 内部成功提示样式 */
.inner-success {
background: #2ecc71 !important;
color: #ffffff !important;
padding: 8px 12px !important;
margin-top: 8px !important;
border-radius: 6px !important;
text-align: center !important;
font-size: 14px !important;
display: none !important;
}
/* 搜索输入框样式 */
#search-input {
width: calc(100% - 32px) !important;
padding: 10px 12px !important;
margin: 16px !important;
border: 1px solid #e1e4e8 !important;
border-radius: 6px !important;
background: #f8f9fa !important;
color: #2c3e50 !important;
font-size: 14px !important;
transition: all 0.2s ease !important;
}
#search-input:focus {
outline: none !important;
border-color: #3498db !important;
box-shadow: 0 0 0 2px rgba(52,152,219,0.2) !important;
}
#search-input::placeholder {
color: #95a5a6 !important;
}
`);
// 确保DOM加载完成后再创建元素
function createElements() {
// 创建 Toggle 按钮
const toggleBtn = document.createElement('button');
toggleBtn.id = 'toggle-prompt-btn';
toggleBtn.title = '隐藏/显示 Prompt Manager';
toggleBtn.innerHTML = '☰';
document.body.appendChild(toggleBtn);
// 如果用户之前拖动过,则恢复按钮保存的位置
const savedX = GM_getValue('toggleBtnX', null);
const savedY = GM_getValue('toggleBtnY', null);
if (savedX !== null && savedY !== null) {
toggleBtn.style.setProperty('left', savedX + 'px', 'important');
toggleBtn.style.setProperty('top', savedY + 'px', 'important');
toggleBtn.style.setProperty('right', 'auto', 'important');
}
// 创建 Prompt Manager 容器,增加了关闭叉号
const manager = document.createElement('div');
manager.id = 'prompt-manager';
manager.classList.add('hidden'); // 默认隐藏
manager.innerHTML = `
Prompts
×
`;
document.body.appendChild(manager);
// 为关闭叉号添加点击事件
const closeBtn = document.getElementById('close-prompt-btn');
closeBtn.addEventListener('click', () => {
manager.classList.add('hidden');
});
// 创建复制成功提示
const copySuccess = document.createElement('div');
copySuccess.id = 'copy-success';
copySuccess.textContent = '复制成功';
document.body.appendChild(copySuccess);
// 创建一个 Prompt 项
function createPromptItem(prompt, index) {
const item = document.createElement('div');
item.className = 'prompt-item';
const title = document.createElement('div');
title.className = 'prompt-title';
const titleText = document.createElement('span');
titleText.textContent = prompt.title || "无标题 Prompt";
const copyTitleBtn = document.createElement('button');
copyTitleBtn.className = 'copy-button';
copyTitleBtn.textContent = '复制';
copyTitleBtn.title = '复制整个 Prompt 内容';
// 创建内部成功提示元素
const innerSuccess = document.createElement('div');
innerSuccess.className = 'inner-success';
innerSuccess.textContent = '复制成功';
innerSuccess.style.display = 'none';
copyTitleBtn.onclick = (e) => {
e.stopPropagation();
if (prompt.content) {
copyToClipboard(prompt.content, item);
} else {
showInnerSuccess(item, '内容为空,无法复制。');
}
};
// 仅添加标题和复制按钮
title.appendChild(titleText);
title.appendChild(copyTitleBtn);
const content = document.createElement('div');
content.className = 'prompt-content';
content.textContent = prompt.content || "无内容 Prompt";
content.addEventListener('click', () => {
if (prompt.content) {
copyToClipboard(prompt.content, item);
} else {
showInnerSuccess(item, '内容为空,无法复制。');
}
});
// 仅添加点击切换内容显示
title.addEventListener('click', () => {
const isVisible = content.style.display === 'block';
content.style.display = isVisible ? 'none' : 'block';
});
item.appendChild(title);
item.appendChild(content);
item.appendChild(innerSuccess); // 添加内部成功提示
return item;
}
// 渲染 Prompts 列表
function renderPrompts(filter = '') {
const promptList = document.getElementById('prompt-list');
promptList.innerHTML = '';
const filtered = prompts.filter(p =>
(p.title && p.title.toLowerCase().includes(filter.toLowerCase())) ||
(p.content && p.content.toLowerCase().includes(filter.toLowerCase()))
);
filtered.forEach((prompt, index) => {
const item = createPromptItem(prompt, index);
promptList.appendChild(item);
});
}
// 复制到剪贴板并显示成功提示
function copyToClipboard(text, promptItem) {
navigator.clipboard.writeText(text).then(() => {
showInnerSuccess(promptItem, '复制成功');
}).catch(err => {
console.error('复制失败: ', err);
showInnerSuccess(promptItem, '复制失败,请手动复制。');
});
}
// 显示成功提示并立即关闭面板
function showInnerSuccess(promptItem, message = '复制成功') {
// 直接关闭面板,不显示内部提示
document.getElementById('prompt-manager').classList.add('hidden');
// 在外部显示一个简短的提示
showCopySuccess(message);
}
// 显示复制成功提示(保留旧函数以兼容)
function showCopySuccess(message = '复制成功') {
copySuccess.textContent = message;
copySuccess.style.opacity = '1';
setTimeout(() => {
copySuccess.style.opacity = '0';
}, 1500);
}
// ======= 以下为拖拽功能 =======
let isDragging = false, justDragged = false, startX, startY, origLeft, origTop;
toggleBtn.addEventListener('mousedown', function(e) {
if (e.button !== 0) return; // 仅响应鼠标左键
isDragging = false;
startX = e.clientX;
startY = e.clientY;
// 获取当前按钮的位置(相对于视口)
const rect = toggleBtn.getBoundingClientRect();
origLeft = rect.left;
origTop = rect.top;
function onMouseMove(e) {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
if (!isDragging) {
// 超过 5px 视为拖拽操作
if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
isDragging = true;
}
}
if (isDragging) {
// 使用 setProperty 带上 'important' 以覆盖样式中的 !important
toggleBtn.style.setProperty('left', (origLeft + dx) + 'px', 'important');
toggleBtn.style.setProperty('top', (origTop + dy) + 'px', 'important');
toggleBtn.style.setProperty('right', 'auto', 'important');
e.preventDefault();
}
}
function onMouseUp(e) {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
if (isDragging) {
justDragged = true;
// 保存新位置
const newLeft = parseInt(toggleBtn.style.left, 10);
const newTop = parseInt(toggleBtn.style.top, 10);
GM_setValue('toggleBtnX', newLeft);
GM_setValue('toggleBtnY', newTop);
}
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
// 修改点击事件,避免拖拽后触发点击
toggleBtn.addEventListener('click', (e) => {
if (justDragged) {
justDragged = false;
return;
}
manager.classList.toggle('hidden');
});
// Toggle 按钮快捷键显示/隐藏 Prompt Manager (Ctrl/Command + O)
document.addEventListener('keydown', (e) => {
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const modifier = isMac ? e.metaKey : e.ctrlKey;
if (modifier && e.key.toLowerCase() === 'o') {
e.preventDefault();
manager.classList.toggle('hidden');
}
});
// 搜索 Prompts
const searchInput = document.getElementById('search-input');
searchInput.addEventListener('input', () => {
renderPrompts(searchInput.value);
});
// 初始渲染
renderPrompts();
}
// 确保DOM加载完成后再创建元素
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', createElements);
} else {
createElements();
}
// 每隔一秒检查一次是否需要重新创建元素(用于处理某些网站的动态加载)
let checkInterval = setInterval(() => {
if (!document.getElementById('toggle-prompt-btn')) {
createElements();
}
}, 1000);
// 5分钟后停止检查,以避免无限循环
setTimeout(() => {
clearInterval(checkInterval);
}, 300000); // 5分钟
// ======= 添加油猴菜单命令,用于重置按钮默认位置 =======
GM_registerMenuCommand("重置按钮默认位置", () => {
GM_deleteValue('toggleBtnX');
GM_deleteValue('toggleBtnY');
const toggleBtn = document.getElementById('toggle-prompt-btn');
if (toggleBtn) {
toggleBtn.style.setProperty('top', '60px', 'important');
toggleBtn.style.setProperty('right', '20px', 'important');
toggleBtn.style.removeProperty('left');
}
});
})();