// ==UserScript== // @name DeepL UI Cleaner // @namespace http://tampermonkey.net/ // @version 0.4 // @description Streamlines DeepL's interface for translation-focused use by removing footers, cookie banners, and adding toggle buttons for sidebar and header // @match https://www.deepl.com/* // @license Unlicense // @grant none // @run-at document-start // @downloadURL none // ==/UserScript== (function () { "use strict"; // Define selectors for target elements const TARGETS = { remove: { footer: [ "footer", ".relative.bg-neutral-next-50 > .mobile\\:hidden", '.bg-white[class*="px-0"][class*="xl:px-"][class*="md:px-"][class*="min-"][class*="px-"]', ], cookieBanner: ['[id*="cookieBanner"]', '[class*="cookieBanner"]'], writePageElements: [ '.bg-white.px-0[class*="xl:px-"][class*="px"][class*="md:px-"][class*="px"][class*="min-"][class*="px"][class*="px"]', '.mobile\\:hidden.p-8.px-0[class*="xl:px-"][class*="px"][class*="md:px-"][class*="px"][class*="min-"][class*="px"][class*="px"]', ], }, toggle: { leftSidebar: '[class*="md:block"].bg-white.border-e[class*="w-["][class*="px]"].h-full.hidden[class*="start-0"].border-neutral-next-100', topHeader: '[class*="BasePageHeader-module--container"]', }, }; // CSS styles for toggle buttons const BUTTON_STYLES = ` .toggle-button { position: fixed; z-index: 10000; width: 2em; height: 2em; background-color: rgba(240, 240, 240, 0.7); border: 1px solid #ccc; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 16px; transition: all 0.3s; } .toggle-button:hover { background-color: rgba(220, 220, 220, 0.9); } `; // Function to inject CSS styles into the page function injectStyles() { const style = document.createElement("style"); const hideSelectors = [ ...Object.values(TARGETS.remove).flat(), ...Object.values(TARGETS.toggle), ].join(", "); style.textContent = ` ${hideSelectors} { display: none !important; } ${BUTTON_STYLES} `; (document.head || document.documentElement).appendChild(style); } // Function to remove unwanted elements from the page function removeElements() { Object.values(TARGETS.remove) .flat() .forEach((selector) => { document .querySelectorAll(selector) .forEach((element) => element.remove()); }); } // Function to create a toggle button function createToggleButton( showIcon, hideIcon, onClick, position, ariaLabel ) { const button = document.createElement("button"); button.className = "toggle-button"; button.textContent = showIcon; button.setAttribute("aria-label", ariaLabel); // Accessibility improvement button.addEventListener("click", onClick); Object.assign(button.style, position); return button; } // Function to adjust button positions based on header visibility function adjustButtonPositions() { const header = document.querySelector(TARGETS.toggle.topHeader); const topPosition = header && getComputedStyle(header).display !== "none" ? `${header.offsetHeight}px` : "0.5em"; document.querySelectorAll(".toggle-button").forEach((button) => { button.style.top = topPosition; }); } // Function to toggle visibility of elements function toggleElementVisibility(selector, button, showIcon, hideIcon) { const elements = document.querySelectorAll(selector); const isVisible = [...elements].some( (el) => getComputedStyle(el).display !== "none" ); elements.forEach((el) => el.style.setProperty("display", isVisible ? "none" : "block", "important") ); button.textContent = isVisible ? showIcon : hideIcon; adjustButtonPositions(); } // Function to initialize the script function init() { try { removeElements(); const buttons = [ { selector: TARGETS.toggle.leftSidebar, icons: ["≡", "×"], position: { left: "0.5em" }, ariaLabel: "Toggle sidebar visibility", }, { selector: TARGETS.toggle.topHeader, icons: ["▼", "▲"], position: { left: "3em" }, ariaLabel: "Toggle header visibility", }, ]; buttons.forEach( ({ selector, icons: [showIcon, hideIcon], position, ariaLabel }) => { const button = createToggleButton( showIcon, hideIcon, () => toggleElementVisibility(selector, button, showIcon, hideIcon), position, ariaLabel ); document.body.appendChild(button); } ); adjustButtonPositions(); // Set up MutationObserver to handle dynamically added elements const observer = new MutationObserver(() => { removeElements(); adjustButtonPositions(); }); observer.observe(document.body, { childList: true, subtree: true }); } catch (error) { console.error("DeepL UI Cleaner encountered an error:", error); } } // Inject styles immediately injectStyles(); // Run initialization when DOM is ready if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); } else { init(); } })();