// ==UserScript== // @name 画图ai提示词管理器-川味面最好吃 // @namespace https://space.bilibili.com/37440705?spm_id_from=333.788.0.0 // @version 4.3 // @description 网页提示词管理器:支持保存、分类、快速使用提示词。请修改@match那行的网址,如果需要多个网站可以多些几行,现在的设置是每个网站都会显示 // @author B站:川味面最好吃 // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // ==/UserScript== (function () { 'use strict'; // 添加样式 // 添加 Toast 样式 GM_addStyle(` .toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 10000; } .toast { background: rgba(0, 0, 0, 0.8); color: white; padding: 10px 20px; border-radius: 4px; margin-top: 10px; animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } /* 通用颜色变量 - 亮色模式 */ :root { --pm-text-color: #ddd; --pm-bg-color: #333; --pm-border-color: #555; --pm-hover-color: #444; --pm-primary-color: #3a80d2; --pm-primary-hover: #2a70c2; --pm-danger-color: #c73c2e; --pm-secondary-color: #777; --pm-border-light: #444; } /* 深色模式 */ .prompt-manager-dark-mode { --pm-text-color: #ddd; --pm-bg-color: #333; --pm-border-color: #555; --pm-hover-color: #444; --pm-primary-color: #3a80d2; --pm-primary-hover: #2a70c2; --pm-danger-color: #c73c2e; --pm-secondary-color: #777; --pm-border-light: #444; } .prompt-manager-menu { position: fixed; background: var(--pm-bg-color); border: 1px solid var(--pm-border-color); border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); padding: 8px; z-index: 9999; min-width: 150px; max-height: 400px; color: var(--pm-text-color); } .prompt-manager-toolbar { display: flex; justify-content: space-between; padding-bottom: 8px; margin-bottom: 8px; } .prompt-manager-toolbar button { background: none; border: none; cursor: pointer; font-size: 14px; padding: 4px; color: var(--pm-text-color); } .prompt-manager-category { padding: 4px 8px; cursor: pointer; margin: 2px 0; color: var(--pm-text-color); } .prompt-manager-category:hover { background: var(--pm-hover-color); border-radius: 4px; } #div1{ position: absolute; height: 100%; width:0; top: 0; left: 0; } .prompt-manager-modal { transform: translateX(-100%); background: var(--pm-bg-color); padding: 10px; border-radius: 8px 0 0 8px; height: 100%; z-index: 10000; min-width: 300px; max-width: 520px; color: var(--pm-text-color); border: 1px solid #666; border-right: 0; display: flex ; flex-direction: column; justify-content: space-between; } .prompt-manager-modal2{ position: fixed; top: 50%; left: 20px; transform: translateY(-50%); background: var(--pm-bg-color); padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); z-index: 10000; min-width: 300px; max-width: 520px; color: var(--pm-text-color); } .settings-section { margin-bottom: 20px; padding-bottom: 15px; border-bottom: 1px solid var(--pm-border-light); } .settings-section:last-child { border-bottom: none; margin-bottom: 15px; } .settings-section h4 { margin: 0 0 10px 0; color: var(--pm-text-color); } /* 触摸设备优化 */ @media (hover: none) { .prompt-manager-button, .toolbar-btn, .prompt-favorite, .prompt-edit, .prompt-delete { min-height: 44px; min-width: 44px; } .prompt-manager-list-item { padding: 12px 8px; } .prompt-actions { opacity: 1; } .prompt-manager-category { padding: 12px 8px; } } .prompt-manager-input { width: 100%; padding: 8px; margin: 8px 0; border: 1px solid #ddd; border-radius: 4px; color: var(--pm-text-color); } .prompt-manager-button { padding: 8px 16px; margin: 4px; border: none; border-radius: 4px; background: var(--pm-primary-color); color: white; cursor: pointer; } .prompt-manager-button:hover { background: var(--pm-primary-hover); } .prompt-manager-button.danger { background: var(--pm-danger-color); } .prompt-manager-button.secondary { background: #999; } .prompt-manager-list { max-height: 300px; overflow-y: auto; margin: 10px 0; display: flex; flex-wrap: wrap; } .prompt-manager-list-item { background-color:#222; margin:2px; border-radius: 5px; cursor: pointer; color: var(--pm-text-color); max-width:120px; padding:1px 7px; } .prompt-manager-list-item:hover { background: var(--pm-hover-color); } `); // 数据结构 let data = { categories: [], // [{id: string, name: string, order: number}] prompts: [], // [{id: string, text: string, alias: string, categoryId: string, favorite: boolean, useCount: number, isTemplate: boolean, lastUsed: string}] lastUsedCategoryId: null, // 记录上次使用的分组ID backups: [], // 自动备份历史 [{date: string, data: Object}] settings: { darkMode: false, // 深色模式 modalPosition: null, // 模态框位置 sortBy: 'time', // 排序方式:time(添加时间), name(名称), usage(使用次数) showFavoriteOnly: false, // 是否只显示收藏的提示词 enableContextMenu: true, // 启用右键菜单 autoBackup: true, // 自动备份 backupInterval: 7, // 备份间隔(天) maxBackups: 5, // 最大备份数量 categorySort: 'custom' // 分类排序方式:custom(自定义), name(名称) } }; // 初始化数据 function initData() { const savedData = GM_getValue('promptManagerData'); if (savedData) { try { data = JSON.parse(savedData); // 兼容旧版本数据结构 if (!data.settings) { data.settings = { darkMode: false, modalPosition: null, sortBy: 'time', showFavoriteOnly: false, enableContextMenu: true, autoBackup: true, backupInterval: 7 }; } if (!data.backups) { data.backups = []; } // 检查是否需要创建备份 checkBackup(); } catch (e) { console.error('数据解析错误', e); // 尝试恢复最近的备份 tryRestore(); } } } // 保存数据 function saveData() { try { GM_setValue('promptManagerData', JSON.stringify(data)); } catch (e) { console.error('保存数据失败', e); alert('保存数据失败,请检查浏览器存储空间或导出备份数据'); } } // 检查是否需要创建备份 function checkBackup() { if (!data.settings.autoBackup) return; const now = new Date(); const lastBackup = data.backups[0]?.date ? new Date(data.backups[0].date) : null; // 如果没有备份或最后一次备份超过指定天数 if (!lastBackup || (now - lastBackup) / (1000 * 60 * 60 * 24) > data.settings.backupInterval) { // 创建备份,不包含之前的备份数据 const backupData = JSON.parse(JSON.stringify(data)); delete backupData.backups; // 添加新备份到开头 data.backups.unshift({ date: now.toISOString(), data: backupData }); // 保留最多5个备份 if (data.backups.length > 5) { data.backups = data.backups.slice(0, 5); } saveData(); } } // 尝试从备份恢复 function tryRestore() { const savedBackups = GM_getValue('promptManagerBackups'); if (savedBackups) { try { const backups = JSON.parse(savedBackups); if (backups.length > 0) { // 使用最新的备份 data = backups[0].data; alert('检测到数据损坏,已自动从最近备份恢复'); return; } } catch (e) { console.error('备份解析错误', e); } } // 如果没有可用备份,重置数据 data = { categories: [], prompts: [], lastUsedCategoryId: null, backups: [], settings: { darkMode: false, modalPosition: null, sortBy: 'time', showFavoriteOnly: false, enableContextMenu: true, autoBackup: true, backupInterval: 7 } }; alert('无法恢复数据,已重置为默认设置'); } // 初始化数据 // = GM_getValue('promptManagerData'); // 显示提示信息 function showToast(message, duration = 3000) { let container = document.querySelector('.toast-container'); if (!container) { container = document.createElement('div'); container.className = 'toast-container'; document.body.appendChild(container); } const toast = document.createElement('div'); toast.className = 'toast'; toast.textContent = message; container.appendChild(toast); setTimeout(() => { toast.remove(); if (container.children.length === 0) { container.remove(); } }, duration); } // 创建浮动菜单 function createFloatingMenu(x, y) { const menu = document.createElement('div'); menu.className = 'prompt-manager-menu'; menu.style.left = x + 'px'; menu.style.top = y + 'px'; const div1=document.createElement('div'); div1.id='div1'; menu.appendChild(div1); const div2=document.createElement('div'); menu.appendChild(div2); // 工具栏 const toolbar = document.createElement('div'); toolbar.className = 'prompt-manager-toolbar'; makeDraggable(menu); const settingsBtn = document.createElement('button'); settingsBtn.innerHTML = '⚙️'; settingsBtn.onclick = showSettings; const addCategoryBtn = document.createElement('button'); addCategoryBtn.innerHTML = '+🗂️'; addCategoryBtn.onclick = () => showAddCategoryDialog(); toolbar.appendChild(settingsBtn); toolbar.appendChild(addCategoryBtn); div2.appendChild(toolbar); // 分类列表 data.categories.forEach(category => { const categoryDiv = document.createElement('div'); categoryDiv.className = 'prompt-manager-category'; categoryDiv.textContent = category.name; categoryDiv.onclick = () => showPromptList(category.id); div2.appendChild(categoryDiv); }); document.body.appendChild(menu); return menu; } // 显示添加分类对话框 function showAddCategoryDialog() { const modal = createModal(); modal.innerHTML = `

