diff --git a/background.js b/background.js index 9ea1831..ddec65a 100644 --- a/background.js +++ b/background.js @@ -1,37 +1,215 @@ let originTabId = null; -// Create context menu +// Function to show loading overlay directly in the page +function showLoadingOverlay(tabId) { + chrome.scripting.executeScript({ + target: { tabId: tabId }, + function: () => { + // Create overlay elements if they don't exist + let overlay = document.getElementById('real-chatgpt-overlay'); + if (!overlay) { + // Create styles + const style = document.createElement('style'); + style.textContent = ` + #real-chatgpt-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 9999; + font-family: Arial, sans-serif; + } + #real-chatgpt-message { + color: white; + font-size: 18px; + margin-top: 20px; + padding: 10px 20px; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 5px; + text-align: center; + max-width: 80%; + } + #real-chatgpt-message.completion { + background-color: #28a745; + font-weight: bold; + } + #real-chatgpt-spinner { + width: 50px; + height: 50px; + border: 5px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + border-top-color: #fff; + animation: spin 1s ease-in-out infinite; + } + @keyframes spin { + to { transform: rotate(360deg); } + } + `; + document.head.appendChild(style); + + // Create overlay + overlay = document.createElement('div'); + overlay.id = 'real-chatgpt-overlay'; + + // Create spinner + const spinner = document.createElement('div'); + spinner.id = 'real-chatgpt-spinner'; + + // Create message + const message = document.createElement('div'); + message.id = 'real-chatgpt-message'; + message.textContent = 'Processing with ChatGPT...'; + + // Assemble overlay + overlay.appendChild(spinner); + overlay.appendChild(message); + document.body.appendChild(overlay); + } + } + }); +} + +// Function to show completion message +function showCompletionMessage(tabId) { + chrome.scripting.executeScript({ + target: { tabId: tabId }, + function: () => { + // Update existing overlay or create a new one + let overlay = document.getElementById('real-chatgpt-overlay'); + let spinner = document.getElementById('real-chatgpt-spinner'); + let message = document.getElementById('real-chatgpt-message'); + + if (!overlay) { + // If overlay doesn't exist, create it + const style = document.createElement('style'); + style.textContent = ` + #real-chatgpt-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 9999; + font-family: Arial, sans-serif; + } + #real-chatgpt-message { + color: white; + font-size: 18px; + margin-top: 20px; + padding: 10px 20px; + background-color: #28a745; + border-radius: 5px; + text-align: center; + max-width: 80%; + font-weight: bold; + } + `; + document.head.appendChild(style); + + overlay = document.createElement('div'); + overlay.id = 'real-chatgpt-overlay'; + + message = document.createElement('div'); + message.id = 'real-chatgpt-message'; + + overlay.appendChild(message); + document.body.appendChild(overlay); + } else if (spinner) { + // Hide spinner if it exists + spinner.style.display = 'none'; + } + + // Update message + if (message) { + message.textContent = 'Finished, please paste from clipboard'; + message.classList.add('completion'); + } + + // Remove overlay after 1 second + setTimeout(() => { + const overlay = document.getElementById('real-chatgpt-overlay'); + if (overlay) { + overlay.remove(); + } + }, 1000); + } + }); +} + +// Create context menus from settings or defaults +function createContextMenus(menuItems) { + // Remove all existing context menus + chrome.contextMenus.removeAll(); + + // Create new context menus from settings + menuItems.forEach(item => { + chrome.contextMenus.create({ + id: item.id, + title: item.title, + contexts: ["selection"], // Show only when text is selected + }); + }); +} + +// Initialize context menus on installation chrome.runtime.onInstalled.addListener(() => { - chrome.contextMenus.create({ - id: "improveMail", - title: "Verbessere Mail", - contexts: ["selection"], // Show only when text is selected + // Initialize storage with default values if not already set + chrome.storage.sync.get(['menuItems'], (result) => { + const menuItems = result.menuItems || defaultMenuItems; + + // Save to storage if not already set + if (!result.menuItems) { + chrome.storage.sync.set({ menuItems: defaultMenuItems }); + } + + // Create context menus + createContextMenus(menuItems); }); - chrome.contextMenus.create({ - id: "improveText", - title: "Verbessere Text", - contexts: ["selection"], // Show only when text is selected - }); - chrome.contextMenus.create({ - id: "seoText", - title: "Erstelle ein SEO-Text", - contexts: ["selection"], // Show only when text is selected - }); - chrome.contextMenus.create({ - id: "explainMe", - title: "Erkläre Text", - contexts: ["selection"], // Show only when text is selected +}); +// Handle context menu clicks +chrome.contextMenus.onClicked.addListener((info, tab) => { + // Get menu items from storage + chrome.storage.sync.get(['menuItems'], (result) => { + const menuItems = result.menuItems || defaultMenuItems; + const selectedItem = menuItems.find(item => item.id === info.menuItemId); + + if (selectedItem) { + handleMenuItemClick(info, tab, selectedItem.prompt, selectedItem.model); + } }); }); +// Listen for messages from popup.js +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message.action === 'updateContextMenus') { + chrome.storage.sync.get(['menuItems'], (result) => { + const menuItems = result.menuItems || defaultMenuItems; + createContextMenus(menuItems); + }); + } +}); // Utility function to handle menu item click dynamically -function handleMenuItemClick(info, tab, prefixText) { +function handleMenuItemClick(info, tab, prefixText, model = 'gpt-4o') { originTabId = tab.id; if (info.selectionText) { + // Show loading indicator in the original tab + showLoadingOverlay(originTabId); + const selectedText = prefixText + info.selectionText; - chrome.tabs.create({ url: "https://chatgpt.com/?temporary-chat=true" }, (newTab) => { + chrome.tabs.create({ url: `https://chatgpt.com/?model=${model}&temporary-chat=true`, active: false }, (newTab) => { chrome.tabs.onUpdated.addListener(function listener(tabId, info) { if (tabId === newTab.id && info.status === "complete") { chrome.tabs.onUpdated.removeListener(listener); @@ -45,19 +223,7 @@ function handleMenuItemClick(info, tab, prefixText) { }); } } -// Handle context menu clicks -chrome.contextMenus.onClicked.addListener((info, tab) => { - const menuActions = { - explainMe: 'Erkläre mir folgenden Text, fasse es kurz und gut lesbar zusammen. Erstelle keine eigenen Kommentare, zeige rein nur den text als Ausgabe: ', - improveMail: 'Verbessere folgende Mail, erstelle keine eigenen Kommentare, zeige rein nur den text als ausgabe: ', - improveText: 'Verbessere folgenden Text, mach es nicht viel länger oder kürzer als es jetzt schon ist, erstelle keine eigenen Kommentare, zeige rein nur den text als Ausgabe: ', - seoText: 'Du bist der Weltbeste SEO-Text Author. Schreibe einen SEO-optimierten Text mit 400-500 Wörtern basierend auf dem folgenden Inhalt. Identifiziere das Haupt-Keyword und integriere es mit einer Keyword-Dichte von 2-3 %. Strukturierte den Text mit HTML-Elementen (h1, h2, h3, p). Hebe das Keyword mit dem strong-Tag hervor. Gib nur den HTML-Code aus, ohne HTML-, Head- oder Body-Tags und ohne Kommentare. Die Ausgabe sollte als reiner Text erscheinen, nicht in einem Codefeld. Hier ist der relevante Text/Keyword: ', - }; - if (menuActions[info.menuItemId]) { - handleMenuItemClick(info, tab, menuActions[info.menuItemId]); - } -}); // Listen for a message to close the current tab and switch back @@ -69,9 +235,14 @@ chrome.runtime.onMessage.addListener((message, sender) => { chrome.tabs.remove(currentTabId, () => { console.log("Closed current tab:", currentTabId); - // Switch back to the original tab + // Switch back to the original tab and show completion message if (originTabId) { - chrome.tabs.update(originTabId, { active: true }); + chrome.tabs.update(originTabId, { active: true }, () => { + // Show completion message in the original tab + setTimeout(() => { + showCompletionMessage(originTabId); + }, 100); // Small delay to ensure tab is active + }); } }); } diff --git a/contentScript.css b/contentScript.css index e69de29..183e366 100644 --- a/contentScript.css +++ b/contentScript.css @@ -0,0 +1,43 @@ +#real-chatgpt-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 9999; + font-family: Arial, sans-serif; +} + +#real-chatgpt-message { + color: white; + font-size: 18px; + margin-top: 20px; + padding: 10px 20px; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 5px; + text-align: center; + max-width: 80%; +} + +#real-chatgpt-message.completion { + background-color: #28a745; + font-weight: bold; +} + +#real-chatgpt-spinner { + width: 50px; + height: 50px; + border: 5px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + border-top-color: #fff; + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} diff --git a/contentScript.js b/contentScript.js index e69de29..6f26fcb 100644 --- a/contentScript.js +++ b/contentScript.js @@ -0,0 +1,94 @@ +// Create and manage overlay elements for loading and completion states +let overlay = null; +let messageElement = null; + +// Flag to indicate content script is ready +let isInitialized = false; + +// Initialize the content script +function initialize() { + if (isInitialized) return; + isInitialized = true; + + // Let the background script know we're ready + chrome.runtime.sendMessage({ action: 'contentScriptReady' }); + console.log('Real ChatGPT Extension: Content script initialized'); +} + +// Initialize immediately +initialize(); + +// Create the overlay element with loading spinner +function createOverlay() { + // Remove any existing overlay + removeOverlay(); + + // Create main overlay container + overlay = document.createElement('div'); + overlay.id = 'real-chatgpt-overlay'; + + // Create message container + messageElement = document.createElement('div'); + messageElement.id = 'real-chatgpt-message'; + + // Create loading spinner + const spinner = document.createElement('div'); + spinner.id = 'real-chatgpt-spinner'; + + // Add loading message + messageElement.textContent = 'Processing with ChatGPT...'; + + // Assemble the overlay + overlay.appendChild(spinner); + overlay.appendChild(messageElement); + document.body.appendChild(overlay); +} + +// Remove the overlay from the DOM +function removeOverlay() { + const existingOverlay = document.getElementById('real-chatgpt-overlay'); + if (existingOverlay) { + existingOverlay.remove(); + } +} + +// Show completion message and remove after delay +function showCompletionMessage() { + if (!overlay) { + createOverlay(); + } + + // Update the overlay to show completion message + const spinner = document.getElementById('real-chatgpt-spinner'); + if (spinner) { + spinner.style.display = 'none'; + } + + // Update message + if (messageElement) { + messageElement.textContent = 'Finished, please paste from clipboard'; + messageElement.classList.add('completion'); + } + + // Remove after 1 second + setTimeout(removeOverlay, 1000); +} + +// Listen for messages from the background script +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + // Make sure we're initialized + initialize(); + if (message.action === 'showLoading') { + createOverlay(); + sendResponse({ status: 'overlay_created' }); + return true; + } else if (message.action === 'showCompletion') { + showCompletionMessage(); + sendResponse({ status: 'completion_shown' }); + return true; + } else if (message.action === 'removeOverlay') { + removeOverlay(); + sendResponse({ status: 'overlay_removed' }); + return true; + } +}); diff --git a/manifest.json b/manifest.json index 96fed1c..f9e991c 100644 --- a/manifest.json +++ b/manifest.json @@ -7,7 +7,8 @@ "scripting", "activeTab", "tabs", - "clipboardWrite" + "clipboardWrite", + "storage" ], "host_permissions": [ "https://chatgpt.com/*" @@ -25,20 +26,5 @@ }, "background": { "service_worker": "background.js" - }, - "content_scripts": [ - { - "matches": [ - "http://*/*", - "https://*/*" - ], - "run_at": "document_end", - "js": [ - "contentScript.js" - ], - "css": [ - "contentScript.css" - ] - } - ] + } } \ No newline at end of file diff --git a/popup.css b/popup.css index c7cf5f5..a6c9e3b 100644 --- a/popup.css +++ b/popup.css @@ -4,31 +4,103 @@ } body { - width: 500px; - height: 200px; + background: #fff9d8; min-width: 500px; min-height: 200px; margin: 0; } .container { - background-color: #F2DE62; - width: 100%; - height: 100%; display: flex; flex-direction: column; align-items: flex-start; justify-content: space-evenly; - padding: 30px; + padding: 15px; + box-sizing: border-box; + border-radius: 10px; +} +.btn-primary { + background-color: #2196F3; + margin-right: 1rem; +} +.btn { + color: white; + font-weight: bold; +} +h1 { + font-size: 20px; +} +.menu-items { + margin-bottom: 10px; + width: 100%; +} +.menu-item { + border: 1px solid #ddd; + border-radius: 4px; + padding: 10px; + margin-bottom: 10px; + background-color: #f9f9f9; +} +.menu-item-header { + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + font-weight: bold; +} +.menu-item-content { + display: none; + margin-top: 1rem; +} +.menu-item.expanded .menu-item-content { + display: block; +} +input[type="text"], textarea, select { + width: 100%; + padding: 8px; + margin: 5px 0; + border: 1px solid #ddd; + border-radius: 4px; box-sizing: border-box; } - -h1 { - margin: 0; - font-family: 'Sora'; +textarea { + height: 80px; + resize: vertical; } - -p { - margin: 0; - font-family: 'Sora'; +.btn { + padding: 8px 12px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 13px; +} +.btn-primary { + background-color: #4285f4; + color: white; +} +.btn-danger { + background-color: #ea4335; + color: white; +} +.btn-secondary { + background-color: #f1f1f1; + color: #333; +} +.action-buttons { + display: flex; + justify-content: space-between; + margin-top: 10px; +} +.toggle-btn { + background: none; + border: none; + cursor: pointer; +} +.form-group { + margin-bottom: 10px; +} +.form-group label { + display: block; + margin-bottom: 5px; + font-weight: bold; } \ No newline at end of file diff --git a/popup.html b/popup.html index f3cf1ab..57eb154 100644 --- a/popup.html +++ b/popup.html @@ -3,14 +3,59 @@
-Your extension is ready
you can go to https://developer.chrome.com/docs/extensions/ to learn more about chrome extensions