My Prompt

Save, edit, delete, import, and export your custom prompts directly in ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini, and LMArena

// ==UserScript==
// @name               My Prompt
// @name:en            My Prompt
// @name:pt-BR         Meu Prompt
// @name:es            Mi Prompt
// @name:zh-CN         我的提示
// @namespace          https://github.com/0H4S
// @version            1.1
// @description        Save, edit, delete, import, and export your custom prompts directly in ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini, and LMArena
// @description:en     Save, edit, delete, import, and export your custom prompts directly in ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini, and LMArena
// @description:pt-BR  Salve, edite, exclua, importe e exporte seus prompts personalizados diretamente no ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini e LMArena
// @description:es     Guarda, edita, elimina, importa y exporta tus prompts personalizados directamente en ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini y LMArena
// @description:zh-CN  直接在 ChatGPT、DeepSeek、Google AI Studio、Qwen、Z.ai、Gemini 和 LMArena 中保存、编辑、删除、导入和导出您的自定义提示。
// @author             OHAS
// @homepage           https://github.com/0H4S
// @icon               https://cdn-icons-png.flaticon.com/512/4997/4997543.png
// @license            Copyright (c) 2025 OHAS. All Rights Reserved.
// @match              https://chatgpt.com/*
// @match              https://chat.deepseek.com/*
// @match              https://aistudio.google.com/*
// @match              https://chat.qwen.ai/*
// @match              https://chat.z.ai/*
// @match              https://gemini.google.com/*
// @match              https://lmarena.ai/*
// @require            https://update.greasyfork.org/scripts/549920/1662869/Script%20Notifier.js
// @connect            gist.githubusercontent.com
// @grant              GM_getValue
// @grant              GM_setValue
// @grant              GM_registerMenuCommand
// @grant              GM_xmlhttpRequest
// @run-at             document-end
// ==/UserScript==
(function() {
    'use strict';
	/* globals ScriptNotifier */
    if (window.top !== window.self) {
        return;
    }
    const SCRIPT_CONFIG = {
        notificationsUrl: 'https://gist.githubusercontent.com/0H4S/40b2a2feb2ba18d0bf63a1943ba5cec3/raw/my_prompt_notifications.json',
        scriptVersion: '1.1',
        currentLang: navigator.language || 'en'
    };
  const notifier = new ScriptNotifier(SCRIPT_CONFIG);
  notifier.run();
  const PROMPT_STORAGE_KEY = 'Prompts';
  const LANG_STORAGE_KEY = 'Lang';
  const translations = {
    'en': {
      'langName': 'English',
      'prompt': 'Prompt',
      'prompts': 'Prompts',
      'newPrompt': 'New Prompt',
      'editPrompt': 'Edit Prompt',
      'title': 'Title',
      'text': 'Prompt',
      'save': 'Save',
      'close': 'Close',
      'edit': 'Edit',
      'delete': 'Delete',
      'noSavedPrompts': 'No saved prompts.',
      'addPrompt': 'Add prompt',
      'import': 'Import',
      'export': 'Export',
      'confirmDelete': 'Delete prompt "{title}"?',
      'noPromptsToExport': 'No prompts to export.',
      'promptsImported': '{count} prompts imported successfully!',
      'errorImporting': 'Error importing file: {error}',
      'requiredFields': 'Title and prompt are required.',
      'editorNotFound': 'Could not find the text area for {platform}.',
      'languageSettings': '🌐 Language',
      'fileName': 'My Prompt.json'
    },
    'es': {
      'langName': 'Español',
      'prompt': 'Prompt',
      'prompts': 'Prompts',
      'newPrompt': 'Nuevo Prompt',
      'editPrompt': 'Editar Prompt',
      'title': 'Título',
      'text': 'Prompt',
      'save': 'Guardar',
      'close': 'Cerrar',
      'edit': 'Editar',
      'delete': 'Eliminar',
      'noSavedPrompts': 'No hay prompts guardados.',
      'addPrompt': 'Añadir prompt',
      'import': 'Importar',
      'export': 'Exportar',
      'confirmDelete': '¿Eliminar prompt "{title}"?',
      'noPromptsToExport': 'No hay prompts para exportar.',
      'promptsImported': '¡{count} prompts importados con éxito!',
      'errorImporting': 'Error al importar el archivo: {error}',
      'requiredFields': 'El título y el prompt son obligatorios.',
      'editorNotFound': 'No se pudo encontrar el área de texto para {platform}.',
      'languageSettings': '🌐 Idioma',
      'fileName': 'Mi Prompt.json'
    },
    'pt-BR': {
      'langName': 'Português (BR)',
      'prompt': 'Prompt',
      'prompts': 'Prompts',
      'newPrompt': 'Novo Prompt',
      'editPrompt': 'Editar Prompt',
      'title': 'Título',
      'text': 'Prompt',
      'save': 'Salvar',
      'close': 'Fechar',
      'edit': 'Editar',
      'delete': 'Excluir',
      'noSavedPrompts': 'Nenhum prompt salvo.',
      'addPrompt': 'Adicionar prompt',
      'import': 'Importar',
      'export': 'Exportar',
      'confirmDelete': 'Excluir prompt "{title}"?',
      'noPromptsToExport': 'Não há prompts para exportar.',
      'promptsImported': '{count} prompts importados com sucesso!',
      'errorImporting': 'Erro ao importar o arquivo: {error}',
      'requiredFields': 'Título e prompt são obrigatórios.',
      'editorNotFound': 'Não foi possível encontrar a área de texto para {platform}.',
      'languageSettings': '🌐 Idioma',
      'fileName': 'Meu Prompt.json'
    },
    'zh-CN': {
      'langName': '简体中文',
      'prompt': '提示',
      'prompts': '提示',
      'newPrompt': '新建提示',
      'editPrompt': '编辑提示',
      'title': '标题',
      'text': '提示内容',
      'save': '保存',
      'close': '关闭',
      'edit': '编辑',
      'delete': '删除',
      'noSavedPrompts': '没有已保存的提示。',
      'addPrompt': '添加提示',
      'import': '导入',
      'export': '导出',
      'confirmDelete': '确定要删除提示 "{title}" 吗?',
      'noPromptsToExport': '沒有可導出的提示。',
      'promptsImported': '成功导入 {count} 个提示!',
      'errorImporting': '导入文件时出错: {error}',
      'requiredFields': '标题和提示内容为必填项。',
      'editorNotFound': '未能找到 {platform} 的文本输入区域。',
      'languageSettings': '🌐 语言',
      'fileName': '我的提示.json'
    }
  };
  let currentLang = 'en';
  function getTranslation(key, replacements = {}) {
    let text = translations[currentLang]?.[key] || translations.en [key];
    for (const placeholder in replacements) {
      text = text.replace(`{${placeholder}}`, replacements[placeholder]);
    }
    return text;
  }
  async function determineLanguage() {
    let savedLang = await GM_getValue(LANG_STORAGE_KEY);
    if (savedLang && translations[savedLang]) {
      currentLang = savedLang;
      return;
    }
    let browserLang = (navigator.language || navigator.userLanguage).toLowerCase();
    if (browserLang.startsWith('pt')) currentLang = 'pt-BR';
    else if (browserLang.startsWith('es')) currentLang = 'es';
    else if (browserLang.startsWith('zh')) currentLang = 'zh-CN';
    else currentLang = 'en';
  }
  let isInitialized = false;
  let isInitializing = false;
  let currentButton = null;
  let currentMenu = null;
  let currentModal = null;
  let languageModal = null;
  let currentPlatform = null;
  let pageObserver = null;
  const scriptPolicy = window.trustedTypes
    ? window.trustedTypes.createPolicy('MyPromptPolicy', { createHTML: (input) => input })
    : null;
  function setSafeInnerHTML(element, html) {
    if (!element) return;
    if (scriptPolicy) {
      element.innerHTML = scriptPolicy.createHTML(html);
    } else {
      element.innerHTML = html;
    }
  }
  function detectPlatform() {
    const hostname = window.location.hostname;
    if (hostname.includes('chatgpt.com')) return 'chatgpt';
    if (hostname.includes('deepseek.com')) return 'deepseek';
    if (hostname.includes('aistudio.google.com')) return 'googlestudio';
    if (hostname.includes('chat.qwen.ai')) return 'qwen';
    if (hostname.includes('chat.z.ai')) return 'zai';
    if (hostname.includes('gemini.google.com')) return 'gemini';
    if (hostname.includes('lmarena.ai')) return 'lmarena';
    return null;
  }
  function waitFor(selector, timeout = 8000) {
    return new Promise((resolve, reject) => {
      const el = document.querySelector(selector);
      if (el) { resolve(el); return; }
      const timer = setTimeout(() => {
        obs.disconnect();
        reject(`Timeout esperando por ${selector}`);
      }, timeout);
      const obs = new MutationObserver(() => {
        const target = document.querySelector(selector);
        if (target) {
          clearTimeout(timer);
          obs.disconnect();
          resolve(target);
        }
      });
      if (document.body) {
        obs.observe(document.body, { childList: true, subtree: true });
      } else {
        document.addEventListener('DOMContentLoaded', () => obs.observe(document.body, { childList: true, subtree: true }));
      }
    });
  }
  const debounce = (func, wait) => {
    let timeout;
    return (...args) => {
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(this, args), wait);
    };
  };
  async function getAll() { return (await GM_getValue(PROMPT_STORAGE_KEY, [])); }
  async function addItem(item) {
    const prompts = await getAll();
    prompts.push(item);
    await GM_setValue(PROMPT_STORAGE_KEY, prompts);
    return item;
  }
  async function update(index, itemToUpdate) {
    let prompts = await getAll();
    if (prompts[index]) {
      prompts[index] = itemToUpdate;
      await GM_setValue(PROMPT_STORAGE_KEY, prompts);
    }
  }
  async function remove(index) {
    let prompts = await getAll();
    prompts.splice(index, 1);
    await GM_setValue(PROMPT_STORAGE_KEY, prompts);
  }
  function createCustomTooltip(button, text, position = 'top') {
    let tooltipElement = null;
    const showTooltip = () => {
      if (tooltipElement) return;
      tooltipElement = document.createElement('div');
      const innerDiv = document.createElement('div');
      innerDiv.textContent = text;
      innerDiv.style.cssText = "color: #1d1d20; text-align: center; font-family: 'Inter', sans-serif; font-size: 14px; font-weight: 400; line-height: 1;";
      tooltipElement.appendChild(innerDiv);
      tooltipElement.style.cssText = "position: fixed; z-index: 2147483647; background-color: #f4f4f6; border-radius: 6px; padding: 6px 12px; pointer-events: none; opacity: 0; transform: scale(0.95); transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1); white-space: nowrap;";
      document.body.appendChild(tooltipElement);
      const btnRect = button.getBoundingClientRect();
      const tooltipRect = tooltipElement.getBoundingClientRect();
      let top;
      const margin = 8;
      if (position === 'bottom') {
        top = btnRect.bottom + margin;
        if (top + tooltipRect.height > window.innerHeight) {
          top = btnRect.top - tooltipRect.height - margin;
        }
      } else {
        top = btnRect.top - tooltipRect.height - margin;
        if (top < 0) {
          top = btnRect.bottom + margin;
        }
      }
      let left = btnRect.left + (btnRect.width / 2) - (tooltipRect.width / 2);
      if (left < 0) { left = margin; }
      if (left + tooltipRect.width > window.innerWidth) { left = window.innerWidth - tooltipRect.width - margin; }
      tooltipElement.style.left = `${left}px`;
      tooltipElement.style.top = `${top}px`;
      requestAnimationFrame(() => {
        tooltipElement.style.opacity = '1';
        tooltipElement.style.transform = 'scale(1)';
      });
    };
    const hideTooltip = () => {
      if (!tooltipElement) return;
      const el = tooltipElement;
      tooltipElement = null;
      el.style.opacity = '0';
      el.style.transform = 'scale(0.95)';
      setTimeout(() => {
        if (document.body.contains(el)) {
          document.body.removeChild(el);
        }
      }, 150);
    };
    button.addEventListener('mouseenter', showTooltip);
    button.addEventListener('mouseleave', hideTooltip);
    button.addEventListener('mousedown', hideTooltip);
  }
  function createChatGPTButton() {
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.setAttribute('aria-label', getTranslation('prompts'));
    btn.setAttribute('title', getTranslation('prompt'));
    btn.className = 'composer-btn';
    setSafeInnerHTML(btn, `<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-label="" class="icon"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg>`);
    return btn;
  }
  function createDeepSeekButton() {
    const btn = document.createElement('button');
    btn.setAttribute('role', 'button');
    btn.setAttribute('tabindex', '0');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    setSafeInnerHTML(btn, `<div class="ds-icon" style="font-size: 17px; width: 17px; height: 17px; color: currentColor; margin-right: 6px; visibility: visible;"><svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg></div><span class=""><span class="_6dbc175">${getTranslation('prompt')}</span></span>`);
    return btn;
  }
  function createGoogleStudioButton() {
    const btn = document.createElement('button');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.setAttribute('ms-button', '');
    btn.setAttribute('variant', 'icon');
    btn.className = 'mat-mdc-tooltip-trigger icon';
    btn.setAttribute('aria-label', getTranslation('prompts'));
    btn.setAttribute('title', getTranslation('prompt'));
    const svgHTML = `<svg fill="currentColor" style="width: 24px; height: 24px; display: flex;" version="1.1" viewBox="0 0 100 100"><g><path d="M17.563,30.277h0.012c0,1.245,1.004,2.254,2.246,2.267v0.002h60.359v-0.001c1.248-0.006,2.259-1.018,2.259-2.268h0.01 l0-10.459h0c-0.002-1.251-1.017-2.265-2.269-2.265l0,0H19.821v0c0,0,0,0,0,0c-1.253,0-2.269,1.017-2.269,2.269 c0,0.039,0.01,0.076,0.012,0.115L17.563,30.277z"/><path d="M80.179,42.504L80.179,42.504H19.821v0c0,0,0,0,0,0c-1.253,0-2.269,1.017-2.269,2.269c0,0.039,0.01,0.076,0.012,0.115 l0,10.34h0.012c0,1.245,1.004,2.254,2.246,2.267v0.002h60.359v-0.001c1.248-0.006,2.259-1.018,2.259-2.268h0.01l0-10.459h0 C82.446,43.518,81.431,42.504,80.179,42.504z"/><path d="M80.179,67.454L80.179,67.454H19.821l0,0c0,0,0,0,0,0c-1.253,0-2.269,1.017-2.269,2.269c0,0.039,0.01,0.076,0.012,0.115 l0,10.34h0.012c0,1.245,1.004,2.254,2.246,2.267v0.002h60.359v-0.001c1.248-0.006,2.259-1.019,2.259-2.269h0.01l0-10.459h0 C82.446,68.468,81.431,67.454,80.179,67.454z"/></g></svg>`;
    setSafeInnerHTML(btn, svgHTML);
    return btn;
  }
  function createQwenButton() {
    const btn = document.createElement('button');
    btn.className = 'chat-input-feature-btn';
    btn.setAttribute('data-testid', 'composer-button-prompts');
    setSafeInnerHTML(btn, `<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="chat-input-feature-btn-icon" style="font-size: 16px;"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg><span class="chat-input-feature-btn-text">${getTranslation('prompt')}</span>`);
    return btn;
  }
  function createZaiButton() {
    const btnWrapper = document.createElement('div');
    setSafeInnerHTML(btnWrapper, `<button type="button" class="px-2 @xl:px-3 py-1.5 flex gap-1.5 items-center text-sm rounded-lg border transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden bg-transparent dark:text-gray-300 border-[#E5E5E5] dark:border-[#3C3E3F] hover:bg-black/5 dark:hover:bg-white/5"><svg class=" size-4" stroke-width="2" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9 17L3 12L9 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15 17L21 12L15 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="hidden @sm:block whitespace-nowrap overflow-hidden text-ellipsis translate-y-[0.5px] mr-0.5">${getTranslation('prompt')}</span></button>`);
    const btn = btnWrapper.firstElementChild;
    btn.setAttribute('data-testid', 'composer-button-prompts');
    return btn;
  }
  function createGeminiButton() {
    const btn = document.createElement('button');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.className = 'mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-primary mat-mdc-tooltip-trigger';
    const svgHTML = `<span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span>
    <svg style="width: 24px; height: 24px; display: flex;" viewBox="0 0 20 20" fill="currentColor"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg>
    <span class="mat-focus-indicator"></span><span class="mat-mdc-button-touch-target"></span><span class="mat-ripple mat-mdc-button-ripple"></span>`;
    setSafeInnerHTML(btn, svgHTML);
    // Adicionamos 'bottom' para especificar a posição
    createCustomTooltip(btn, getTranslation('prompt'), 'bottom');
    return btn;
  }
  function createLmarenaButton() {
    const btn = document.createElement('button');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.className = 'inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ring-offset-2 focus-visible:ring-offset-surface-primary disabled:pointer-events-none disabled:opacity-50 text-interactive-active border border-border-faint bg-transparent hover:text-interactive-normal active:text-text-tertiary h-8 w-8 p-2 rounded-md active:scale-[0.96] active:transition-transform active:duration-75 transition-colors duration-150 ease-out hover:shadow-sm hover:bg-interactive-normal/10 hover:border-interactive-normal/10';
    btn.type = 'button';
    const svgHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4 transition-colors duration-150 ease-out text-interactive-normal"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg>`;
    setSafeInnerHTML(btn, svgHTML);
    createCustomTooltip(btn, getTranslation('prompt'));
    return btn;
  }
  function createMenu() {
    const m = document.createElement('div');
    m.setAttribute('data-state', 'closed');
    m.setAttribute('data-prompts-menu', 'true');
    m.style.cssText = `position: fixed; display: none; min-width: 320px; max-width: 420px; background-color: #353535; border: 1px solid #626262; border-radius: 16px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); z-index: 2147483647; flex-direction: column; padding: 6px 0; user-select: none; color: #F8FAFF;`;
    return m;
  }
  function createModal() {
    const overlay = document.createElement('div');
    overlay.id = '__ap_modal';
    overlay.setAttribute('data-prompts-modal', 'true');
    overlay.style.cssText = `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); display: none; z-index: 2147483647; justify-content: center; align-items: center; backdrop-filter: blur(4px);`;
    const box = document.createElement('div');
    box.style.cssText = `position: relative; background-color: #2a2a2e; color: #e0e0e0; border-radius: 16px; padding: 28px; box-shadow: 0 4px 6px rgba(0,0,0,0.1), 0 10px 20px rgba(0,0,0,0.4); width: min(90vw, 520px); display: flex; flex-direction: column; border: 1px solid #444; transform: scale(0.95); opacity: 0; transition: transform 0.2s ease-out, opacity 0.2s ease-out;`;
    setSafeInnerHTML(box, `
    <style>
    #__ap_modal input:focus, #__ap_modal textarea:focus { border-color: #22c55e; box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.4); }
    </style>
    <button id="__ap_close" aria-label="${getTranslation('close')}" style="position: absolute; top: 12px; right: 12px; background: none; border: none; color: #999; font-size: 22px; cursor: pointer; width: 32px; height: 32px; border-radius: 50%; transition: transform 0.3s ease, color 0.3s ease; display: flex; justify-content: center; align-items: center;">✕</button>
    <h2 id="__ap_modal_title" style="font-size: 18px; font-weight: 600; margin: 0 0 20px; text-align: center; color: #f0f0f0; letter-spacing: 0.5px;">${getTranslation('newPrompt')}</h2>
      <label for="__ap_title" style="margin-bottom: 6px; font-size: 13px; font-weight: 500; color: #bbb;">${getTranslation('title')}</label>
      <input id="__ap_title" style="background-color: #1e1e22; color: #e0e0e0; border: 1px solid #555; border-radius: 8px; padding: 10px; margin-bottom: 16px; width: 100%; box-sizing: border-box; transition: all 0.2s; outline: none;" />
      <label for="__ap_text" style="margin-bottom: 6px; font-size: 13px; font-weight: 500; color: #bbb;">${getTranslation('text')}</label>
      <textarea id="__ap_text" style="background-color: #1e1e22; color: #e0e0e0; border: 1px solid #555; border-radius: 8px; padding: 10px; height: 120px; width: 100%; margin-bottom: 24px; box-sizing: border-box; resize: vertical; outline: none; font-family: inherit;"></textarea>
      <div style="display: flex; justify-content: center;">
        <button id="__ap_save" style="padding: 10px 28px; border-radius: 8px; background-color: #22c55e; color: white; border: none; font-weight: 600; cursor: pointer; transition: all 0.2s ease-in-out; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">${getTranslation('save')}</button>
      </div>`);
    const saveBtn = box.querySelector('#__ap_save');
    saveBtn.addEventListener('mouseenter', () => { saveBtn.style.backgroundColor = '#16a34a'; saveBtn.style.transform = 'translateY(-1px)'; });
    saveBtn.addEventListener('mouseleave', () => { saveBtn.style.backgroundColor = '#22c55e'; saveBtn.style.transform = 'translateY(0)'; });
    const closeBtn = box.querySelector('#__ap_close');
    closeBtn.addEventListener('mouseenter', () => { closeBtn.style.transform = 'rotate(90deg)'; closeBtn.style.color = '#ef4444'; });
    closeBtn.addEventListener('mouseleave', () => { closeBtn.style.transform = 'rotate(0deg)'; closeBtn.style.color = '#999'; });
    overlay.appendChild(box);
    closeBtn.onclick = (e) => { e.stopPropagation(); hideModal(currentModal); };
    return overlay;
  }
  function createLanguageModal() {
    const overlay = document.createElement('div');
    overlay.id = '__ap_lang_modal';
    overlay.style.cssText = `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); display: none; z-index: 2147483647; justify-content: center; align-items: center; backdrop-filter: blur(4px);`;
    const box = document.createElement('div');
    box.style.cssText = `position: relative; background-color: #2a2a2e; color: #e0e0e0; border-radius: 16px; padding: 40px 28px 28px; box-shadow: 0 4px 6px rgba(0,0,0,0.1), 0 10px 20px rgba(0,0,0,0.4); width: min(90vw, 380px); display: flex; flex-direction: column; border: 1px solid #444; transform: scale(0.95); opacity: 0; transition: transform 0.2s ease-out, opacity 0.2s ease-out;`;
    const buttonsContainer = document.createElement('div');
    buttonsContainer.style.cssText = 'display: flex; flex-direction: column; gap: 12px;';
    Object.keys(translations).forEach(langKey => {
      const btn = document.createElement('button');
      btn.textContent = translations[langKey].langName;
      btn.style.cssText = `padding: 12px 20px; border-radius: 8px; background-color: #3e3e42; color: white; border: 1px solid #555; font-weight: 500; cursor: pointer; transition: all 0.2s ease-in-out; text-align: center;`;
      btn.addEventListener('mouseenter', () => { btn.style.borderColor = '#22c55e'; btn.style.backgroundColor = '#4a4a50'; });
      btn.addEventListener('mouseleave', () => { btn.style.borderColor = '#555'; btn.style.backgroundColor = '#3e3e42'; });
      btn.onclick = async () => {
        await GM_setValue(LANG_STORAGE_KEY, langKey);
        window.location.reload();
      };
      buttonsContainer.appendChild(btn);
    });
    setSafeInnerHTML(box, `
      <button id="__ap_lang_close" aria-label="${getTranslation('close')}" style="position: absolute; top: 5px; right: 5px; background: none; border: none; color: #999; font-size: 22px; cursor: pointer; width: 32px; height: 32px; border-radius: 50%; transition: transform 0.3s ease, color 0.3s ease; display: flex; justify-content: center; align-items: center;">✕</button>
    `);
    box.appendChild(buttonsContainer);
    overlay.appendChild(box);
    const closeBtnLang = box.querySelector('#__ap_lang_close');
    closeBtnLang.onclick = (e) => { e.stopPropagation(); hideModal(languageModal); };
    closeBtnLang.addEventListener('mouseenter', () => { closeBtnLang.style.transform = 'rotate(90deg)'; closeBtnLang.style.color = '#ef4444'; });
    closeBtnLang.addEventListener('mouseleave', () => { closeBtnLang.style.transform = 'rotate(0deg)'; closeBtnLang.style.color = '#999'; });
    return overlay;
  }
  function positionMenu(menu, button) {
    const btnRect = button.getBoundingClientRect();
    const menuHeight = menu.offsetHeight;
    const menuWidth = menu.offsetWidth;
    const viewportHeight = window.innerHeight;
    const viewportWidth = window.innerWidth;
    const margin = 8;
    let top = btnRect.bottom + margin;
    const spaceBelow = viewportHeight - btnRect.bottom;
    const spaceAbove = btnRect.top;
    if (spaceBelow < menuHeight + margin && spaceAbove > menuHeight + margin) { top = btnRect.top - menuHeight - margin; }
    let left = btnRect.left;
    if (left + menuWidth > viewportWidth) { left = viewportWidth - menuWidth - margin; }
    if (top < margin) { top = margin; }
    if (left < margin) { left = margin; }
    menu.style.top = `${top}px`;
    menu.style.left = `${left}px`;
    menu.style.visibility = 'visible';
  }
  function showModal(modal) {
    if (!modal) return;
    modal.style.display = 'flex';
    setTimeout(() => {
      const box = modal.querySelector('div');
      box.style.opacity = '1';
      box.style.transform = 'scale(1)';
    }, 10);
  }
  function hideModal(modal) {
    if (!modal) return;
    const box = modal.querySelector('div');
    box.style.opacity = '0';
    box.style.transform = 'scale(0.95)';
    setTimeout(() => { modal.style.display = 'none'; }, 200);
  }
  function openModal(item = null, index = -1) {
    if (!currentModal) return;
    const isEditing = !!item;
    currentModal.setAttribute('data-index', index);
    document.getElementById('__ap_modal_title').textContent = isEditing ? getTranslation('editPrompt') : getTranslation('newPrompt');
    document.getElementById('__ap_title').value = item?.title || '';
    document.getElementById('__ap_text').value = item?.text || '';
    showModal(currentModal);
    setTimeout(() => { document.getElementById('__ap_title').focus(); }, 100);
  }
  function ensureZaiToolsButtonIsVisible() {
    if (currentPlatform !== 'zai') return;
    setTimeout(() => {
      const referenceIconPath = document.querySelector('svg path[d="M2.6499 4.48322H13.3166"]');
      if (referenceIconPath) {
        const toolsButton = referenceIconPath.closest('button[data-melt-popover-trigger]');
        if (toolsButton && toolsButton.style.display === 'none') {
          toolsButton.removeAttribute('style');
        }
      }
    }, 0);
  }
  function closeMenu() {
    if (currentMenu && currentMenu.getAttribute('data-state') === 'open') {
      currentMenu.setAttribute('data-state', 'closed');
      currentMenu.style.display = 'none';
      currentMenu.style.visibility = 'hidden';
      ensureZaiToolsButtonIsVisible();
    }
  }
  function closeOtherMenus() {
    document.querySelectorAll('[data-state="open"]:not([data-prompts-menu])').forEach(menu => {
      if (menu.setAttribute) {
        menu.setAttribute('data-state', 'closed');
        if (menu.style) menu.style.display = 'none';
      }
    });
  }
  async function refreshMenu() {
    if (!currentMenu) return;
    setSafeInnerHTML(currentMenu, '');
    const promptsListContainer = document.createElement('div');
    promptsListContainer.style.cssText = 'max-height: 190px; overflow-y: auto;';
    const items = await getAll();
    if (!items.length) {
      const empty = document.createElement('div');
      empty.style.cssText = `padding: 8px 16px; color: #A0A0A0; font-size: 13px;`;
      empty.textContent = getTranslation('noSavedPrompts');
      promptsListContainer.appendChild(empty);
    } else {
      items.forEach((p, index) => {
        const row = document.createElement('div');
        row.style.cssText = `display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-bottom: 1px solid #626262; cursor: pointer; transition: background-color 0.2s;`;
        row.addEventListener('mouseenter', () => { row.style.backgroundColor = '#424451'; });
        row.addEventListener('mouseleave', () => { row.style.backgroundColor = 'transparent'; });
        const titleDiv = document.createElement('div');
        titleDiv.style.cssText = `font-size: 14px; font-weight: 500; cursor: pointer; flex: 1; padding-right: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #F8FAFF;`;
        titleDiv.textContent = p.title;
        titleDiv.title = p.title;
        titleDiv.onclick = (e) => { e.stopPropagation(); inserirPrompt(p, index); closeMenu(); };
        row.appendChild(titleDiv);
        const actionsDiv = document.createElement('div');
        actionsDiv.style.cssText = `display: flex; align-items: center; gap: 8px; flex-shrink: 0;`;
        const btnE = document.createElement('button');
        btnE.textContent = getTranslation('edit');
        btnE.title = getTranslation('edit');
        btnE.style.cssText = `background: none; border: none; color: #fbbf24; cursor: pointer; font-size: 12px; padding: 4px 8px; border-radius: 4px; transition: background-color 0.2s;`;
        btnE.addEventListener('mouseenter', () => { btnE.style.backgroundColor = '#92400e'; });
        btnE.addEventListener('mouseleave', () => { btnE.style.backgroundColor = 'transparent'; });
        btnE.onclick = (e) => { e.stopPropagation(); openModal(p, index); };
        actionsDiv.appendChild(btnE);
        const btnD = document.createElement('button');
        btnD.textContent = getTranslation('delete');
        btnD.title = getTranslation('delete');
        btnD.style.cssText = `background: none; border: none; color: #ef4444; cursor: pointer; font-size: 12px; padding: 4px 8px; border-radius: 4px; transition: background-color 0.2s;`;
        btnD.addEventListener('mouseenter', () => { btnD.style.backgroundColor = '#7f1d1d'; });
        btnD.addEventListener('mouseleave', () => { btnD.style.backgroundColor = 'transparent'; });
        btnD.onclick = (e) => { e.stopPropagation(); if (confirm(getTranslation('confirmDelete', { title: p.title }))) { remove(index).then(refreshMenu); } };
        actionsDiv.appendChild(btnD);
        row.appendChild(actionsDiv);
        promptsListContainer.appendChild(row);
      });
    }
    currentMenu.appendChild(promptsListContainer);
    const add = document.createElement('div');
    add.style.cssText = `display: flex; align-items: center; justify-content: center; padding: 8px 12px; cursor: pointer; transition: background-color 0.2s; color: #F8FAFF; border-top: 1px solid #626262;`;
    add.addEventListener('mouseenter', () => { add.style.backgroundColor = '#424451'; });
    add.addEventListener('mouseleave', () => { add.style.backgroundColor = 'transparent'; });
    setSafeInnerHTML(add, `<svg width="16" height="16" fill="currentColor" viewBox="0 0 20 20" style="margin-right: 8px;"><path d="M10 5v10m5-5H5" stroke="currentColor" stroke-width="2"/></svg><span style="font-size: 13px;">${getTranslation('addPrompt')}</span>`);
    add.title = getTranslation('addPrompt');
    add.onclick = (e) => { e.stopPropagation(); openModal(); };
    currentMenu.appendChild(add);
    const importExportHr = document.createElement('hr');
    importExportHr.style.cssText = "border: none; border-top: 1px solid #626262; margin: 0; padding: 0;";
    currentMenu.appendChild(importExportHr);
    const importExportContainer = document.createElement('div');
    importExportContainer.style.cssText = `display: flex; justify-content: space-around; align-items: center;`;
    const exportBtn = createMenuButton(getTranslation('export'));
    exportBtn.onclick = (e) => { e.stopPropagation(); exportPrompts(); };
    const importBtn = createMenuButton(getTranslation('import'));
    importBtn.onclick = (e) => { e.stopPropagation(); importPrompts(); };
    const divider = document.createElement('div');
    divider.style.cssText = "border-left: 1px solid rgb(98, 98, 98); height: 24px;";
    importExportContainer.appendChild(exportBtn);
    importExportContainer.appendChild(divider);
    importExportContainer.appendChild(importBtn);
    currentMenu.appendChild(importExportContainer);
  }
  function createMenuButton(text) {
    const btn = document.createElement('div');
    btn.textContent = text;
    btn.style.cssText = `flex: 1; text-align: center; padding: 8px 12px; cursor: pointer; transition: background-color 0.2s; color: #F8FAFF; font-size: 13px;`;
    btn.addEventListener('mouseenter', () => { btn.style.backgroundColor = '#424451'; });
    btn.addEventListener('mouseleave', () => { btn.style.backgroundColor = 'transparent'; });
    return btn;
  }
  async function exportPrompts() {
    const prompts = await getAll();
    if (prompts.length === 0) { alert(getTranslation('noPromptsToExport')); return; }
    const jsonString = JSON.stringify(prompts, null, 2);
    const blob = new Blob([jsonString], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = getTranslation('fileName');
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    closeMenu();
  }
  function importPrompts() {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.json,application/json';
    input.onchange = async (e) => {
      const file = e.target.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = async (event) => {
        try {
          const importedPrompts = JSON.parse(event.target.result);
          if (!Array.isArray(importedPrompts)) { throw new Error("O arquivo JSON não é um array válido."); }
          const currentPrompts = await getAll();
          const newPrompts = importedPrompts.map((p) => ({ title: p.title || 'Sem Título', text: p.text || '' }));
          await GM_setValue(PROMPT_STORAGE_KEY, [...currentPrompts, ...newPrompts]);
          await refreshMenu();
          alert(getTranslation('promptsImported', { count: newPrompts.length }));
        } catch (error) { alert(getTranslation('errorImporting', { error: error.message })); }
      };
      reader.readAsText(file);
    };
    input.click();
    closeMenu();
  }
  async function inserirPrompt(promptItem, index) {
    const platformSelectors = {
        chatgpt: '#prompt-textarea',
        deepseek: 'textarea[placeholder="Message DeepSeek"]',
        googlestudio: 'ms-autosize-textarea textarea',
        qwen: 'textarea#chat-input',
        zai: 'textarea#chat-input',
        gemini: 'div.ql-editor[contenteditable="true"]',
        lmarena: 'textarea[name="message"]'
    };
    const selector = platformSelectors[currentPlatform];
    const editor = document.querySelector(selector);
    if (!editor) {
        alert(getTranslation('editorNotFound', { platform: currentPlatform }));
        return;
    }
    editor.focus();

    setTimeout(() => {
        if (currentPlatform === 'gemini') {
            let p = editor.querySelector('p');
            if (!p) {
                p = document.createElement('p');
                editor.appendChild(p);
            }
            p.textContent = promptItem.text;
            editor.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
        } else {
            const dataTransfer = new DataTransfer();
            dataTransfer.setData('text/plain', promptItem.text);
            editor.dispatchEvent(new ClipboardEvent('paste', {
                clipboardData: dataTransfer,
                bubbles: true,
                cancelable: true
            }));
            if (editor.value !== promptItem.text) {
                const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
                nativeInputValueSetter.call(editor, promptItem.text);
                editor.dispatchEvent(new Event('input', { bubbles: true }));
            }
        }
    }, 50);

    let prompts = await getAll();
    if (index > 0) {
        const item = prompts.splice(index, 1)[0];
        prompts.unshift(item);
        await GM_setValue(PROMPT_STORAGE_KEY, prompts);
    }
  }
  function cleanup() {
    if (currentButton) { currentButton.remove(); currentButton = null; }
    if (currentMenu) { currentMenu.remove(); currentMenu = null; }
    if (currentModal) { currentModal.remove(); currentModal = null; }
    if (languageModal) { languageModal.remove(); languageModal = null; }
    isInitialized = false;
  }
  async function initUI() {
    if (pageObserver) pageObserver.disconnect();
    cleanup();
    currentPlatform = detectPlatform();
    if (!currentPlatform) return;
    try {
      let btn, elementToInsert, insertionPoint, insertionMethod = 'before';
      if (currentPlatform === 'chatgpt') {
        insertionPoint = await waitFor('div[class*="[grid-area:leading]"]').catch(() => null);
        if (insertionPoint) {
          insertionPoint.style.display = 'flex';
          insertionPoint.style.flexDirection = 'row';
          insertionPoint.style.alignItems = 'center';
          insertionPoint.style.gap = '8px';
          btn = createChatGPTButton();
          elementToInsert = btn;
          insertionMethod = 'append';
        }
      } else if (currentPlatform === 'deepseek') {
        const buttonsContainer = await waitFor('.ec4f5d61');
        const referenceButton = buttonsContainer.querySelector('button:has(span._6dbc175)');
        insertionPoint = buttonsContainer.querySelector('.bf38813a');
        if (!referenceButton || !insertionPoint) { throw new Error('Elementos da UI do DeepSeek não encontrados.'); }
        btn = createDeepSeekButton();
        btn.className = referenceButton.className;
        elementToInsert = btn;
        insertionMethod = 'before';
      } else if (currentPlatform === 'googlestudio') {
        insertionPoint = await waitFor('ms-add-chunk-menu', 5000).then(el => el.closest('.button-wrapper')).catch(() => null);
        if (insertionPoint) {
          const wrapper = document.createElement('div');
          wrapper.className = 'button-wrapper';
          btn = createGoogleStudioButton();
          wrapper.appendChild(btn);
          elementToInsert = wrapper;
          insertionMethod = 'before';
          const parentContainer = insertionPoint.closest('.prompt-input-wrapper-container');
          if (parentContainer) { parentContainer.style.alignItems = 'center'; }
        }
      } else if (currentPlatform === 'qwen') {
        insertionPoint = await waitFor('button.websearch_button', 5000).catch(() => null);
        if (insertionPoint) {
          btn = createQwenButton();
          elementToInsert = btn;
          insertionMethod = 'after';
        }
      } else if (currentPlatform === 'zai') {
        const referenceIconPath = await waitFor('svg path[d="M2.6499 4.48322H13.3166"]', 8000).catch(() => null);
        if (referenceIconPath) {
          insertionPoint = referenceIconPath.closest('button[data-melt-popover-trigger]');
          if (insertionPoint) {
            btn = createZaiButton();
            elementToInsert = btn;
            insertionMethod = 'after';
          }
        }
      } else if (currentPlatform === 'gemini') {
        insertionPoint = await waitFor('button.upload-card-button', 8000).catch(() => null);
        if (insertionPoint) {
            btn = createGeminiButton();
            elementToInsert = btn;
            insertionMethod = 'after';
            const wrapper = insertionPoint.closest('div.leading-actions-wrapper');
            if (wrapper) {
                wrapper.style.display = 'flex';
                wrapper.style.alignItems = 'center';
                wrapper.style.gap = '8px';
            }
        }
      } else if (currentPlatform === 'lmarena') {
        insertionPoint = await waitFor('div[data-sentry-component="SelectChatModality"]', 8000).catch(() => null);
        if (insertionPoint) {
            btn = createLmarenaButton();
            elementToInsert = btn;
            insertionMethod = 'append';
        }
      }
      if (!btn || !insertionPoint) {
        return;
      }
      currentButton = elementToInsert;
      const clickableElement = btn;
      currentMenu = createMenu();
      currentModal = createModal();
      languageModal = createLanguageModal();
      if (insertionMethod === 'append') {
        insertionPoint.appendChild(elementToInsert);
      } else if (insertionMethod === 'before') {
        insertionPoint.parentNode.insertBefore(elementToInsert, insertionPoint);
      } else {
        insertionPoint.parentNode.insertBefore(elementToInsert, insertionPoint.nextSibling);
      }
      document.body.appendChild(currentMenu);
      document.body.appendChild(currentModal);
      document.body.appendChild(languageModal);
      clickableElement.addEventListener('click', e => {
        e.stopPropagation();
        e.preventDefault();
        if (currentMenu.getAttribute('data-state') === 'open') {
          closeMenu();
          return;
        }
        closeOtherMenus();
        ensureZaiToolsButtonIsVisible();
        currentMenu.style.display = 'flex';
        currentMenu.style.visibility = 'hidden';
        refreshMenu().then(() => {
          setTimeout(() => {
            positionMenu(currentMenu, clickableElement);
            currentMenu.setAttribute('data-state', 'open');
          }, 10);
        });
      });
      currentModal.querySelector('#__ap_save').onclick = (e) => {
        e.stopPropagation();
        const indexStr = currentModal.getAttribute('data-index');
        const index = indexStr !== '-1' ? Number(indexStr) : -1;
        const title = document.getElementById('__ap_title').value.trim();
        const text = document.getElementById('__ap_text').value.trim();
        if (!title || !text) { alert(getTranslation('requiredFields')); return; }
        const item = { title, text };
        const op = index > -1 ? update(index, item) : addItem(item);
        op.then(() => { hideModal(currentModal); refreshMenu(); });
      };
      isInitialized = true;
    } catch (error) {
      cleanup();
    } finally {
      setupPageObserver();
    }
  }
  function setupGlobalEventListeners() {
    document.addEventListener('click', ev => {
      if (!currentMenu || !currentButton) return;
      if (ev.target.closest('[data-prompts-menu],[data-testid="composer-button-prompts"],[data-prompts-modal]')) return;
      closeMenu();
    });
    document.addEventListener('keydown', ev => {
      if (ev.key === 'Escape') {
        closeMenu();
        if (currentModal && currentModal.style.display === 'flex') { hideModal(currentModal); }
        if (languageModal && languageModal.style.display === 'flex') { hideModal(languageModal); }
      }
    });
    window.addEventListener('resize', debounce(() => {
      if (currentMenu && currentMenu.getAttribute('data-state') === 'open') {
        const clickable = currentButton.hasAttribute('data-testid') ? currentButton : currentButton.querySelector('[data-testid="composer-button-prompts"]');
        if (clickable) positionMenu(currentMenu, clickable);
      }
    }, 100));
  }
  function registerLanguageMenu() {
    GM_registerMenuCommand(getTranslation('languageSettings'), () => {
      if (!languageModal) {
        languageModal = createLanguageModal();
        document.body.appendChild(languageModal);
      }
      showModal(languageModal);
    });
  }
  const debouncedTryInit = debounce(tryInit, 500);
  function setupPageObserver() {
    if (pageObserver) pageObserver.disconnect();
    pageObserver = new MutationObserver(() => {
      if (!document.body.contains(currentButton)) {
        debouncedTryInit();
      }
    });
    pageObserver.observe(document.body, { childList: true, subtree: true });
  }
  function tryInit() {
    if (isInitializing) return;
    if (isInitialized && currentButton && document.body.contains(currentButton) && currentPlatform === detectPlatform()) {
      return;
    }
    isInitializing = true;
    initUI().catch(()=> {
    }).finally(() => {
      isInitializing = false;
    });
  }
  async function start() {
    await determineLanguage();
    setupGlobalEventListeners();
    registerLanguageMenu();
    tryInit();
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', start);
  } else {
    start();
  }
})();