新建分类

`; modal.style.left = '40%'; const input = modal.querySelector('input'); const [confirmBtn, cancelBtn] = modal.querySelectorAll('button'); confirmBtn.onclick = () => { if (input.value.trim()) { const newCategory = { id: Date.now().toString(), name: input.value.trim() }; data.categories.push(newCategory); saveData(); closeModal(); // 刷新菜单 const oldMenu = document.querySelector('.prompt-manager-menu'); if (oldMenu) { const rect = oldMenu.getBoundingClientRect(); oldMenu.remove(); createFloatingMenu(rect.left, rect.top); } } }; cancelBtn.onclick = closeModal; } // 显示提示词列表 function showPromptList(categoryId) { try{ document.getElementsByClassName('prompt-manager-modal')[0].remove(); }catch(e){} console.log(document.getElementById('div1').innerHTML) const prompts = data.prompts.filter(p => p.categoryId === categoryId); const category = data.categories.find(c => c.id === categoryId); const modal = createModal(); modal.innerHTML = `

${category.name}

${prompts.map(prompt => `
${prompt.alias || prompt.text}
`).join('')}
`; // 添加CSS样式 const style = document.createElement('style'); style.textContent = ` .prompt-manager-list-item { display: flex; flex-wrap: wrap; flex-direction: row; justify-content: space-between; align-items: center; position: relative; padding-left: 5px; } .prompt-text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; user-select: none; } .prompt-favorite { background: none; border: none; cursor: pointer; font-size: 16px; color: gold; } .prompt-checkbox { position: absolute; left: 5px; width: 16px; height: 16px; cursor: pointer; opacity: 0; } .prompt-checkbox-custom { position: absolute; left: 5px; width: 16px; height: 16px; border: 2px solid var(--pm-text-color); border-radius: 3px; pointer-events: none; } .prompt-checkbox:checked + .prompt-checkbox-custom::after { content: '✓'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: var(--pm-primary-color); } .prompt-manager-list-item.selected { background-color: rgba(74, 144, 226, 0.1); } .batch-actions { display: none; margin-bottom: 10px; gap: 8px; flex-wrap: wrap; } .batch-actions.visible { display: flex; } /* 操作提示和反馈 */ .toast-container { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 10001; pointer-events: none; } .toast { background: rgba(0, 0, 0, 0.8); color: white; padding: 10px 20px; border-radius: 4px; margin-top: 10px; animation: fadeInOut 3s ease-in-out; } @keyframes fadeInOut { 0% { opacity: 0; transform: translateY(20px); } 10% { opacity: 1; transform: translateY(0); } 90% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-20px); } } /* 触摸设备优化 */ @media (hover: none) { .prompt-checkbox, .prompt-checkbox-custom { width: 22px; height: 22px; } .prompt-manager-list-item { padding-left: 35px; } .batch-actions button { padding: 12px 20px; } } .prompt-actions { opacity: 0.3; transition: opacity 0.2s; } .prompt-manager-list-item:hover .prompt-actions { opacity: 1; } .prompt-delete, .prompt-edit { background: none; border: none; cursor: pointer; font-size: 10px; } .prompt-manager-list-item.active { background-color: rgba(74, 144, 226, 0.1); } .empty-list-message { padding: 20px; text-align: center; color: #999; } .prompt-toolbar { display: flex; gap: 8px; } .toolbar-btn { background: none; border: none; cursor: pointer; padding: 4px 8px; font-size: 16px; color: var(--pm-text-color); border-radius: 4px; } .toolbar-btn:hover { background: var(--pm-hover-color); } .search-bar { position: relative; } @media (max-width: 768px) { .prompt-manager-modal { left: 0 !important; right: 0 !important; width: auto !important; margin: 10px; max-width: none !important; } .prompt-manager-menu { left: 0 !important; right: 0 !important; width: auto !important; margin: 10px; } .prompt-toolbar { gap: 4px; } .toolbar-btn { padding: 8px; } } `; document.head.appendChild(style); // 搜索和过滤功能 const sortBtn = modal.querySelector('#sort-btn'); const favoriteFilterBtn = modal.querySelector('#favorite-filter-btn'); // 排序函数 const sortPrompts = (items) => { return Array.from(items).sort((a, b) => { const aPrompt = data.prompts.find(p => p.id === a.dataset.id); const bPrompt = data.prompts.find(p => p.id === b.dataset.id); if (!aPrompt || !bPrompt) return 0; switch (data.settings.sortBy) { case 'name': return (aPrompt.alias || aPrompt.text).localeCompare(bPrompt.alias || bPrompt.text); case 'usage': return (bPrompt.useCount || 0) - (aPrompt.useCount || 0); default: // 'time' return bPrompt.id.localeCompare(aPrompt.id); } }); }; // 搜索和过滤函数 // 排序按钮点击事件 sortBtn.addEventListener('click', () => { switch (data.settings.sortBy) { case 'time': data.settings.sortBy = 'name'; sortBtn.textContent = '🔤'; break; case 'name': data.settings.sortBy = 'usage'; sortBtn.textContent = '📊'; break; default: data.settings.sortBy = 'time'; sortBtn.textContent = '⏱️'; } saveData(); }); // 收藏过滤按钮点击事件 favoriteFilterBtn.addEventListener('click', () => { data.settings.showFavoriteOnly = !data.settings.showFavoriteOnly; favoriteFilterBtn.textContent = data.settings.showFavoriteOnly ? '★' : '☆'; favoriteFilterBtn.title = data.settings.showFavoriteOnly ? '显示全部' : '只看收藏'; saveData(); }); // 提示词点击事件 const items = modal.querySelectorAll('.prompt-manager-list-item'); items.forEach(item => { // 收藏按钮点击事件 const favoriteBtn = item.querySelector('.prompt-favorite'); favoriteBtn.onclick = (e) => { e.stopPropagation(); const promptId = item.dataset.id; const promptIndex = data.prompts.findIndex(p => p.id === promptId); if (promptIndex !== -1) { // 切换收藏状态 data.prompts[promptIndex].favorite = !data.prompts[promptIndex].favorite; favoriteBtn.textContent = data.prompts[promptIndex].favorite ? '★' : '☆'; favoriteBtn.title = data.prompts[promptIndex].favorite ? '取消收藏' : '收藏'; saveData(); } }; // 提示词文本点击事件 const textSpan = item.querySelector('.prompt-text'); textSpan.onclick = (e) => { e.stopPropagation(); // 阻止事件冒泡 const promptId = item.dataset.id; const prompt = data.prompts.find(p => p.id === promptId); if (!prompt) { alert('提示词数据已损坏,请尝试刷新页面'); return; } let text = prompt.text; // 如果是模板,处理变量替换 if (prompt.isTemplate) { // 提取所有变量 const variables = []; const regex = /\{\{([^}]+)\}\}/g; let match; while ((match = regex.exec(text)) !== null) { if (!variables.includes(match[1])) { variables.push(match[1]); } } // 如果有变量,提示用户输入 if (variables.length > 0) { // 收集变量值 const values = {}; for (const variable of variables) { const value = prompt(`请输入"${variable}"的值:`); if (value === null) { // 用户取消了输入 return; } values[variable] = value; } // 替换所有变量 for (const [variable, value] of Object.entries(values)) { const regex = new RegExp(`\\{\\{${variable}\\}\\}`, 'g'); text = text.replace(regex, value); } } } // 检查文本结尾是否是逗号,如果不是则添加逗号 if (!text.endsWith(',')) { text += ','; } // 记录最近聚焦的输入元素 let targetInput = window.lastFocusedInput; // 如果没有记录或记录的元素不再有效,则尝试查找页面上可见的输入框 if (!targetInput || !document.body.contains(targetInput)) { // 查找页面上所有的输入框和文本框 const inputs = document.querySelectorAll('input[type="text"], textarea'); targetInput = Array.from(inputs).find(input => { // 检查元素是否可见且可编辑 const style = window.getComputedStyle(input); const rect = input.getBoundingClientRect(); return style.display !== 'none' && !input.readOnly && !input.disabled && rect.width > 0 && rect.height > 0; }); } if (targetInput) { // 将文本插入到输入框 targetInput.focus(); const start = targetInput.selectionStart || 0; const end = targetInput.selectionEnd || 0; targetInput.value = targetInput.value.substring(0, start) + text + targetInput.value.substring(end); targetInput.setSelectionRange(start + text.length, start + text.length); // 触发输入事件,确保动态网页能检测到内容变化 const inputEvent = new Event('input', { bubbles: true }); targetInput.dispatchEvent(inputEvent); // 更新使用次数 const promptId = item.dataset.id; const promptIndex = data.prompts.findIndex(p => p.id === promptId); if (promptIndex !== -1) { data.prompts[promptIndex].useCount = (data.prompts[promptIndex].useCount || 0) + 1; saveData(); } } //closeModal(); }; // 删除按钮点击事件 const deleteBtn = item.querySelector('.prompt-delete'); deleteBtn.onclick = (e) => { e.stopPropagation(); const promptId = item.dataset.id; if (confirm('确定要删除这个提示词吗?')) { try { data.prompts = data.prompts.filter(p => p.id !== promptId); saveData(); item.remove(); // 检查列表是否为空 const listItems = modal.querySelectorAll('.prompt-manager-list-item:not([style*="display: none"])'); const listContainer = modal.querySelector('.prompt-manager-list'); if (listItems.length === 0) { const message = data.settings.showFavoriteOnly ? '没有收藏的提示词' : '没有提示词'; listContainer.innerHTML = `
${message}
`; } showToast('提示词已删除'); } catch (error) { console.error('删除提示词失败', error); showToast('删除失败,请重试'); } } }; }); // 工具栏按钮 const shareCategoryBtn = modal.querySelector('#share-category'); const [editCategoryBtn,edititem, closeBtn] = modal.querySelectorAll('.prompt-manager-toolbar button'); // 分享分类按钮点击事件 shareCategoryBtn.onclick = () => { const category = data.categories.find(c => c.id === categoryId); if (!category) return; const prompts = data.prompts.filter(p => p.categoryId === categoryId); if (prompts.length === 0) { showToast('当前分类没有提示词可分享'); return; } const shareModal = createModal(); shareModal.innerHTML = `

分享分类:${category.name}

`; const formatSelect = shareModal.querySelector('#share-format'); const previewArea = shareModal.querySelector('textarea'); const copyBtn = shareModal.querySelector('#copy-share'); const downloadBtn = shareModal.querySelector('#download-share'); const closeShareBtn = shareModal.querySelector('.prompt-manager-button.secondary'); // 生成分享内容 const generateContent = (format) => { switch (format) { case 'text': return prompts.map(p => { const text = p.text.replace(/\n/g, ' '); return p.alias ? `${text}|${p.alias}` : text; }).join('\n'); case 'markdown': return `# ${category.name}\n\n` + prompts.map(p => { const text = p.text.replace(/\n/g, ' '); return `- ${p.alias ? `**${p.alias}**: ` : ''}${text}`; }).join('\n'); case 'json': return JSON.stringify({ category: category.name, prompts: prompts.map(p => ({ text: p.text, alias: p.alias || null })) }, null, 2); } }; // 更新预览 const updatePreview = () => { previewArea.value = generateContent(formatSelect.value); }; formatSelect.onchange = updatePreview; updatePreview(); // 复制内容 copyBtn.onclick = async () => { try { await navigator.clipboard.writeText(previewArea.value); showToast('内容已复制到剪贴板'); } catch (error) { console.error('复制失败', error); // 降级方案 previewArea.select(); document.execCommand('copy'); showToast('内容已复制到剪贴板'); } }; // 下载文件 downloadBtn.onclick = () => { const format = formatSelect.value; const content = generateContent(format); const blob = new Blob([content], { type: format === 'json' ? 'application/json' : 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `prompts-${category.name}.${format === 'markdown' ? 'md' : format}`; a.click(); URL.revokeObjectURL(url); showToast('文件已开始下载'); }; closeShareBtn.onclick = () => closeModal(shareModal); }; edititem.onclick=()=>{ showx() } showx() function showx(){ const categories = document.querySelectorAll('.prompt-actions .prompt-delete') for(let i=0;i { showEditCategoryDialog(categoryId); }; closeBtn.onclick = closeModal; } // 显示设置界面 function showSettings() { const modal = createModal(); modal.innerHTML = `

设置

导入导出

每行一个提示词,如果有简称以"|"分隔。每次请只添加一个分组的,因为添加后所有的都会被分到同一个分组

其他操作

1、点击"+🗂️"
2、在页面中划词可以添加提示词
3、点击提示词可以填入到编辑框里
`; //modal.style.transform = 'none'; //modal.style.top = '20px'; const darkModeToggle = modal.querySelector('#dark-mode-toggle'); const exportJsonBtn = modal.querySelector('#export-json'); const exportTxtBtn = modal.querySelector('#export-txt'); const [, importBtn, batchImportBtn, helpBtn, clearBtn, closeBtn] = modal.querySelectorAll('.prompt-manager-button'); const fileInput = modal.querySelector('#import-file'); const batchFileInput = modal.querySelector('#batch-import-file'); // 深色模式切换 /*darkModeToggle.onchange = () => { data.settings.darkMode = darkModeToggle.checked; saveData(); applyDarkMode(); };*/ // 导出仅包含prompts数组的JSON数据 exportJsonBtn.onclick = () => { const exportData = { categories: data.categories, prompts: data.prompts }; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); //const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'prompt-manager-data.json'; a.click(); URL.revokeObjectURL(url); }; importBtn.onclick = () => fileInput.click(); // 批量导入按钮 batchImportBtn.onclick = () => showBatchImportDialog()//batchFileInput.click(); // 批量导入文件处理 batchFileInput.onchange = async () => { const file = batchFileInput.files[0]; if (file) { try { const text = await file.text(); showBatchImportDialog(text); } catch (e) { alert('文件读取失败'); } } }; fileInput.onchange = async () => { const file = fileInput.files[0]; if (file) { try { const text = await file.text(); const importedData = JSON.parse(text); if (importedData.categories && importedData.prompts) { // 保留lastUsedCategoryId或使用导入数据中的值 const currentLastUsedCategory = data.lastUsedCategoryId; data = importedData; // 如果导入的数据没有lastUsedCategoryId,保留当前的值 if (!data.lastUsedCategoryId && currentLastUsedCategory) { data.lastUsedCategoryId = currentLastUsedCategory; } saveData(); alert('数据导入成功!'); closeModal(); } } catch (e) { alert('导入失败:无效的数据格式'); } } }; clearBtn.onclick = () => { if (confirm('确定要清空所有数据吗?此操作不可恢复!')) { data = { categories: [], prompts: [], lastUsedCategoryId: null }; saveData(); closeModal(); } }; closeBtn.onclick = closeModal; } // 显示保存提示词对话框 function showSavePromptDialog(text) { const modal = createModal2(); modal.innerHTML = `

保存提示词

❓ 什么是模板?
`; // 防止点击事件冒泡 modal.addEventListener('click', (e) => { e.stopPropagation(); }); // 添加拖拽功能 makeDraggable(modal); const aliasInput = modal.querySelector('input'); const categorySelect = modal.querySelector('select'); const [saveBtn, cancelBtn] = modal.querySelectorAll('button'); saveBtn.onclick = () => { const categoryId = categorySelect.value; if (!categoryId) { alert('请选择分类!'); return; } const textArea = modal.querySelector('textarea'); const isTemplateCheckbox = modal.querySelector('#is-template') || { checked: false }; const newPrompt = { id: Date.now().toString(), text: textArea.value.trim(), alias: aliasInput.value.trim(), categoryId: categoryId, favorite: false, useCount: 0, isTemplate: isTemplateCheckbox.checked }; // 保存提示词的同时记录最后使用的分组ID data.lastUsedCategoryId = categoryId; data.prompts.push(newPrompt); saveData(); closeModal(); }; // 如果有上次使用的分组,自动选中 if (data.lastUsedCategoryId) { const option = categorySelect.querySelector(`option[value="${data.lastUsedCategoryId}"]`); if (option) { categorySelect.value = data.lastUsedCategoryId; } else { // 如果找不到对应的分类(可能已被删除),清除记录 data.lastUsedCategoryId = null; saveData(); } } cancelBtn.onclick = closeModal; } // 显示批量导入对话框 function showBatchImportDialog(text) { const modal = createModal(); modal.innerHTML = `

批量导入提示词

每行一个提示词,格式:提示词文本|别名(可选)。导入后需要刷新

`; const textArea = modal.querySelector('textarea'); const categorySelect = modal.querySelector('select'); const [importBtn, cancelBtn] = modal.querySelectorAll('button'); // 如果有上次使用的分组,自动选中 if (data.lastUsedCategoryId) { categorySelect.value = data.lastUsedCategoryId; } importBtn.onclick = () => { const categoryId = categorySelect.value; if (!categoryId) { alert('请选择分类!'); return; } const lines = textArea.value.split('\n').filter(line => line.trim()); if (lines.length === 0) { alert('没有找到有效的提示词'); return; } let importCount = 0; lines.forEach(line => { const parts = line.split('|'); const text = parts[0].trim(); const alias = parts.length > 1 ? parts[1].trim() : ''; if (text) { const newPrompt = { id: Date.now().toString() + importCount, text: text, alias: alias, categoryId: categoryId, favorite: false }; data.prompts.push(newPrompt); importCount++; } }); if (importCount > 0) { data.lastUsedCategoryId = categoryId; saveData(); alert(`成功导入 ${importCount} 个提示词`); closeModal(); } else { alert('没有找到有效的提示词'); } }; cancelBtn.onclick = closeModal; } // 应用深色模式 function applyDarkMode() { if (data.settings?.darkMode) { document.body.classList.add('prompt-manager-dark-mode'); } else { document.body.classList.remove('prompt-manager-dark-mode'); } } // 创建模态框 function createModal() { const modal = document.createElement('div'); modal.className = 'prompt-manager-modal'; // 如果有保存的位置,使用保存的位置 /* if (data.settings?.modalPosition) { modal.style.left = data.settings.modalPosition.left + 'px'; modal.style.top = data.settings.modalPosition.top + 'px'; modal.style.transform = 'none'; }*/ // 添加拖拽功能 makeDraggable(modal); const menu = document.querySelector('#div1').appendChild(modal); //document.body.appendChild(modal); return modal; } function createModal2() { const modal = document.createElement('div'); modal.className = 'prompt-manager-modal2'; // 如果有保存的位置,使用保存的位置 if (data.settings?.modalPosition) { modal.style.left = data.settings.modalPosition.left + 'px'; modal.style.top = data.settings.modalPosition.top + 'px'; modal.style.transform = 'none'; } //const menu = document.querySelector('#div1').appendChild(modal); document.body.appendChild(modal); return modal; } // 使元素可拖拽 function makeDraggable(element) { let isDragging = false; let offsetX, offsetY; // 创建拖拽手柄 const dragHandle = document.createElement('div'); dragHandle.style.cssText = ` position: absolute; top: 0; left: 0; right: 0; height: 30px; cursor: move; background-color: transparent; `; element.appendChild(dragHandle); console.log(dragHandle); // 鼠标按下事件 dragHandle.addEventListener('mousedown', (e) => { isDragging = true; // 获取鼠标在元素内的相对位置 const rect = element.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; // 阻止默认行为和冒泡 e.preventDefault(); e.stopPropagation(); }); // 鼠标移动事件 document.addEventListener('mousemove', (e) => { if (!isDragging) return; // 计算新位置 const x = e.clientX - offsetX; const y = e.clientY - offsetY; // 应用新位置 element.style.left = x + 'px'; element.style.top = y + 'px'; element.style.transform = 'none'; // 保存位置到设置 data.settings.modalPosition = { left: x, top: y }; }); // 鼠标释放事件 document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; saveData(); } }); } // 关闭模态框 function closeModal() { const modal = document.querySelector('.prompt-manager-modal'); const modal2 = document.querySelector('.prompt-manager-modal2'); if (modal) modal.remove(); if (modal2) modal2.remove(); } function closeModal2() { const modal = document.querySelector('.prompt-manager-modal2'); if (modal) modal.remove(); } // 点击页面任意位置关闭模态框(使用捕获阶段) document.addEventListener('click', (e) => { const modal = document.querySelector('.prompt-manager-modal2'); if (modal && !e.target.closest('.prompt-manager-modal2')) { closeModal2(); } }, true); // 显示编辑提示词对话框 function showEditPromptDialog(promptId, text, alias, categoryId) { const modal = createModal(); modal.innerHTML = `

编辑提示词

`; // 防止点击事件冒泡 modal.addEventListener('click', (e) => { e.stopPropagation(); }); const textArea = modal.querySelector('textarea'); const aliasInput = modal.querySelector('input[type="text"]'); const isTemplateCheckbox = modal.querySelector('#is-template') || { checked: false }; const templateHelp = modal.querySelector('.template-help'); const categorySelect = modal.querySelector('select'); const [saveBtn, cancelBtn] = modal.querySelectorAll('button'); // 模板帮助提示 templateHelp.onclick = () => { alert('模板支持使用变量占位符,格式为 {{变量名}}。\n\n使用时会提示输入变量值,自动替换占位符。\n\n例如:\n"你好,我是{{名字}},我来自{{地点}}。"\n\n使用时会提示输入"名字"和"地点"的值。'); }; saveBtn.onclick = () => { const newCategoryId = categorySelect.value; if (!newCategoryId) { alert('请选择分类!'); return; } const newText = textArea.value; if (!newText.trim()) { alert('提示词内容不能为空!'); return; } // 更新提示词 const promptIndex = data.prompts.findIndex(p => p.id === promptId); if (promptIndex !== -1) { data.prompts[promptIndex] = { ...data.prompts[promptIndex], text: newText, alias: aliasInput.value.trim(), categoryId: newCategoryId }; saveData(); closeModal(); // 如果分类改变了,需要刷新提示词列表 if (newCategoryId !== categoryId) { showPromptList(newCategoryId); } else { showPromptList(categoryId); } } }; cancelBtn.onclick = closeModal; } // 显示编辑分类对话框 function showEditCategoryDialog(categoryId) { const category = data.categories.find(c => c.id === categoryId); if (!category) return; const modal = createModal(); modal.innerHTML = `

编辑分类

`; const nameInput = modal.querySelector('input'); const [saveBtn, deleteBtn, cancelBtn] = modal.querySelectorAll('button'); saveBtn.onclick = () => { const newName = nameInput.value.trim(); if (newName) { category.name = newName; saveData(); closeModal(); // 刷新分类列表 showPromptList(categoryId); } else { alert('分类名称不能为空'); } }; deleteBtn.onclick = () => { if (confirm(`确定要删除分类"${category.name}"吗?该分类下的所有提示词也将被删除!`)) { // 删除该分类下的所有提示词 data.prompts = data.prompts.filter(p => p.categoryId !== categoryId); // 删除分类 data.categories = data.categories.filter(c => c.id !== categoryId); // 如果删除的是上次使用的分类,清除记录 if (data.lastUsedCategoryId === categoryId) { data.lastUsedCategoryId = null; } saveData(); closeModal(); // 刷新菜单 const menu = document.querySelector('.prompt-manager-menu'); if (menu) { const rect = menu.getBoundingClientRect(); menu.remove(); createFloatingMenu(rect.left, rect.top); } } }; cancelBtn.onclick = closeModal; } // 添加键盘快捷键支持 function setupKeyboardShortcuts() { document.addEventListener('keydown', (e) => { // ESC键关闭所有对话框 if (e.key === 'Escape') { closeModal(); const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); } // Ctrl+Shift+P 打开最近使用的分类 if (e.ctrlKey && e.shiftKey && e.key === 'P') { e.preventDefault(); if (data.lastUsedCategoryId) { const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); showPromptList(data.lastUsedCategoryId); } } }); } // 初始化 initData(); // 记录最近聚焦的输入元素 window.lastFocusedInput = null; document.addEventListener('focusin', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { window.lastFocusedInput = e.target; } }); // 监听文本框点击 document.addEventListener('click', (e) => { const target = e.target; if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') { const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); const rect = target.getBoundingClientRect(); createFloatingMenu(rect.left - 170, rect.top); } else if (!e.target.closest('.prompt-manager-menu') && !e.target.closest('.prompt-manager-modal')) { const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); } }); // 监听选中文本 document.addEventListener('mouseup', (e) => { // 检查是否在模态框内,如果是则不处理 if (e.target.closest('.prompt-manager-modal' )|| e.target.closest('.prompt-manager-menu')|| e.target.closest('.prompt-manager-modal2')) { return; } const selection = window.getSelection(); const text = selection.toString().trim(); // 如果有选中的文本,则显示保存对话框 if (text) { // 延迟显示保存对话框,避免与其他点击事件冲突 setTimeout(() => { const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); showSavePromptDialog(text); }, 100); } }); })();