WhatsApp Web - Clean UI

Fix & debloat WhatsApp Web's interface

// ==UserScript==
// @name         WhatsApp Web - Clean UI
// @description  Fix & debloat WhatsApp Web's interface
// @author       Gamba
// @version      1.10
// @license      MIT
// @namespace    http://tampermonkey.net/
// @match        https://web.whatsapp.com/*
// @icon         https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://web.whatsapp.com/&size=256
// @grant        none
// @run-at       document-start
// ==/UserScript==

"use strict";

// Add original dark theme
{
    const themeKey = "theme";
    const darkThemeValue = '"dark"';
    const lightThemeValue = '"light"';
    const systemKey = "system-theme-mode";
    const originalKey = "original-theme";
    const originalLabel = " (2024)";

    document.addEventListener("DOMContentLoaded", onLoad);

    function onLoad()
    {
        const body = document.body;

        function observe(callback, options)
        {
            const observer = new MutationObserver(callback);

            observer.observe(body, options);
        }

        observe(onTreeChange,
        {
            childList: true,
            subtree: true
        });

        function onTreeChange()
        {
            onThemePreview();
            onOptionsDialog();
        }

        // Replace theme preview label
        let previewActive = false;

        function onThemePreview()
        {
            const preview = document.querySelector("#app > div > div.x78zum5.xdt5ytf.x5yr21d > div > div.x10l6tqk.x13vifvy.x1o0tod.x78zum5.xh8yej3.x5yr21d.x6ikm8r.x10wlt62.x47corl > div._aigw._as6h.xevlxbw.x9f619.x1n2onr6.x5yr21d.x17dzmu4.x1i1dayz.x2ipvbc.x1w8yi2h.x78zum5.xdt5ytf.x14bqcqg.x18dvir5.xxljpkc.xwfak60.x6ikm8r.x10wlt62.x1ks9yow.xpilrb4.x1t7ytsu.x1m2ixmg > span > div > span > div > div > div > div > div > div:nth-child(1) > div:nth-child(2) > div > div.x98rzlu > div.x1f6kntn.xd4r4e8.x16zc8z2");
            const previewExists = preview != null;

            if (previewExists != previewActive)
            {
                previewActive = previewExists;

                if (previewExists)
                {
                    const original = localStorage.getItem(originalKey) == "true";

                    if (original) preview.innerHTML += originalLabel;
                }
            }
        }

        // Replace system theme option with original dark
        let dialogActive = false;

        function onOptionsDialog()
        {
            const dialog = document.querySelector("#app > div > span:nth-child(3) > div > div > div > div > div > div");
            const dialogExists = dialog != null;

            if (dialogExists != dialogActive)
            {
                dialogActive = dialogExists;

                if (dialogExists)
                {
                    const darkOption = getOption(1);
                    const darkLabel = getLabel(darkOption);
                    const systemOption = getOption(2);

                    setLabel(systemOption, darkLabel + originalLabel);

                    const original = localStorage.getItem(originalKey) == "true";

                    if (original) systemOption.click();

                    const okButton = dialog.children[2].firstElementChild.children[1];
                    okButton.addEventListener("click", onConfirm, true);

                    function onConfirm()
                    {
                        const darkSelected = getSelected(darkOption);
                        const systemSelected = getSelected(systemOption);

                        localStorage.setItem(systemKey, false);
                        localStorage.setItem(originalKey, systemSelected);
                        localStorage.setItem(themeKey, (darkSelected || systemSelected) ? darkThemeValue : lightThemeValue);

                        location.reload();
                    }
                }
            }

            function getOption(index)
            {
                return dialog.children[1].firstElementChild.firstElementChild.firstElementChild.children[index].children[1];
            }

            function getLabel(option)
            {
                const label = option.innerHTML;
                const child = option.firstElementChild.outerHTML;

                return label.replace(child, "");
            }

            function setLabel(option, text)
            {
                const child = option.firstElementChild.outerHTML;

                option.innerHTML = text + child;
            }

            function getSelected(option)
            {
                const radio = option.previousElementSibling.children[1];

                return radio.ariaChecked == "true";
            }
        }

        // Apply theme on startup
        observe(onThemeChange,
        {
            attributes: true,
            attributeFilter: ["class"]
        });

        function onThemeChange()
        {
            const system = localStorage.getItem(systemKey) == "true";
            const theme = localStorage.getItem(themeKey);
            const original = localStorage.getItem(originalKey) == "true";

            if (system)
            {
                localStorage.setItem(systemKey, false);
                localStorage.setItem(themeKey, darkThemeValue);
                localStorage.setItem(originalKey, true);

                location.reload();
            }

            if (theme == darkThemeValue && original) applyOriginalDark();
        }

        function applyOriginalDark()
        {
            const targetClass = "dark";

            if (body.className == targetClass) return;

            body.className = targetClass;
        }
    }
}

