Skip to content

Instantly share code, notes, and snippets.

@narze
Last active January 1, 2025 15:55
Show Gist options
  • Save narze/4b33764266c4d99625d15309e073aa5b to your computer and use it in GitHub Desktop.
Save narze/4b33764266c4d99625d15309e073aa5b to your computer and use it in GitHub Desktop.
Arc Boost - Hide Facebook Notification Bubble
(function () {
'use strict';
const enabled = true;
function log() {
// Uncomment to debug
// console.log(arguments)
}
function findNotificationBubble() {
// Step 1: Find all potential notification elements
// Facebook specific
const allElements = document.querySelectorAll('[role="navigation"] div, [role="navigation"] span, [role="navigation"] a');
// const allElements = document.querySelectorAll('div, span, a');
for (const el of allElements) {
const style = window.getComputedStyle(el);
const text = el.textContent.trim();
// Check visibility and size constraints
if (
style.display !== 'none' &&
style.visibility !== 'hidden' &&
el.offsetParent !== null
) {
const width = el.offsetWidth;
const height = el.offsetHeight;
// Threshold for notification bubble size (e.g., max 24px)
if (
width > 0 && width <= 24 &&
height > 0 && height <= 24 &&
/^\d+$/.test(text) // Check if content is numeric
) {
// Check if the bubble is red-ish or blue-ish
console.log(`πŸ“ Found unread notification bubble: ${text}`, el);
return el;
}
}
}
log('❌ No unread notification bubble detected.');
return null;
}
/** πŸŸ₯ Detect if color is red-ish or blue-ish **/
function isColorRedOrBlue(color) {
const rgb = getRGBFromColor(color);
if (!rgb) return false; // If we can't parse the color, return false
const [r, g, b] = rgb;
if (r === 29 && g === 155 && b === 240) {
return true;
}
// Define thresholds for red and blue
const isRed = r > 100 && r > b && g < 50; // More red than blue/green
const isBlue = b > 100 && b > r && g < 50; // More blue than red/green
return isRed || isBlue;
}
/** 🎨 Convert color to RGB array **/
function getRGBFromColor(color) {
if (!color) return null;
let rgb;
// Handle RGB and rgba (including cases where alpha channel is used)
if (color.startsWith('rgb')) {
rgb = color.match(/\d+/g);
}
// Handle hex color format
else if (color.startsWith('#')) {
if (color.length === 7) {
rgb = [
parseInt(color.slice(1, 3), 16),
parseInt(color.slice(3, 5), 16),
parseInt(color.slice(5, 7), 16)
];
}
}
return rgb ? rgb.map(Number) : null;
}
function findNotificationBubbleParentAndChild() {
// Step 2: Detect the bubble
const bubble = findNotificationBubble();
if (!bubble) return null;
let currentElement = bubble;
// Traverse upward to find a parent that's reasonably larger
while (currentElement.parentElement) {
currentElement = currentElement.parentElement;
const parentWidth = currentElement.offsetWidth;
const parentHeight = currentElement.offsetHeight;
// Threshold for a reasonable parent size (>24px)
if (parentWidth > 24 && parentHeight > 24) {
log('βœ… Found parent container:', currentElement);
// Step 3: Find child smaller than 24px
const children = currentElement.querySelectorAll('*');
for (const child of children) {
const childWidth = child.offsetWidth;
const childHeight = child.offsetHeight;
if (childWidth > 0 && childWidth <= 24 && childHeight > 0 && childHeight <= 24) {
log('🎯 Found child smaller than 24px:', child);
return child;
}
}
log('❌ No child smaller than 24px found in this parent.');
return null;
}
}
log('❌ No suitable parent container found.');
return null;
}
// Main function to hide notification bubbles
function hideNotificationBubbles() {
const bubble = findNotificationBubbleParentAndChild();
if (!bubble) {
log('❌ No notification bubbles found to hide.');
return;
}
bubble.style.display = 'none';
}
function observeDOMChanges() {
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.addedNodes.length > 0) {
hideNotificationBubbles();
}
}
});
if (document.body) {
observer.observe(document.body, {
childList: true,
subtree: true,
});
log('πŸ‘€ DOM Observer started, watching for notification bubbles...');
} else {
setTimeout(observeDOMChanges, 500);
return;
}
}
if (enabled) {
hideNotificationBubbles();
observeDOMChanges();
}
/** πŸ“ Remove Numbers from Page Title **/
function cleanPageTitle() {
const originalTitle = document.title;
const cleanTitle = originalTitle.replace(/^\(\d+\)\s*/, '');
if (originalTitle !== cleanTitle) {
document.title = cleanTitle;
log(`πŸ“ Cleaned page title: "${cleanTitle}"`);
}
}
/** 🎯 Observe Title Changes **/
function observeTitleChanges() {
// Ensure the title element is available
const titleElement = document.querySelector('title');
if (!titleElement) {
log('❌ No <title> element found, retrying...');
setTimeout(observeTitleChanges, 500);
return;
}
const titleObserver = new MutationObserver(() => {
cleanPageTitle();
});
titleObserver.observe(titleElement, {
childList: true,
subtree: true,
});
log('πŸ‘€ Title Observer started, watching for title changes...');
}
if (enabled) {
cleanPageTitle()
observeTitleChanges()
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment