Greasy Fork is available in English.
Easily create and edit AI prompts.
// ==UserScript== // @name AI Prompt Manager // @namespace https://github.com/insign/ai-prompt-manager // @version 2025.02.18.1758 // @description Easily create and edit AI prompts. // DeepSeek Chat only for now. // @author Hélio <[email protected]> // @license MIT // @match https://chat.deepseek.com/* // @grant GM.setValue // @grant GM.getValue // @grant GM.addStyle // ==/UserScript== (function() { 'use strict'; const MANAGER_ID = 'ds-prompt-manager'; const BUTTON_ID = 'ds-prompt-button'; const STORAGE_KEY = 'ds_prompts_v2'; const CSS_THEME = '#4D6BFE'; let prompts = []; async function initialize() { try { const storedPrompts = await GM.getValue(STORAGE_KEY, []); prompts = Array.isArray(storedPrompts) ? storedPrompts : []; createManagerButton(); createPromptManager(); setupEventListeners(); refreshPromptList(); } catch (error) { console.error('Initialization failed:', error); } } function createManagerButton() { if (document.getElementById(BUTTON_ID)) return; const btn = document.createElement('div'); btn.id = BUTTON_ID; btn.innerHTML = '📋'; Object.assign(btn.style, { position: 'fixed', bottom: '90px', right: '20px', width: '45px', height: '45px', background: CSS_THEME, color: 'white', borderRadius: '50%', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '2147483647', fontSize: '24px', boxShadow: '0 2px 8px rgba(0,0,0,0.2)' }); document.body.appendChild(btn); } function createPromptManager() { if (document.getElementById(MANAGER_ID)) return; const mgr = document.createElement('div'); mgr.id = MANAGER_ID; mgr.innerHTML = ` <div class="header">Saved Prompts</div> <div class="prompt-list"></div> <button class="add-prompt">+ New Prompt</button> `; Object.assign(mgr.style, { position: 'fixed', bottom: '145px', right: '20px', background: 'white', borderRadius: '12px', boxShadow: '0 8px 24px rgba(0,0,0,0.15)', padding: '16px', width: '300px', display: 'none', zIndex: '2147483647' }); document.body.appendChild(mgr); } async function refreshPromptList() { const list = document.querySelector(`#${MANAGER_ID} .prompt-list`); if (!list) return; list.innerHTML = ''; prompts.forEach((prompt, index) => { const item = document.createElement('div'); item.className = 'prompt-item'; item.innerHTML = ` <span class="prompt-title">${prompt.title}</span> <div class="prompt-actions"> <button class="edit-btn">✏️</button> <button class="delete-btn">🗑️</button> </div> `; item.querySelector('.delete-btn').addEventListener('click', (e) => { e.stopPropagation(); deletePrompt(index); }); item.querySelector('.edit-btn').addEventListener('click', (e) => { e.stopPropagation(); editPrompt(index); }); item.addEventListener('click', () => insertPrompt(prompt.content)); list.appendChild(item); }); } async function deletePrompt(index) { prompts.splice(index, 1); await GM.setValue(STORAGE_KEY, prompts); refreshPromptList(); } async function editPrompt(index) { const prompt = prompts[index]; const newTitle = prompt('Edit title:', prompt.title); if (newTitle === null) return; const newContent = prompt('Edit content:', prompt.content); if (newContent === null) return; prompts[index] = { title: newTitle, content: newContent }; await GM.setValue(STORAGE_KEY, prompts); refreshPromptList(); } async function insertPrompt(content) { const fakeInput = document.querySelector('.b13855df'); const textarea = document.getElementById('chat-input'); if (!fakeInput || !textarea) return; try { // Update React state const reactPropsKey = Object.keys(textarea).find(k => k.startsWith('__reactProps')); if (reactPropsKey) { const reactProps = textarea[reactPropsKey]; if (reactProps?.onChange) { textarea.value = content + '\n\n' + textarea.value; reactProps.onChange({ target: textarea, currentTarget: textarea, type: 'input' }); } } // Update visible editor const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(fakeInput); range.collapse(false); selection.removeAllRanges(); selection.addRange(range); document.execCommand('insertText', false, content + '\n\n'); } catch (error) { console.error('Insertion failed:', error); } } function setupEventListeners() { // Toggle manager document.getElementById(BUTTON_ID).addEventListener('click', function(e) { e.stopImmediatePropagation(); const mgr = document.getElementById(MANAGER_ID); mgr.style.display = mgr.style.display === 'none' ? 'block' : 'none'; }, true); // Close manager document.addEventListener('click', function(e) { const mgr = document.getElementById(MANAGER_ID); if (mgr && !mgr.contains(e.target) && !e.target.closest(`#${BUTTON_ID}`)) { mgr.style.display = 'none'; } }, true); // Add new prompt document.querySelector(`#${MANAGER_ID} .add-prompt`).addEventListener('click', async function(e) { e.stopImmediatePropagation(); const title = prompt('Enter prompt title:'); if (!title) return; const content = prompt('Enter prompt content:'); if (!content) return; prompts.push({ title, content }); await GM.setValue(STORAGE_KEY, prompts); refreshPromptList(); }, true); } GM.addStyle(` #${MANAGER_ID} { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fff; border: 1px solid ${CSS_THEME}20; color: #1a1a1a; } #${MANAGER_ID} .prompt-item { display: flex; justify-content: space-between; align-items: center; padding: 12px; margin: 8px 0; border-radius: 8px; cursor: pointer; transition: background 0.2s; } #${MANAGER_ID} .prompt-item:hover { background: ${CSS_THEME}08; } #${MANAGER_ID} .header { font-weight: 600; color: ${CSS_THEME}; margin-bottom: 12px; padding-bottom: 8px; border-bottom: 2px solid ${CSS_THEME}20; } #${MANAGER_ID} .add-prompt { width: 100%; margin-top: 16px; padding: 12px; background: ${CSS_THEME}; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 500; transition: opacity 0.2s; } #${MANAGER_ID} .add-prompt:hover { opacity: 0.9; } .prompt-actions button { background: none; border: none; padding: 4px; cursor: pointer; margin-left: 8px; opacity: 0.7; transition: opacity 0.2s; } .prompt-actions button:hover { opacity: 1; } `); // Initialize after slight delay to ensure DOM is ready setTimeout(initialize, 1000); })();