Skip to content

Instantly share code, notes, and snippets.

@1nsp1r3rnzt
Last active May 15, 2025 22:52
Show Gist options
  • Save 1nsp1r3rnzt/0e335419da26a9e5336e597741e35f11 to your computer and use it in GitHub Desktop.
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..
// ==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