improvements
This commit is contained in:
parent
13c7ab1d08
commit
655e788b7a
241
background.js
241
background.js
@ -1,37 +1,215 @@
|
|||||||
let originTabId = null;
|
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.runtime.onInstalled.addListener(() => {
|
||||||
chrome.contextMenus.create({
|
// Initialize storage with default values if not already set
|
||||||
id: "improveMail",
|
chrome.storage.sync.get(['menuItems'], (result) => {
|
||||||
title: "Verbessere Mail",
|
const menuItems = result.menuItems || defaultMenuItems;
|
||||||
contexts: ["selection"], // Show only when text is selected
|
|
||||||
|
// 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",
|
// Handle context menu clicks
|
||||||
title: "Verbessere Text",
|
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||||
contexts: ["selection"], // Show only when text is selected
|
// Get menu items from storage
|
||||||
});
|
chrome.storage.sync.get(['menuItems'], (result) => {
|
||||||
chrome.contextMenus.create({
|
const menuItems = result.menuItems || defaultMenuItems;
|
||||||
id: "seoText",
|
const selectedItem = menuItems.find(item => item.id === info.menuItemId);
|
||||||
title: "Erstelle ein SEO-Text",
|
|
||||||
contexts: ["selection"], // Show only when text is selected
|
if (selectedItem) {
|
||||||
});
|
handleMenuItemClick(info, tab, selectedItem.prompt, selectedItem.model);
|
||||||
chrome.contextMenus.create({
|
}
|
||||||
id: "explainMe",
|
|
||||||
title: "Erkläre Text",
|
|
||||||
contexts: ["selection"], // Show only when text is selected
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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
|
// Utility function to handle menu item click dynamically
|
||||||
function handleMenuItemClick(info, tab, prefixText) {
|
function handleMenuItemClick(info, tab, prefixText, model = 'gpt-4o') {
|
||||||
originTabId = tab.id;
|
originTabId = tab.id;
|
||||||
|
|
||||||
if (info.selectionText) {
|
if (info.selectionText) {
|
||||||
|
// Show loading indicator in the original tab
|
||||||
|
showLoadingOverlay(originTabId);
|
||||||
|
|
||||||
const selectedText = prefixText + info.selectionText;
|
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) {
|
chrome.tabs.onUpdated.addListener(function listener(tabId, info) {
|
||||||
if (tabId === newTab.id && info.status === "complete") {
|
if (tabId === newTab.id && info.status === "complete") {
|
||||||
chrome.tabs.onUpdated.removeListener(listener);
|
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
|
// 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, () => {
|
chrome.tabs.remove(currentTabId, () => {
|
||||||
console.log("Closed current tab:", 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) {
|
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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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); }
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -7,7 +7,8 @@
|
|||||||
"scripting",
|
"scripting",
|
||||||
"activeTab",
|
"activeTab",
|
||||||
"tabs",
|
"tabs",
|
||||||
"clipboardWrite"
|
"clipboardWrite",
|
||||||
|
"storage"
|
||||||
],
|
],
|
||||||
"host_permissions": [
|
"host_permissions": [
|
||||||
"https://chatgpt.com/*"
|
"https://chatgpt.com/*"
|
||||||
@ -25,20 +26,5 @@
|
|||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"service_worker": "background.js"
|
"service_worker": "background.js"
|
||||||
},
|
|
||||||
"content_scripts": [
|
|
||||||
{
|
|
||||||
"matches": [
|
|
||||||
"http://*/*",
|
|
||||||
"https://*/*"
|
|
||||||
],
|
|
||||||
"run_at": "document_end",
|
|
||||||
"js": [
|
|
||||||
"contentScript.js"
|
|
||||||
],
|
|
||||||
"css": [
|
|
||||||
"contentScript.css"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
100
popup.css
100
popup.css
@ -4,31 +4,103 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
width: 500px;
|
background: #fff9d8;
|
||||||
height: 200px;
|
|
||||||
min-width: 500px;
|
min-width: 500px;
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
background-color: #F2DE62;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-evenly;
|
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;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
textarea {
|
||||||
h1 {
|
height: 80px;
|
||||||
margin: 0;
|
resize: vertical;
|
||||||
font-family: 'Sora';
|
|
||||||
}
|
}
|
||||||
|
.btn {
|
||||||
p {
|
padding: 8px 12px;
|
||||||
margin: 0;
|
border: none;
|
||||||
font-family: 'Sora';
|
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;
|
||||||
}
|
}
|
||||||
51
popup.html
51
popup.html
@ -3,14 +3,59 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Chrome extension</title>
|
<title>Real ChatGPT Extension Settings</title>
|
||||||
<link rel="stylesheet" href="popup.css">
|
<link rel="stylesheet" href="popup.css">
|
||||||
<script defer src="popup.js"></script>
|
<script defer src="popup.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Great!</h1>
|
<h1>Real ChatGPT Extension Settings</h1>
|
||||||
<p>Your extension is ready<br>you can go to <a target="_blank" href="https://developer.chrome.com/docs/extensions/">https://developer.chrome.com/docs/extensions/</a> to learn more about chrome extensions</p>
|
|
||||||
|
<div class="menu-items" id="menuItems">
|
||||||
|
<!-- Menu items will be added here dynamically -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button id="addMenuItem" class="btn btn-primary">+ New</button>
|
||||||
|
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button id="saveSettings" class="btn btn-primary">Save Settings</button>
|
||||||
|
<button id="resetSettings" class="btn btn-danger">Reset to Default</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Template for menu item -->
|
||||||
|
<template id="menuItemTemplate">
|
||||||
|
<div class="menu-item">
|
||||||
|
<div class="menu-item-header">
|
||||||
|
<span class="menu-item-title">Menu Item</span>
|
||||||
|
<button class="toggle-btn">▼</button>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item-content">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="menuId">ID:</label>
|
||||||
|
<input type="text" class="menu-id" placeholder="Unique identifier (e.g., improveMail)">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="menuTitle">Title:</label>
|
||||||
|
<input type="text" class="menu-title" placeholder="Display text in context menu">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="menuPrompt">Prompt Template:</label>
|
||||||
|
<textarea class="menu-prompt" placeholder="Prompt text to send to ChatGPT"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="menuModel">Model:</label>
|
||||||
|
<select class="menu-model">
|
||||||
|
<option value="gpt-4o">GPT-4o</option>
|
||||||
|
<option value="gpt-4-5">GPT-4.5</option>
|
||||||
|
<option value="o1">o1</option>
|
||||||
|
<option value="o3-mini">o3-mini</option>
|
||||||
|
<option value="o3-mini-high">o3-mini-high</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger delete-menu-item">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
177
popup.js
177
popup.js
@ -0,0 +1,177 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// Default menu items
|
||||||
|
const defaultMenuItems = [
|
||||||
|
{
|
||||||
|
id: "improveMail",
|
||||||
|
title: "Improve Email",
|
||||||
|
prompt:
|
||||||
|
"Improve the following email. Do not add any personal comments, only show the text as output:",
|
||||||
|
model: "gpt-4o",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "improveText",
|
||||||
|
title: "Improve Text",
|
||||||
|
prompt:
|
||||||
|
"Improve the following text without making it much longer or shorter than it already is. Do not add any personal comments, only show the text as output:",
|
||||||
|
model: "gpt-4o",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "seoText",
|
||||||
|
title: "Create an SEO Text",
|
||||||
|
prompt:
|
||||||
|
"You are the world’s best SEO text author. Write an SEO-optimized text of 400–500 words based on the following content. Identify the main keyword and integrate it with a keyword density of 2–3%. Structure the text with HTML elements (h1, h2, h3, p). Highlight the keyword with the strong tag. Only output the HTML code, without HTML, head, or body tags, and without comments. The output should appear as plain text, not in a code block. Here is the relevant text/keyword:",
|
||||||
|
model: "gpt-4o",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "explainMe",
|
||||||
|
title: "Explain Text",
|
||||||
|
prompt:
|
||||||
|
"Explain the following text to me, summarize it briefly and in a readable way. Do not add any personal comments, only show the text as output:",
|
||||||
|
model: "gpt-4o",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fixCode",
|
||||||
|
title: "Fix Code",
|
||||||
|
prompt:
|
||||||
|
"Improve or fix the following code snippet. Provide the corrected code without adding any personal comments. Only output the corrected code:",
|
||||||
|
model: "gpt-4o",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// DOM Elements
|
||||||
|
const menuItemsContainer = document.getElementById("menuItems");
|
||||||
|
const addMenuItemBtn = document.getElementById("addMenuItem");
|
||||||
|
const saveSettingsBtn = document.getElementById("saveSettings");
|
||||||
|
const resetSettingsBtn = document.getElementById("resetSettings");
|
||||||
|
const menuItemTemplate = document.getElementById("menuItemTemplate");
|
||||||
|
|
||||||
|
// Load settings from storage
|
||||||
|
function loadSettings() {
|
||||||
|
chrome.storage.sync.get(["menuItems"], (result) => {
|
||||||
|
let menuItems = result.menuItems || defaultMenuItems;
|
||||||
|
renderMenuItems(menuItems);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save settings to storage
|
||||||
|
function saveSettings() {
|
||||||
|
const menuItems = [];
|
||||||
|
const menuItemElements = document.querySelectorAll(".menu-item");
|
||||||
|
|
||||||
|
menuItemElements.forEach((item) => {
|
||||||
|
const id = item.querySelector(".menu-id").value.trim();
|
||||||
|
const title = item.querySelector(".menu-title").value.trim();
|
||||||
|
const prompt = item.querySelector(".menu-prompt").value.trim();
|
||||||
|
const model = item.querySelector(".menu-model").value;
|
||||||
|
|
||||||
|
if (id && title && prompt) {
|
||||||
|
menuItems.push({
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
prompt,
|
||||||
|
model,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.storage.sync.set({ menuItems }, () => {
|
||||||
|
// Update context menus
|
||||||
|
chrome.runtime.sendMessage({ action: "updateContextMenus" });
|
||||||
|
|
||||||
|
// Show save confirmation
|
||||||
|
const saveBtn = document.getElementById("saveSettings");
|
||||||
|
const originalText = saveBtn.textContent;
|
||||||
|
saveBtn.textContent = "Saved!";
|
||||||
|
saveBtn.disabled = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
saveBtn.textContent = originalText;
|
||||||
|
saveBtn.disabled = false;
|
||||||
|
}, 1500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset settings to default
|
||||||
|
function resetSettings() {
|
||||||
|
if (confirm("Are you sure you want to reset all settings to default?")) {
|
||||||
|
chrome.storage.sync.set({ menuItems: defaultMenuItems }, () => {
|
||||||
|
renderMenuItems(defaultMenuItems);
|
||||||
|
chrome.runtime.sendMessage({ action: "updateContextMenus" });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render menu items in the UI
|
||||||
|
function renderMenuItems(menuItems) {
|
||||||
|
menuItemsContainer.innerHTML = "";
|
||||||
|
|
||||||
|
menuItems.forEach((item, index) => {
|
||||||
|
const menuItemElement = createMenuItemElement(item);
|
||||||
|
menuItemsContainer.appendChild(menuItemElement);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a menu item element
|
||||||
|
function createMenuItemElement(item = {}) {
|
||||||
|
const fragment = document.importNode(menuItemTemplate.content, true);
|
||||||
|
const menuItem = fragment.querySelector(".menu-item");
|
||||||
|
|
||||||
|
// Set values if provided
|
||||||
|
const titleElement = menuItem.querySelector(".menu-item-title");
|
||||||
|
const idInput = menuItem.querySelector(".menu-id");
|
||||||
|
const titleInput = menuItem.querySelector(".menu-title");
|
||||||
|
const promptInput = menuItem.querySelector(".menu-prompt");
|
||||||
|
const modelSelect = menuItem.querySelector(".menu-model");
|
||||||
|
|
||||||
|
if (item.id) {
|
||||||
|
idInput.value = item.id;
|
||||||
|
titleElement.textContent = item.title || "Menu Item";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.title) titleInput.value = item.title;
|
||||||
|
if (item.prompt) promptInput.value = item.prompt;
|
||||||
|
if (item.model) modelSelect.value = item.model;
|
||||||
|
|
||||||
|
// Toggle expand/collapse
|
||||||
|
const toggleBtn = menuItem.querySelector(".menu-item-header");
|
||||||
|
toggleBtn.addEventListener("click", () => {
|
||||||
|
menuItem.classList.toggle("expanded");
|
||||||
|
toggleBtn.querySelector(".toggle-btn").textContent =
|
||||||
|
menuItem.classList.contains("expanded") ? "▲" : "▼";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete button
|
||||||
|
const deleteBtn = menuItem.querySelector(".delete-menu-item");
|
||||||
|
deleteBtn.addEventListener("click", () => {
|
||||||
|
if (confirm("Are you sure you want to delete this menu item?")) {
|
||||||
|
menuItem.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update title when changed
|
||||||
|
titleInput.addEventListener("input", () => {
|
||||||
|
titleElement.textContent = titleInput.value || "Menu Item";
|
||||||
|
});
|
||||||
|
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new menu item
|
||||||
|
function addMenuItem() {
|
||||||
|
const newItem = createMenuItemElement();
|
||||||
|
menuItemsContainer.appendChild(newItem);
|
||||||
|
|
||||||
|
// Expand the new item and scroll to it
|
||||||
|
newItem.classList.add("expanded");
|
||||||
|
newItem.querySelector(".toggle-btn").textContent = "▲";
|
||||||
|
newItem.scrollIntoView({ behavior: "smooth" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event listeners
|
||||||
|
addMenuItemBtn.addEventListener("click", addMenuItem);
|
||||||
|
saveSettingsBtn.addEventListener("click", saveSettings);
|
||||||
|
resetSettingsBtn.addEventListener("click", resetSettings);
|
||||||
|
|
||||||
|
// Initialize
|
||||||
|
loadSettings();
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user