Last active
April 25, 2025 13:54
-
-
Save jackcarey/b3f65e67b1fe4544096c02d05cc065c6 to your computer and use it in GitHub Desktop.
Adds buttons to Gmail to quickly toggle the unread filter on the current view. Appears left of the search text input.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Filter Gmail to unread | |
// @namespace http://tampermonkey.net/ | |
// @version 1.1.1 | |
// @description Adds a button to Gmail to quickly toggle the unread filter on the current view. | |
// @author jackcarey | |
// @match https://mail.google.com/mail/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=google.com | |
// @grant none | |
// @run-at document-idle | |
// @homepageURL https://gist.github.com/jackcarey/b3f65e67b1fe4544096c02d05cc065c6 | |
// @downloadURL https://gist.github.com/jackcarey/b3f65e67b1fe4544096c02d05cc065c6/raw/filter-gmail-unread.user.js | |
// @updateURL https://gist.github.com/jackcarey/b3f65e67b1fe4544096c02d05cc065c6/raw/filter-gmail-unread.user.js | |
// ==/UserScript== | |
function waitForElement(selector) { | |
return new Promise((resolve) => { | |
if (document.querySelector(selector)) { | |
return resolve(document.querySelector(selector)); | |
} | |
const observer = new MutationObserver(() => { | |
if (document.querySelector(selector)) { | |
resolve(document.querySelector(selector)); | |
observer.disconnect(); | |
} | |
}); | |
observer.observe(document.querySelector("body"), { | |
childList: true, | |
subtree: true, | |
}); | |
}); | |
} | |
waitForElement(`button[aria-label="Search mail"]`).then(function() { | |
'use strict'; | |
const searchInputEl = document.querySelector(`*[name="q"]`); | |
const searchBtnEl = document.querySelector(`button[aria-label="Search mail"]`); | |
const unreadBtn = document.createElement("button"); | |
const archivedBtn = document.createElement("button"); | |
const btnSize = "1.5em"; | |
const enterEvent = new KeyboardEvent('keydown', { | |
key: 'Enter', | |
code: 'Enter', | |
which: 13, | |
keyCode: 13, | |
}); | |
const clickToggler = (querySegment)=>{ | |
return (evt)=>{ | |
evt.preventDefault(); | |
if(!searchInputEl?.value?.includes(querySegment)){ | |
searchInputEl.value+=` ${querySegment}`; | |
}else{ | |
searchInputEl.value = searchInputEl.value.replace(querySegment,"").trim(); | |
} | |
while(searchInputEl.value.includes(" ")){ | |
searchInputEl.value = searchInputEl.value.replace(" "," "); | |
} | |
searchInputEl.value = searchInputEl.value.replace(new RegExp("\s{2,}","gi")," "); | |
searchInputEl.value = searchInputEl.value.trim(); | |
searchInputEl.dispatchEvent(enterEvent); | |
}; | |
}; | |
//Unread button | |
unreadBtn.style.width=btnSize; | |
unreadBtn.style.height=btnSize; | |
unreadBtn.position="relative"; | |
unreadBtn.style.top= "1em"; | |
unreadBtn.style.left= "-2.5em"; | |
unreadBtn.style.backgroundSize = "contain"; | |
unreadBtn.title="Toggle unread messages in current view"; | |
unreadBtn.style.backgroundImage="url(https://ssl.gstatic.com/ui/v1/icons/mail/gm3/1x/stacked_email_baseline_nv700_20dp.png)"; | |
unreadBtn.className = searchBtnEl.className; | |
unreadBtn.addEventListener("click",clickToggler("-is:read")); | |
///Archived button | |
archivedBtn.style.width=btnSize; | |
archivedBtn.style.height=btnSize; | |
archivedBtn.position="relative"; | |
archivedBtn.style.top= "1em"; | |
archivedBtn.style.left= "-5em"; | |
archivedBtn.style.backgroundSize = "contain"; | |
archivedBtn.title="Toggle archived messages in current view"; | |
archivedBtn.style.backgroundImage="url(https://ssl.gstatic.com/ui/v1/icons/mail/gm3/1x/inbox_baseline_nv700_20dp.png)"; | |
archivedBtn.className = searchBtnEl.className; | |
archivedBtn.addEventListener("click",clickToggler("in:inbox")); | |
//append buttons | |
searchBtnEl.after(unreadBtn); | |
searchBtnEl.after(archivedBtn); | |
}); |
Cool. Handling nested labels is something I dislike too. I have an Apps Script that includes a searchTermFromLabelFragment
function for finding nested labels. My plan is to develop an add-on that allows users to store these searches and take actions against matching threads. Using the Gmail Add-on API is the way to build UI elements as far as Google is concerned. It also has the benefits of cross-platform support and predictable interfaces.
Once I’ve had chance to develop something, I’ll share it here
Sounds really interesting. I'll keep monitoring this space. :-)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sorry for hijacking your gist's comment section.
I have a lot (thousands) of labels and nested labels - years back this functionality had better support i gmail, but now it's dreadful, to the point that currently the only place Gmail really handles it well is when manually adding a label to a message, where it's possible to search for substrings in a label, so it can quickly be located and selected. Looking up a label else-where, the search is either not, or hardly existing, making it hard to add new sub labels and to find the ones that currently exist.
So my plan was to try to improve that. Since they already have a fully working search implementation it seems like an easy case of reuse - but it will require many things in the UI to be hidden or modified, and new things injected.
All this should be relatively easy, if it wasn't for the UI elements, that always exists in the same order in the HTML,, to have 10+ different id's, classes or aria-* identifiers, depending on the initial starting point and apparently also the UI language.