DeepL UI Cleaner

Streamlines DeepL's interface for translation-focused use by removing footers, cookie banners, and adding toggle buttons for sidebar and header

Versión del día 30/10/2024. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         DeepL UI Cleaner
// @namespace    http://tampermonkey.net/
// @version      0.6
// @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/*
// @include      https://www.deepl.com/*
// @license      Unlicense
// @grant        none
// @run-at       document-idle
// ==/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"]',
                '.bg-white.min-\\[1280px\\]\\:px-\\[70px\\]'
            ],
        },
        toggle: {
            topHeader: 'header'
        },
    };

    // CSS styles for toggle buttons and initial header state
    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);
        }
        ${TARGETS.toggle.topHeader} {
            display: none !important;
        }
    `;

    // Function to inject CSS styles into the page
    function injectStyles() {
        const style = document.createElement("style");
        const hideSelectors = [
            ...Object.values(TARGETS.remove).flat(),
        ].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;  // Starting with show icon since header is hidden
        button.setAttribute("aria-label", ariaLabel);
        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.topHeader,
                    icons: ["▼", "▲"],
                    position: { left: "0.5em" },
                    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, attributes: 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();
    }
})();