diff --git a/css/mzta-compose-styles.css b/css/mzta-compose-styles.css new file mode 100644 index 00000000..4bfbdc77 --- /dev/null +++ b/css/mzta-compose-styles.css @@ -0,0 +1,61 @@ +#mzta_search_banner{ + background-color: rgb(122, 180, 255); + color:black; + border-radius: 5px; + width: 15em; + height: 2em; + position: absolute; + top: 5px; + right: 5px; + z-index: 1000; + display: flex; + justify-content: center; + align-items: center; +} + +.mzta_autocomplete-items { + position: absolute; + border: 1px solid #ccc; + border-top: none; + z-index: 1001; + background-color: #fff; + max-height: 150px; + overflow-y: auto; + width: 300px; +} + +.mzta_autocomplete-item { + padding: 8px; + cursor: pointer; +} + +.mzta_autocomplete-item:hover { + background-color: #e9e9e9; +} + + +@media (prefers-color-scheme: dark) { + + input { + background-color: #27272a; + color: #ffffff; + } + + #mzta_search_banner{ + background-color: #27272a; + color:#ffffff; + } + + .mzta_autocomplete-items { + border: 1px solid #555; + background-color: #2c2c2c; + } + + .mzta_autocomplete-item { + color: #ffffff; + } + + .mzta_autocomplete-item:hover { + background-color: #444444; + } +} \ No newline at end of file diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js index 12617313..7e5b117b 100644 --- a/js/mzta-compose-script.js +++ b/js/mzta-compose-script.js @@ -62,8 +62,112 @@ switch (message.command) { alert(message.message); break; + case 'searchPrompt': + searchPrompt(); + break; + default: // do nothing break; -} -}); \ No newline at end of file +} +}); + +const autocompleteData = [ + 'Apple', + 'Apricot', + 'Avocado', + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cherry', + 'Coconut', + 'Date', + 'Dragonfruit', + 'Elderberry', + 'Fig', + 'Grape', + 'Grapefruit', + 'Guava', + 'Honeydew', + 'Jackfruit', + 'Kiwi', + 'Lemon', + 'Lime', + 'Mango', + 'Melon', + 'Nectarine', + 'Orange', + 'Papaya', + 'Peach', + 'Pear', + 'Pineapple', + 'Plum', + 'Pomegranate', + 'Raspberry', + 'Strawberry', + 'Watermelon' +]; + +function searchPrompt(){ + const banner = document.createElement('div'); + banner.id = 'mzta_search_banner'; + + const input = document.createElement('input'); + input.type = 'text'; + input.id = 'mzta_search_input'; + input.placeholder = 'Search a prompt...'; + banner.appendChild(input); + + const autocompleteList = document.createElement('div'); + autocompleteList.classList.add('mzta_autocomplete-items'); + autocompleteList.style.display = 'none'; + banner.appendChild(autocompleteList); + + // Function to filter and display autocomplete suggestions + input.addEventListener('input', function() { + const query = this.value.trim().toLowerCase(); + autocompleteList.innerHTML = ''; // Clear previous suggestions + + if (query === '') { + autocompleteList.style.display = 'none'; + return; + } + + // Filter data based on the query + const filteredData = autocompleteData.filter(item => item.toLowerCase().startsWith(query)); + + if (filteredData.length === 0) { + autocompleteList.style.display = 'none'; + return; + } + + // Create a div for each filtered result + filteredData.forEach(item => { + const itemDiv = document.createElement('div'); + itemDiv.classList.add('mzta_autocomplete-item'); + itemDiv.textContent = item; + + // Add a mousedown event to select the item + itemDiv.addEventListener('mousedown', function(e) { // Use mousedown instead of click + e.preventDefault(); // Prevents the input from losing focus + input.value = item; + autocompleteList.style.display = 'none'; + }); + + autocompleteList.appendChild(itemDiv); + }); + + autocompleteList.style.display = 'block'; + }); + + // Handle the input field losing focus to hide the banner + input.addEventListener('blur', function() { + // Use a timeout to allow clicking on suggestions before hiding + setTimeout(() => { + banner.remove(); + }, 200); + }); + + document.body.insertBefore(banner, document.body.firstChild); + input.focus(); +} \ No newline at end of file diff --git a/manifest.json b/manifest.json index d1f88f32..be476a37 100644 --- a/manifest.json +++ b/manifest.json @@ -44,5 +44,10 @@ "default_locale": "en", "options_ui": { "page": "options/mzta-options.html" - } + }, + "commands": { + "_thunderai__do_action": { + "description": "" + } + } } diff --git a/mzta-background.js b/mzta-background.js index 49763d55..b72c45fc 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -32,12 +32,14 @@ let prefs_debug = await browser.storage.sync.get({do_debug: false}); let taLog = new taLogger("mzta-background",prefs_debug.do_debug); browser.composeScripts.register({ - js: [{file: "/js/mzta-compose-script.js"}] + js: [{ file: "js/mzta-compose-script.js" }], + css: [{ file: "css/mzta-compose-styles.css" }], }); // Register the message display script for all newly opened message tabs. messenger.messageDisplayScripts.register({ js: [{ file: "js/mzta-compose-script.js" }], + css: [{ file: "css/mzta-compose-styles.css" }], }); // Inject script and CSS in all already open message tabs. @@ -52,7 +54,10 @@ for (let messageTab of messageTabs) { try { await browser.tabs.executeScript(messageTab.id, { file: "js/mzta-compose-script.js" - }) + }); + await browser.tabs.insertCSS(messageTab.id, { + file: "css/mzta-compose-styles.css" + }); } catch (error) { console.error("[ThunderAI] Error injecting message display script:", error); console.error("[ThunderAI] Message tab:", messageTab.url); @@ -65,6 +70,32 @@ browser.contentScripts.register({ runAt: "document_idle" }); +// Shortcut +messenger.commands.update({ + name: "_thunderai__do_action", + shortcut: "Ctrl+Alt+A" +}).then(() => { + taLog.log('Shortcut registered successfully!'); +}).catch((error) => { + taLog.error('Error registering shortcut: ' + error); +}); + +// Listen for shortcut command +messenger.commands.onCommand.addListener((command, tab) => { + if (command === "_thunderai__do_action") { + handleShortcut(tab); + } + }); + + + function handleShortcut(tab) { + console.log("Shortcut triggered!"); + if(!["mail", "messageCompose","messageDisplay"].includes(tab.type)){ + return; + } + browser.tabs.sendMessage(tab.id, { command: "searchPrompt" }); + } + messenger.runtime.onMessage.addListener(async (message, sender, sendResponse) => { // Check what type of message we have received and invoke the appropriate // handler function.