Last active
May 15, 2025 22:52
-
-
Save 1nsp1r3rnzt/0e335419da26a9e5336e597741e35f11 to your computer and use it in GitHub Desktop.
Hide selected time slots on Focusmate for a clean UX in the weekly view..
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 Focusmate Weekly Schedule Enhancer | |
// @namespace http://tampermonkey.net/ | |
// @version 4.3 | |
// @description Hide selected time slots on Focusmate for a clean UX in the weekly view.. demo at https://ibb.co/xSRt3hRM | |
// @match https://app.focusmate.com/* | |
// @grant none | |
// @license MIT | |
// ==/UserScript== | |
/* | |
* Copyright (c) 2025 Ranjit Saini (FlourishLifetech) | |
* | |
* Released under the MIT License. | |
* https://opensource.org/licenses/MIT | |
* | |
* This script is free to use, modify, and distribute. | |
* If you find it helpful, consider supporting its development via donations. | |
* Your support helps improve the tool and allows for continued updates. | |
* | |
* Contribution link: https://www.flourishlifetech.com/contribute | |
*/ | |
(function () { | |
'use strict'; | |
const defaultSettings = { | |
hideHours: ["6A", "7A"], | |
scrollTime: "9A" | |
}; | |
// Load settings from localStorage | |
function loadSettings() { | |
const saved = localStorage.getItem("focusmateCleanerSettings"); | |
return saved ? JSON.parse(saved) : defaultSettings; | |
} | |
// Save settings to localStorage | |
function saveSettings(settings) { | |
localStorage.setItem("focusmateCleanerSettings", JSON.stringify(settings)); | |
} | |
// Create settings UI | |
function createSettingsUI(settings) { | |
const settingsDiv = document.createElement("div"); | |
settingsDiv.id = "focusmateCleanerSettings"; | |
settingsDiv.style.position = "fixed"; | |
settingsDiv.style.top = "50px"; | |
settingsDiv.style.right = "20px"; | |
settingsDiv.style.backgroundColor = "white"; | |
settingsDiv.style.border = "2px solid #6C63FF"; | |
settingsDiv.style.borderRadius = "10px"; | |
settingsDiv.style.padding = "15px"; | |
settingsDiv.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.1)"; | |
settingsDiv.style.zIndex = "9999"; | |
settingsDiv.style.maxHeight = "80vh"; // Max height for scrollability | |
settingsDiv.style.overflowY = "auto"; // Enable vertical scroll | |
settingsDiv.style.display = "none"; // Hidden by default | |
const hours = ["12A", "1A", "2A", "3A", "4A", "5A", "6A", "7A", "8A", "9A", "10A", "11A", "12P", "1P", "2P", "3P", "4P", "5P", "6P", "7P", "8P", "9P", "10P", "11P"]; | |
let html = "<h3 style='font-size: 18px; color: #333;'>Focusmate Cleaner Settings</h3>"; | |
// Hour settings | |
html += "<strong style='color: #333;'>Hide Hours:</strong><br>"; | |
hours.forEach(hour => { | |
const checked = settings.hideHours.includes(hour) ? "checked" : ""; | |
html += `<label style='display: block; margin: 5px 0;'><input type="checkbox" data-hour="${hour}" ${checked}> ${hour}</label>`; | |
}); | |
// Scroll to Time setting | |
html += "<br><strong style='color: #333;'>Scroll to Time on Load:</strong><br>"; | |
html += `<select id="scrollToTime" style='padding: 5px; font-size: 14px;'>`; | |
hours.forEach(hour => { | |
const selected = settings.scrollTime === hour ? "selected" : ""; | |
html += `<option value="${hour}" ${selected}>${hour}</option>`; | |
}); | |
html += `</select><br><br>`; | |
html += "<button id='focusmateSave' style='background-color: #6C63FF; color: white; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer; transition: background-color 0.3s;'>Save</button> "; | |
html += "<button id='focusmateClose' style='background-color: #e1e1e1; color: #333; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer; transition: background-color 0.3s;'>Close</button> "; | |
html += "<button id='focusmateReset' style='background-color: #ff6f61; color: white; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer; transition: background-color 0.3s;'>Reset Script</button>"; | |
// Subtle donation button | |
html += "<br><br><button id='focusmateDonate' style='background-color: transparent; color: #6C63FF; border: none; padding: 8px 16px; cursor: pointer; text-decoration: underline; font-size: 14px;'>Support FlourishLifetech</button>"; | |
settingsDiv.innerHTML = html; | |
document.body.appendChild(settingsDiv); | |
// Event listeners for buttons | |
document.getElementById("focusmateSave").addEventListener("click", () => { | |
const newSettings = { | |
hideHours: [], | |
scrollTime: document.getElementById("scrollToTime").value | |
}; | |
hours.forEach(hour => { | |
if (settingsDiv.querySelector(`[data-hour="${hour}"]`).checked) { | |
newSettings.hideHours.push(hour); | |
} | |
}); | |
saveSettings(newSettings); | |
alert("Settings saved! Reloading to apply..."); | |
location.reload(); | |
}); | |
document.getElementById("focusmateClose").addEventListener("click", () => { | |
settingsDiv.style.display = "none"; // Hide the settings panel | |
}); | |
// Reset the script | |
document.getElementById("focusmateReset").addEventListener("click", () => { | |
alert("Re-initializing the script..."); | |
init(); // Re-initialize the script | |
hideBookingColumns(settings); // Ensure columns are hidden based on current settings | |
}); | |
// Add donation button | |
document.getElementById("focusmateDonate").addEventListener("click", () => { | |
window.open("https://www.flourishlifetech.com", "_blank"); | |
}); | |
} | |
// Create settings button | |
function createSettingsButton() { | |
const btn = document.createElement("button"); | |
btn.textContent = "Cleaner Settings"; | |
btn.style.position = "fixed"; | |
btn.style.top = "10px"; | |
btn.style.right = "300px"; | |
btn.style.backgroundColor = "#6C63FF"; | |
btn.style.color = "white"; | |
btn.style.border = "none"; | |
btn.style.padding = "10px 20px"; | |
btn.style.borderRadius = "5px"; | |
btn.style.zIndex = "9999"; | |
btn.style.fontSize = "16px"; | |
btn.addEventListener("click", toggleSettings); | |
document.body.appendChild(btn); | |
} | |
// Toggle settings visibility (fixing the display issue) | |
function toggleSettings() { | |
const settingsDiv = document.getElementById("focusmateCleanerSettings"); | |
if (settingsDiv.style.display === "none" || settingsDiv.style.display === "") { | |
settingsDiv.style.display = "block"; // Show settings panel | |
} else { | |
settingsDiv.style.display = "none"; // Hide settings panel | |
} | |
} | |
// Scroll to the selected time | |
function scrollToSelectedTime(settings) { | |
const timeLabels = document.querySelectorAll('.fm-time-label'); | |
const targetTime = settings.scrollTime; | |
timeLabels.forEach(label => { | |
const timeText = label.innerText.trim(); | |
if (timeText === targetTime) { | |
label.scrollIntoView({ behavior: "smooth", block: "center" }); | |
} | |
}); | |
} | |
// Hide columns corresponding to selected hours | |
function hideBookingColumns(settings) { | |
const timeLabels = document.querySelectorAll('.fm-time-label'); | |
const bookingColumns = document.querySelectorAll('.mat-grid-tile'); | |
let currentHour = null; | |
let shouldHide = false; | |
timeLabels.forEach(label => { | |
const timeText = label.innerText.trim(); | |
if (/[0-9]+[AP]/.test(timeText)) { | |
currentHour = timeText; | |
shouldHide = settings.hideHours.includes(currentHour); | |
} | |
if (timeText.match(/^:[0-9]{2}$/) || /[0-9]+[AP]/.test(timeText)) { | |
if (shouldHide) { | |
const boundingRect = label.getBoundingClientRect(); | |
const columnTop = boundingRect.top; | |
bookingColumns.forEach(column => { | |
const colRect = column.getBoundingClientRect(); | |
if (Math.abs(colRect.top - columnTop) < 5) { | |
column.style.display = "none"; | |
} | |
}); | |
} | |
} | |
}); | |
} | |
// Listen for the view change from "Day" to "Week" | |
function listenForViewChange() { | |
const dayButton = document.querySelector('.f-btn--calendar-control'); | |
if (dayButton) { | |
dayButton.addEventListener('click', () => { | |
setTimeout(() => { | |
const settings = loadSettings(); | |
hideBookingColumns(settings); // Hide columns after the view changes | |
scrollToSelectedTime(settings); // Scroll to the selected time | |
}, 500); // Delay to ensure the view has switched | |
}); | |
} | |
} | |
// Initialization | |
function init() { | |
const settings = loadSettings(); | |
createSettingsButton(); | |
createSettingsUI(settings); | |
hideBookingColumns(settings); | |
scrollToSelectedTime(settings); | |
listenForViewChange(); // Listen for view changes | |
// Observe changes and update bookings dynamically | |
const observer = new MutationObserver(() => { | |
hideBookingColumns(settings); // Reapply hiding on DOM changes | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
// Fallback interval to check periodically | |
setInterval(() => hideBookingColumns(settings), 1000); | |
} | |
init(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment