// ==UserScript== // @name Gmail Enhanced Toolbar // @namespace http://tampermonkey.net/ // @version 1.0 // @description Adds custom buttons to Gmail toolbar with toggleable features. // @author Antigravity // @match https://mail.google.com/* // @updateURL https://raw.githubusercontent.com/nguyenhuy158/tampermonkey-script/main/gmail-enhanced.user.js // @downloadURL https://raw.githubusercontent.com/nguyenhuy158/tampermonkey-script/main/gmail-enhanced.user.js // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @run-at document-end // ==/UserScript== (function () { 'use strict'; // --- Configuration & State Management --- const FEATURES = { FILTER_NEAR_ARCHIVE: { id: 'filterNearArchive', name: 'Filter Button (Left of Archive)', default: true }, FILTER_NEAR_SELECT: { id: 'filterNearSelect', name: 'Filter Button (Right of Select)', default: true } }; const config = {}; Object.keys(FEATURES).forEach(key => { const feature = FEATURES[key]; config[feature.id] = GM_getValue(feature.id, feature.default); GM_registerMenuCommand(`${config[feature.id] ? '✅' : '❌'} ${feature.name}`, () => { GM_setValue(feature.id, !config[feature.id]); location.reload(); }); }); // --- Utility Functions --- function waitForElement(selector, callback, interval = 500, timeout = 10000) { const startTime = Date.now(); const check = () => { const el = document.querySelector(selector); if (el) { callback(el); } else if (Date.now() - startTime < timeout) { setTimeout(check, interval); } }; check(); } function createGmailButton(label, iconHtml, title, onClick) { const btn = document.createElement('div'); btn.className = 'T-I J-J5-Ji T-I-ax7 T-I-Js-IF mA custom-gmail-btn'; btn.setAttribute('role', 'button'); btn.setAttribute('tabindex', '0'); btn.setAttribute('data-tooltip', title); btn.setAttribute('aria-label', title); btn.style.userSelect = 'none'; btn.style.marginRight = '4px'; btn.style.marginLeft = '4px'; btn.style.display = 'inline-flex'; btn.style.alignItems = 'center'; btn.style.justifyContent = 'center'; btn.title = title; const iconContainer = document.createElement('div'); iconContainer.className = 'asa'; iconContainer.innerHTML = iconHtml || `filter_list`; btn.appendChild(iconContainer); btn.addEventListener('click', (e) => { e.stopPropagation(); onClick(); }); // Hover effect btn.addEventListener('mouseenter', () => btn.classList.add('T-I-JW')); btn.addEventListener('mouseleave', () => btn.classList.remove('T-I-JW')); return btn; } function triggerFilterAction() { // Try to trigger the "Filter messages like these" action // 1. Find the 'More' button const moreBtn = document.querySelector('div[aria-label="More email options"], div[data-tooltip="More"]'); if (moreBtn) { moreBtn.click(); // Wait for menu to appear and click "Filter messages like these" setTimeout(() => { const menuItems = document.querySelectorAll('div[role="menuitem"]'); for (let item of menuItems) { if (item.textContent.includes('Filter messages like these')) { item.click(); break; } } }, 50); } else { console.warn('More button not found'); } } // SVG for the Filter icon (similar to Gmail's style) const FILTER_ICON_SVG = ``; // --- Main Logic --- function injectButtons() { // 1. Feature: Filter Button Near Archive if (config.filterNearArchive) { const archiveBtn = document.querySelector('div[aria-label="Archive"]'); if (archiveBtn && !document.getElementById('custom-filter-archive')) { const filterBtn = createGmailButton('Filter', FILTER_ICON_SVG, 'Filter messages like these', triggerFilterAction); filterBtn.id = 'custom-filter-archive'; archiveBtn.parentNode.insertBefore(filterBtn, archiveBtn); } } // 2. Feature: Filter Button Near Select if (config.filterNearSelect) { const selectGroup = document.querySelector('div.G-as3') || document.querySelector('div[aria-label="Select"]'); if (selectGroup && !document.getElementById('custom-filter-select')) { const filterBtn = createGmailButton('Filter', FILTER_ICON_SVG, 'Filter messages like these', triggerFilterAction); filterBtn.id = 'custom-filter-select'; // Insert after the select group selectGroup.insertAdjacentElement('afterend', filterBtn); } } } // Watch for toolbar changes const observer = new MutationObserver(() => { injectButtons(); }); observer.observe(document.body, { childList: true, subtree: true }); // Initial injection injectButtons(); })();