// Fix menu background exit
{
    window.addEventListener("keydown", onKeyboard, true);

    const exceptions =
    [
        "#app > div > span:nth-child(4) *",
        "#app > div > div > div > div:nth-child(3) > div:first-child > span > div > span > div > header > div > div:first-child > div",
        "#app > div > div > div > div:nth-child(3) > div:first-child > span > div > span > div > span > div > header > div > div:first-child > div",
        "#app > div > span:nth-child(3) > div"
    ];

    function onKeyboard(event)
    {
        if (event.key == "Escape")
        {
            const isException = exceptions.some(exception => event.target.matches(exception));
            const isValid = isChatsSelected() || isException;

            if (!isValid) event.stopImmediatePropagation();
        }
    }

    function isChatsSelected()
    {
        let chatsButton = document.querySelector("#app > div > div > div > header > div > div:first-child > div > div:first-child > button");

        return chatsButton.ariaPressed == "true";
    }
}

// Exit chat on change tab
{
    document.addEventListener("click", onClick, true);

    function onClick(event)
    {
        const button = event.target.closest("button");

        if (button)
        {
            const header = button.closest("header");

            if (header && header.parentElement.hasAttribute("tabindex"))
            {
                const keyEvent = new KeyboardEvent("keydown", { key: "Escape" });

                document.dispatchEvent(keyEvent);
            }
        }
    }
}

// Apply CSS
{
    const css =
    `
    /*Desktop app advertisement*/
    #app > div > div > div
    {
        > div:nth-child(5) > div:not(#main) > div
        {
            > div:nth-child(1),
            > div:nth-child(2)
            {
                display: none;
            }
        }

        > div:nth-child(3) > div:last-child > span
        {
            border: none;

            > div[tabindex] > div:not([tabindex])
            {
                display: none;
            }
        }
    }

    #side > div:nth-child(5) *
    {
        display: none;
    }

    /*Channels & communities*/
    #app > div > div > div > header > div > div:first-child > div
    {
        > div:nth-child(3),
        > div:nth-child(4)
        {
            display: none;
        }
    }

    /*Video call button*/
    #main > header > div:last-child > div > div:first-child
    {
        display: none;
    }

    /*Chat lists*/
    #side > [role="tablist"]
    {
        display: none;
    }

    /*Chat dropdowns arrows*/
    #pane-side > div:nth-last-child(2) > div > div > div > div > div > div:not(:hover) > div:last-child > div:last-child > div:last-child > span:nth-child(3)
    {
        display: none;
    }

    /*Archived chats separator*/
    #app > div > div > div > div:nth-child(3) > div:first-child > span > div > span > div > div:last-child > div > div:nth-child(2) > div.xjm9jq1.xkh2ocl.x1uew315
    {
        display: none;
    }

    /*Picture panel*/
    #app > div > div > div > div:nth-child(3) > div:last-child > span > div > div
    {
        .x1itt0r
        {
            margin-top: calc(var(--h-pane-header) - 1px);
        }

        .x1uoaltn
        {
            height: calc(100% - var(--h-pane-header) + 2px);
        }
    }

    /*Popover tooltips*/
    #wa-popovers-bucket *
    {
        display: none;
    }

    /*Scrollbar*/
    *
    {
        scrollbar-width: unset !important;
        scrollbar-color: unset !important;
    }

    div
    {
        ::-webkit-scrollbar
        {
            width: 14px !important;
        }

        ::-webkit-scrollbar-button
        {
            display: none !important;
        }

        ::-webkit-scrollbar-track,
        ::-webkit-scrollbar-track-piece
        {
            background-color: transparent !important;
        }

        ::-webkit-scrollbar-thumb
        {
            height: 50px !important;

            border: 3px solid transparent !important;
            border-radius: 100px;
            background-clip: padding-box !important;

            background-color: rgba(var(--black-rgb), 20%) !important;
        }
    }

    .dark div ::-webkit-scrollbar-thumb
    {
        background-color: rgba(var(--white-rgb), 16%) !important;
    }

    /*Small unnecessary borders*/
    #app > div > div > div
    {
        > div:nth-child(3) > div,
        > div:nth-child(4),
        > div:nth-child(6)
        {
            border-left: 0;
            padding-left: 0;
        }

        >div:nth-child(5)
        {
            border-left-color: var(--conversation-header-border);
        }
    }

    #expressions-panel-container > span > div > ul > div > div > div
    {
        border-left: 0;
    }

    /*Original dark theme*/
    .dark:not(.color-refresh)
    {
        --drawer-background-deep: #111b21;
        --panel-background-deeper: #111b21;

        --compose-input-background: #202c33;
        --compose-input-border: #202c33;

        --conversation-header-border: #222e35;
        --conversation-panel-border: #222e35;

        ._alyo._alyw
        {
            --WDS-background-wash-inset: #0a1014;
        }

        .x1vmw6bp
        {
            --WDS-surface-default: #111b21;
            --WDS-content-disabled: #617079;
        }
    }

    /*Dark theme 2025*/
    .dark.color-refresh
    {
        --conversation-header-border: #2e2f2f;
        --conversation-panel-border: #222e35;

        .x1vmw6bp
        {
            --WDS-content-disabled: #626363;
        }
    }
    `;

    const style = document.createElement("style");
    style.textContent = css;
    document.head.appendChild(style);
}